diff --git a/AUTHORS b/AUTHORS index 68f5ef6..1a187dbd 100644 --- a/AUTHORS +++ b/AUTHORS
@@ -36,6 +36,7 @@ Adam Yi <i@adamyi.com> Addanki Gandhi Kishor <kishor.ag@samsung.com> Adenilson Cavalcanti <a.cavalcanti@samsung.com> +Adesh Attavar <adesh.attavar@gmail.com> Aditi Singh <a20.singh@samsung.com> Aditya Agarwal <ad.agarwal@samsung.com> Aditya Bhargava <heuristicist@gmail.com>
diff --git a/DEPS b/DEPS index e0b199a..70877c72 100644 --- a/DEPS +++ b/DEPS
@@ -299,19 +299,19 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. - 'src_internal_revision': '4baa1abaa62ee7bde3412e8dbef614134978edab', + 'src_internal_revision': '7bc0f561fe056c19918d9c9efef049525389066e', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and whatever else without interference from each other. - 'skia_revision': '83105a7fb6e2c2e3dda07a63f5139cbedc8c81cf', + 'skia_revision': '0e8023dc0a1a5655703b39454c090b5a004415d6', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. - 'v8_revision': '017bc6b893e733863245628de6f216922150bed3', + 'v8_revision': '13036d7a479a2da10ead4bdc99804cd2e93bb201', # 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': '92bd0099204c0b5e8c6daecff9c691b895b87433', + 'angle_revision': '2937ee276cf5bd27fd5254091abdcf1e68a4155b', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. @@ -378,7 +378,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling chromium_variations # and whatever else without interference from each other. - 'chromium_variations_revision': '1e5fa7e62fdeca99624cc64f84edc865a42cd90f', + 'chromium_variations_revision': 'ff1e3775275922c5f8dd82af21637e99339997e1', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling CrossBench # and whatever else without interference from each other. @@ -394,7 +394,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': '8e82459cfc5a48ed593407748bbef1e6c37ce943', + 'devtools_frontend_revision': 'd00d10d6f5adcb3c705c4f81b889c59bcb904d28', # 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. @@ -422,7 +422,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. - 'quiche_revision': '2789c408aa2677e170a7f4f8a044e42a2f5c8bfe', + 'quiche_revision': 'b05cd0f90dcbfb962056ec04263452aa14120677', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ios_webkit # and whatever else without interference from each other. @@ -450,7 +450,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling nearby # and whatever else without interference from each other. - 'nearby_revision': '16cb7f70b3a8b8b04440b7b96534e11df964ca60', + 'nearby_revision': 'cd4963b0f9c68775372d91dc422c01d703122345', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling securemessage # and whatever else without interference from each other. @@ -818,7 +818,7 @@ 'src/clank': { 'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' + - '542d4f710ed7446ff82fa80babd76cf24a5a83bd', + 'fd941d8a913faebbdaddb132368e9eb723e0634d', 'condition': 'checkout_android and checkout_src_internal', }, @@ -980,7 +980,7 @@ 'packages': [ { 'package': 'chromium/third_party/androidx', - 'version': 'N1ABLBt_DnON5SzQTeRtPn5iHl6fXspohb0jh0zCEd8C', + 'version': 'sKE9EWwTmOTcGm70eYsAYbGu43CFvT4K-aBQl27iDhgC', }, ], 'condition': 'checkout_android', @@ -1155,7 +1155,7 @@ # Tools used when building Chrome for Chrome OS. This affects both the Simple # Chrome workflow, as well as the chromeos-chrome ebuild. 'src/third_party/chromite': { - 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '462c04f706e5185ca5e4e9bede03ec7daa2fc92f', + 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'db1410a8915c656c397f6d9111062c9f5a5947db', 'condition': 'checkout_chromeos', }, @@ -1190,13 +1190,13 @@ }, 'src/third_party/depot_tools': - Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '6953ebe3c1825e0f548e8c124a3b85f6c75dbc73', + Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'cd076ba1b0be061d4446e47f68b3ec53122ce95c', 'src/third_party/devtools-frontend/src': Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'), 'src/third_party/devtools-frontend-internal': { - 'url': Var('chrome_git') + '/devtools/devtools-internal.git' + '@' + '7cdb4af2d310e71f3dfc36ccbf901f5944abd5c7', + 'url': Var('chrome_git') + '/devtools/devtools-internal.git' + '@' + '7bc9c8f33ac40a5b30c4a4f8486f25afde26058b', 'condition': 'checkout_src_internal', }, @@ -1975,7 +1975,7 @@ 'packages': [ { 'package': 'chromeos_internal/apps/media_app/app', - 'version': 'FiqnqaWel3Wvt9OGRi4Jt4kqwnyTz93yomvUTHimFe8C', + 'version': 'Kpu7GEJn2XxdxtmWXbJWAeu0uzbQIjw68dRkRaC8fk0C', }, ], 'condition': 'checkout_chromeos and checkout_src_internal', @@ -4004,7 +4004,7 @@ 'src/ios_internal': { 'url': Var('chrome_git') + '/chrome/ios_internal.git' + '@' + - '61b32446e8a800b02f9bbaf7a2dc49b9d752b034', + 'ad7dea67e79c6d152370879b33caf38c79c7e160', 'condition': 'checkout_ios and checkout_src_internal', },
diff --git a/android_webview/renderer/aw_content_renderer_client.cc b/android_webview/renderer/aw_content_renderer_client.cc index be102c4..fb597da 100644 --- a/android_webview/renderer/aw_content_renderer_client.cc +++ b/android_webview/renderer/aw_content_renderer_client.cc
@@ -5,6 +5,7 @@ #include "android_webview/renderer/aw_content_renderer_client.h" #include <memory> +#include <string_view> #include <vector> #include "android_webview/common/aw_switches.h" @@ -208,9 +209,9 @@ android_system_error_page::PopulateErrorPageHtml(error, error_html); } -uint64_t AwContentRendererClient::VisitedLinkHash(const char* canonical_url, - size_t length) { - return visited_link_reader_->ComputeURLFingerprint(canonical_url, length); +uint64_t AwContentRendererClient::VisitedLinkHash( + std::string_view canonical_url) { + return visited_link_reader_->ComputeURLFingerprint(canonical_url); } bool AwContentRendererClient::IsLinkVisited(uint64_t link_hash) {
diff --git a/android_webview/renderer/aw_content_renderer_client.h b/android_webview/renderer/aw_content_renderer_client.h index e805cb8..f566da2e 100644 --- a/android_webview/renderer/aw_content_renderer_client.h +++ b/android_webview/renderer/aw_content_renderer_client.h
@@ -7,6 +7,7 @@ #include <memory> #include <string> +#include <string_view> #include "android_webview/common/mojom/render_message_filter.mojom.h" #include "android_webview/renderer/aw_render_thread_observer.h" @@ -51,7 +52,7 @@ content::mojom::AlternativeErrorPageOverrideInfoPtr alternative_error_page_info, std::string* error_html) override; - uint64_t VisitedLinkHash(const char* canonical_url, size_t length) override; + uint64_t VisitedLinkHash(std::string_view canonical_url) override; bool IsLinkVisited(uint64_t link_hash) override; void RunScriptsAtDocumentStart(content::RenderFrame* render_frame) override; void GetSupportedKeySystems(media::GetSupportedKeySystemsCB cb) override;
diff --git a/ash/BUILD.gn b/ash/BUILD.gn index 0ccc128..ad1f82ca 100644 --- a/ash/BUILD.gn +++ b/ash/BUILD.gn
@@ -1832,6 +1832,8 @@ "system/notification_center/metrics_utils.h", "system/notification_center/notification_center_bubble.cc", "system/notification_center/notification_center_bubble.h", + "system/notification_center/notification_center_controller.cc", + "system/notification_center/notification_center_controller.h", "system/notification_center/notification_center_tray.cc", "system/notification_center/notification_center_tray.h", "system/notification_center/notification_grouping_controller.cc", @@ -2777,6 +2779,7 @@ "wm/window_transient_descendant_iterator.h", "wm/window_util.cc", "wm/window_util.h", + "wm/wm_constants.h", "wm/wm_default_layout_manager.cc", "wm/wm_default_layout_manager.h", "wm/wm_event.cc",
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc index fe458bd..c8534c2 100644 --- a/ash/constants/ash_features.cc +++ b/ash/constants/ash_features.cc
@@ -1440,7 +1440,7 @@ // Enables Photoshop Web integration with holding space. BASE_FEATURE(kHoldingSpacePhotoshopWebIntegration, "HoldingSpacePhotoshopWeb", - base::FEATURE_DISABLED_BY_DEFAULT); + base::FEATURE_ENABLED_BY_DEFAULT); // Enables holding space icon to be permanently displayed with extended file // expiration to increase predictability of the feature. @@ -3527,7 +3527,8 @@ } bool IsGlanceablesV2CalendarViewEnabled() { - return base::FeatureList::IsEnabled(kGlanceablesV2CalendarView); + return base::FeatureList::IsEnabled(kGlanceablesV2CalendarView) || + AreAnyGlanceablesTimeManagementViewsEnabled(); } bool IsGlanceablesV2ErrorMessageEnabled() {
diff --git a/ash/shell.cc b/ash/shell.cc index 66d93a0..50cb4b6 100644 --- a/ash/shell.cc +++ b/ash/shell.cc
@@ -764,7 +764,8 @@ } RemovePreTargetHandler(system_gesture_filter_.get()); RemoveAccessibilityEventHandler(mouse_cursor_filter_.get()); - if (features::IsPeripheralCustomizationEnabled()) { + if (features::IsPeripheralCustomizationEnabled() || + ::features::IsShortcutCustomizationEnabled()) { RemovePreTargetHandler(shortcut_input_handler_.get()); } RemovePreTargetHandler(modality_filter_.get());
diff --git a/ash/system/notification_center/notification_center_bubble.cc b/ash/system/notification_center/notification_center_bubble.cc index c420fcf..c05a8c3 100644 --- a/ash/system/notification_center/notification_center_bubble.cc +++ b/ash/system/notification_center/notification_center_bubble.cc
@@ -6,7 +6,9 @@ #include <memory> +#include "ash/constants/ash_features.h" #include "ash/shelf/shelf.h" +#include "ash/system/notification_center/notification_center_controller.h" #include "ash/system/notification_center/notification_center_tray.h" #include "ash/system/notification_center/views/notification_center_view.h" #include "ash/system/tray/tray_bubble_wrapper.h" @@ -33,8 +35,14 @@ bubble_view_->SetMaxHeight(CalculateMaxTrayBubbleHeight( notification_center_tray_->GetBubbleWindowContainer())); - notification_center_view_ = - bubble_view_->AddChildView(std::make_unique<NotificationCenterView>()); + if (features::IsNotificationCenterControllerEnabled()) { + notification_center_controller_ = + std::make_unique<NotificationCenterController>(); + bubble_view_->AddChildView(notification_center_controller_->CreateView()); + } else { + notification_center_view_ = + bubble_view_->AddChildView(std::make_unique<NotificationCenterView>()); + } bubble_wrapper_ = std::make_unique<TrayBubbleWrapper>(notification_center_tray_); @@ -45,8 +53,13 @@ } void NotificationCenterBubble::ShowBubble() { + if (features::IsNotificationCenterControllerEnabled()) { + notification_center_controller_->InitView(); + } bubble_wrapper_->ShowBubble(std::move(bubble_view_)); - notification_center_view_->Init(); + if (!features::IsNotificationCenterControllerEnabled()) { + notification_center_view_->Init(); + } GetBubbleView()->SizeToContents(); } @@ -58,6 +71,12 @@ return bubble_wrapper_->GetBubbleWidget(); } +NotificationCenterView* NotificationCenterBubble::GetNotificationCenterView() { + return features::IsNotificationCenterControllerEnabled() + ? notification_center_controller_->GetNotificationCenterView() + : notification_center_view_.get(); +} + void NotificationCenterBubble::UpdateBubbleBounds() { auto* bubble_view = GetBubbleView(); bubble_view->SetMaxHeight(CalculateMaxTrayBubbleHeight(
diff --git a/ash/system/notification_center/notification_center_bubble.h b/ash/system/notification_center/notification_center_bubble.h index 74726185..6b15f3a 100644 --- a/ash/system/notification_center/notification_center_bubble.h +++ b/ash/system/notification_center/notification_center_bubble.h
@@ -17,6 +17,7 @@ namespace ash { +class NotificationCenterController; class NotificationCenterTray; class NotificationCenterView; class TrayBubbleView; @@ -44,9 +45,10 @@ TrayBubbleView* GetBubbleView(); views::Widget* GetBubbleWidget(); - NotificationCenterView* notification_center_view() { - return notification_center_view_; - } + // Based on the `NotificationCenterController` feature: + // Returns `notification_center_view_` when the feature is disabled. + // Returns the view cached in `notification_center_controller_` when enabled. + NotificationCenterView* GetNotificationCenterView(); private: friend class NotificationCenterTestApi; @@ -62,8 +64,14 @@ // The main view responsible for showing all notification content in this // bubble. Owned by `TrayBubbleView`. + // Used when `NotificationCenterController` is disabled. raw_ptr<NotificationCenterView> notification_center_view_ = nullptr; + // The controller responsible for managing the NotificationCenterView and its + // children including the `StackedNotificationBar` and `NotificationListView`. + // Used when `NotificationCenterController` is enabled. + std::unique_ptr<NotificationCenterController> notification_center_controller_; + std::unique_ptr<TrayBubbleView> bubble_view_; std::unique_ptr<TrayBubbleWrapper> bubble_wrapper_; };
diff --git a/ash/system/notification_center/notification_center_bubble_unittest.cc b/ash/system/notification_center/notification_center_bubble_unittest.cc index 8d5366d..8d395f1 100644 --- a/ash/system/notification_center/notification_center_bubble_unittest.cc +++ b/ash/system/notification_center/notification_center_bubble_unittest.cc
@@ -7,19 +7,21 @@ #include <cstdint> #include <string> +#include "ash/constants/ash_features.h" #include "ash/public/cpp/shelf_types.h" #include "ash/shelf/shelf.h" #include "ash/shell.h" -#include "ash/system/notification_center/views/ash_notification_view.h" #include "ash/system/notification_center/message_center_utils.h" #include "ash/system/notification_center/notification_center_bubble.h" #include "ash/system/notification_center/notification_center_test_api.h" +#include "ash/system/notification_center/views/ash_notification_view.h" #include "ash/system/notification_center/views/notification_center_view.h" #include "ash/system/notification_center/views/notification_list_view.h" #include "ash/system/status_area_widget.h" #include "ash/test/ash_test_base.h" #include "ash/wm/tablet_mode/tablet_mode_controller.h" #include "base/strings/string_number_conversions.h" +#include "base/test/scoped_feature_list.h" #include "base/test/task_environment.h" #include "ui/display/display.h" #include "ui/display/manager/display_manager.h" @@ -28,30 +30,52 @@ namespace ash { -class NotificationCenterBubbleTest : public AshTestBase { +class NotificationCenterBubbleTestBase : public AshTestBase { public: - NotificationCenterBubbleTest() - : AshTestBase(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {} - NotificationCenterBubbleTest(const NotificationCenterBubbleTest&) = delete; - NotificationCenterBubbleTest& operator=(const NotificationCenterBubbleTest&) = - delete; - ~NotificationCenterBubbleTest() override = default; + NotificationCenterBubbleTestBase(bool enable_notification_center_controller) + : AshTestBase(base::test::TaskEnvironment::TimeSource::MOCK_TIME), + enable_notification_center_controller_( + enable_notification_center_controller) { + scoped_feature_list_.InitWithFeatureState( + features::kNotificationCenterController, + IsNotificationCenterControllerEnabled()); + } void SetUp() override { AshTestBase::SetUp(); - test_api_ = std::make_unique<NotificationCenterTestApi>(); } NotificationCenterTestApi* test_api() { return test_api_.get(); } + bool IsNotificationCenterControllerEnabled() const { + return enable_notification_center_controller_; + } + private: + base::test::ScopedFeatureList scoped_feature_list_; std::unique_ptr<NotificationCenterTestApi> test_api_; + bool enable_notification_center_controller_ = false; }; +class NotificationCenterBubbleTest + : public NotificationCenterBubbleTestBase, + public testing::WithParamInterface< + /*enable_notification_center_controller=*/bool> { + public: + NotificationCenterBubbleTest() + : NotificationCenterBubbleTestBase( + /*enable_notification_center_controller=*/GetParam()) {} +}; + +INSTANTIATE_TEST_SUITE_P( + All, + NotificationCenterBubbleTest, + /*enable_notification_center_controller=*/testing::Bool()); + // Tests that the notification bubble does not get cut off by the top of the // screen on the launcher homescreen in tablet mode; see b/278471988. -TEST_F(NotificationCenterBubbleTest, +TEST_P(NotificationCenterBubbleTest, TopOfBubbleConstrainedByTopOfDisplayInTabletModeHomescreen) { // Set the display to some known size. UpdateDisplay("1200x800"); @@ -77,7 +101,7 @@ 0); } -TEST_F(NotificationCenterBubbleTest, BubbleHeightConstrainedByDisplay) { +TEST_P(NotificationCenterBubbleTest, BubbleHeightConstrainedByDisplay) { const int display_height = 800; UpdateDisplay("1200x" + base::NumberToString(display_height)); @@ -96,7 +120,7 @@ display_height); } -TEST_F(NotificationCenterBubbleTest, BubbleHeightUpdatedByDisplaySizeChange) { +TEST_P(NotificationCenterBubbleTest, BubbleHeightUpdatedByDisplaySizeChange) { UpdateDisplay("800x600"); // Add a large number of notifications to overflow the scroll view in the @@ -120,7 +144,7 @@ EXPECT_EQ(current_bounds.width(), previous_bounds.width()); } -TEST_F(NotificationCenterBubbleTest, BubbleHeightUpdatedByDisplayRotation) { +TEST_P(NotificationCenterBubbleTest, BubbleHeightUpdatedByDisplayRotation) { const int display_width = 1000; const int display_height = 600; UpdateDisplay(base::NumberToString(display_width) + "x" + @@ -158,7 +182,7 @@ // Tests that notifications from a single notifier id are grouped in a single // parent notification view. -TEST_F(NotificationCenterBubbleTest, NotificationsGroupingBasic) { +TEST_P(NotificationCenterBubbleTest, NotificationsGroupingBasic) { const std::string source_url = "http://test-url.com"; std::string id0, id1; @@ -181,7 +205,7 @@ EXPECT_TRUE(parent_notification_view->FindGroupNotificationView(id1)); } -TEST_F(NotificationCenterBubbleTest, +TEST_P(NotificationCenterBubbleTest, NotificationCollapseStatePreservedFromPopup) { std::string id0 = test_api()->AddNotification(); @@ -196,7 +220,7 @@ EXPECT_FALSE(test_api()->GetNotificationViewForId(id0)->IsExpanded()); } -TEST_F(NotificationCenterBubbleTest, +TEST_P(NotificationCenterBubbleTest, NotificationExpandStatePreservedAcrossDisplays) { UpdateDisplay("600x500,600x500"); @@ -237,7 +261,7 @@ ->IsExpanded()); } -TEST_F(NotificationCenterBubbleTest, LockScreenNotificationVisibility) { +TEST_P(NotificationCenterBubbleTest, LockScreenNotificationVisibility) { std::string system_id, id; system_id = test_api()->AddSystemNotification(); id = test_api()->AddNotification(); @@ -253,7 +277,7 @@ // Tests that unlocking the device automatically closes the notification bubble. // See b/287622547. -TEST_F(NotificationCenterBubbleTest, UnlockClosesBubble) { +TEST_P(NotificationCenterBubbleTest, UnlockClosesBubble) { // Add a notification so that the notification tray will be visible on the // lock screen. test_api()->AddNotification(); @@ -274,7 +298,7 @@ EXPECT_FALSE(test_api()->IsBubbleShown()); } -TEST_F(NotificationCenterBubbleTest, LargeNotificationExpand) { +TEST_P(NotificationCenterBubbleTest, LargeNotificationExpand) { const std::string url = "http://test-url.com/"; std::string id0 = test_api()->AddNotificationWithSourceUrl(url); @@ -312,17 +336,16 @@ } class NotificationCenterBubbleMultiDisplayTest - : public NotificationCenterBubbleTest, + : public NotificationCenterBubbleTestBase, public testing::WithParamInterface< std::tuple</* Primary display height */ int, - /* Secondary display height */ int>> { + /* Secondary display height */ int, + /* enable_notification_center_controller */ bool>> { public: - NotificationCenterBubbleMultiDisplayTest() = default; - NotificationCenterBubbleMultiDisplayTest( - const NotificationCenterBubbleMultiDisplayTest&) = delete; - NotificationCenterBubbleMultiDisplayTest& operator=( - const NotificationCenterBubbleMultiDisplayTest&) = delete; - ~NotificationCenterBubbleMultiDisplayTest() override = default; + NotificationCenterBubbleMultiDisplayTest() + : NotificationCenterBubbleTestBase( + /*enable_notification_center_controller=*/std::get<2>(GetParam())) { + } protected: int GetPrimaryDisplayHeight() { return std::get<0>(GetParam()); } @@ -333,11 +356,14 @@ NotificationCenterBubbleMultiDisplayTest, testing::Values( // Short primary display, tall secondary display - std::make_tuple(600, 1600), + std::make_tuple(600, 1600, false), + std::make_tuple(600, 1600, true), // Tall primary display, short secondary display - std::make_tuple(1600, 600), + std::make_tuple(1600, 600, false), + std::make_tuple(1600, 600, true), // Same primary and secondary display heights - std::make_tuple(600, 600))); + std::make_tuple(600, 600, false), + std::make_tuple(600, 600, true))); // Tests that the height of the bubble is constrained according to the // parameters of the display it is being shown on.
diff --git a/ash/system/notification_center/notification_center_controller.cc b/ash/system/notification_center/notification_center_controller.cc new file mode 100644 index 0000000..f73f8a8 --- /dev/null +++ b/ash/system/notification_center/notification_center_controller.cc
@@ -0,0 +1,37 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/system/notification_center/notification_center_controller.h" + +#include "ash/constants/ash_features.h" +#include "ash/system/notification_center/views/notification_center_view.h" +#include "ui/views/view.h" + +namespace ash { + +NotificationCenterController::NotificationCenterController() { + CHECK(features::IsNotificationCenterControllerEnabled()); +} + +NotificationCenterController::~NotificationCenterController() = default; + +std::unique_ptr<views::View> NotificationCenterController::CreateView() { + auto notification_center_view = std::make_unique<NotificationCenterView>(); + notification_center_view_tracker_.SetView(notification_center_view.get()); + return std::move(notification_center_view); +} + +void NotificationCenterController::InitView() { + auto* notification_center_view = GetNotificationCenterView(); + CHECK(notification_center_view); + notification_center_view->Init(); +} + +NotificationCenterView* +NotificationCenterController::GetNotificationCenterView() { + return static_cast<NotificationCenterView*>( + notification_center_view_tracker_.view()); +} + +} // namespace ash
diff --git a/ash/system/notification_center/notification_center_controller.h b/ash/system/notification_center/notification_center_controller.h new file mode 100644 index 0000000..8861927 --- /dev/null +++ b/ash/system/notification_center/notification_center_controller.h
@@ -0,0 +1,48 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_SYSTEM_NOTIFICATION_CENTER_NOTIFICATION_CENTER_CONTROLLER_H_ +#define ASH_SYSTEM_NOTIFICATION_CENTER_NOTIFICATION_CENTER_CONTROLLER_H_ + +#include "ash/ash_export.h" +#include "base/memory/raw_ptr.h" +#include "ui/views/view_tracker.h" + +namespace views { +class View; +} // namespace views + +namespace ash { + +class NotificationCenterView; + +// Manages and updates `NotificationCenterView`. +class ASH_EXPORT NotificationCenterController { + public: + NotificationCenterController(); + + NotificationCenterController(const NotificationCenterController&) = delete; + NotificationCenterController& operator=(const NotificationCenterController&) = + delete; + + ~NotificationCenterController(); + + // Creates a `NotificationCenterView` object and returns it so it can be added + // to the parent bubble view. + std::unique_ptr<views::View> CreateView(); + + // Inits the tracked `NotificationCenterView`. + void InitView(); + + // Returns the view tracked by `notification_center_view_tracker_`. + NotificationCenterView* GetNotificationCenterView(); + + private: + // View tracker to safely access `NotificationCenterView`. + views::ViewTracker notification_center_view_tracker_; +}; + +} // namespace ash + +#endif // ASH_SYSTEM_NOTIFICATION_CENTER_NOTIFICATION_CENTER_CONTROLLER_H_
diff --git a/ash/system/notification_center/notification_center_test_api.cc b/ash/system/notification_center/notification_center_test_api.cc index 44a1bc1..d0bcf85 100644 --- a/ash/system/notification_center/notification_center_test_api.cc +++ b/ash/system/notification_center/notification_center_test_api.cc
@@ -3,8 +3,10 @@ // found in the LICENSE file. #include "ash/system/notification_center/notification_center_test_api.h" + #include <cstdint> +#include "ash/constants/ash_features.h" #include "ash/focus_cycler.h" #include "ash/root_window_controller.h" #include "ash/shelf/shelf.h" @@ -13,9 +15,9 @@ #include "ash/system/notification_center/message_center_utils.h" #include "ash/system/notification_center/notification_center_bubble.h" #include "ash/system/notification_center/notification_center_tray.h" +#include "ash/system/notification_center/stacked_notification_bar.h" #include "ash/system/notification_center/views/notification_center_view.h" #include "ash/system/notification_center/views/notification_list_view.h" -#include "ash/system/notification_center/stacked_notification_bar.h" #include "ash/system/unified/notification_counter_view.h" #include "ash/system/unified/unified_system_tray.h" #include "base/ranges/algorithm.h" @@ -317,7 +319,7 @@ return nullptr; } - return GetTrayOnDisplay(display_id)->bubble_->notification_center_view_.get(); + return GetTrayOnDisplay(display_id)->bubble_->GetNotificationCenterView(); } NotificationCenterView* NotificationCenterTestApi::GetNotificationCenterView() { @@ -335,9 +337,10 @@ } views::View* NotificationCenterTestApi::GetClearAllButton() { - return GetTray() - ->bubble_->notification_center_view_->notification_bar_ - ->clear_all_button_; + auto* notification_center_view = GetNotificationCenterView(); + return notification_center_view + ? notification_center_view->notification_bar_->clear_all_button_ + : nullptr; } std::string NotificationCenterTestApi::NotificationIdToParentNotificationId( @@ -366,8 +369,8 @@ int64_t display_id) { DCHECK(message_center::MessageCenter::Get()->IsMessageCenterVisible()); - return GetTrayOnDisplay(display_id) - ->bubble_->notification_center_view_->notification_list_view(); + return GetNotificationCenterViewOnDisplay(display_id) + ->notification_list_view(); } std::unique_ptr<message_center::Notification>
diff --git a/ash/system/notification_center/notification_center_tray.cc b/ash/system/notification_center/notification_center_tray.cc index 211dc05..4878bf8 100644 --- a/ash/system/notification_center/notification_center_tray.cc +++ b/ash/system/notification_center/notification_center_tray.cc
@@ -100,8 +100,14 @@ } NotificationListView* NotificationCenterTray::GetNotificationListView() { - return bubble_ ? bubble_->notification_center_view()->notification_list_view() - : nullptr; + if (!bubble_) { + return nullptr; + } + + auto* notification_center_view = bubble_->GetNotificationCenterView(); + return notification_center_view + ? notification_center_view->notification_list_view() + : nullptr; } bool NotificationCenterTray::IsBubbleShown() const {
diff --git a/ash/system/notification_center/notification_center_tray_unittest.cc b/ash/system/notification_center/notification_center_tray_unittest.cc index c6841fc..eea4be7 100644 --- a/ash/system/notification_center/notification_center_tray_unittest.cc +++ b/ash/system/notification_center/notification_center_tray_unittest.cc
@@ -32,28 +32,50 @@ constexpr char kNotificationCenterTrayNoNotificationsToastId[] = "notification_center_tray_toast_ids.no_notifications"; -class NotificationCenterTrayTest : public AshTestBase { +class NotificationCenterTrayTestBase : public AshTestBase { public: - NotificationCenterTrayTest() = default; - NotificationCenterTrayTest(const NotificationCenterTrayTest&) = delete; - NotificationCenterTrayTest& operator=(const NotificationCenterTrayTest&) = - delete; - ~NotificationCenterTrayTest() override = default; + NotificationCenterTrayTestBase(bool enable_notification_center_controller) + : enable_notification_center_controller_( + enable_notification_center_controller) { + scoped_feature_list_.InitWithFeatureState( + features::kNotificationCenterController, + IsNotificationCenterControllerEnabled()); + } void SetUp() override { AshTestBase::SetUp(); - test_api_ = std::make_unique<NotificationCenterTestApi>(); } NotificationCenterTestApi* test_api() { return test_api_.get(); } + bool IsNotificationCenterControllerEnabled() const { + return enable_notification_center_controller_; + } + private: + base::test::ScopedFeatureList scoped_feature_list_; std::unique_ptr<NotificationCenterTestApi> test_api_; + bool enable_notification_center_controller_ = false; }; +class NotificationCenterTrayTest + : public NotificationCenterTrayTestBase, + public testing::WithParamInterface< + /*enable_notification_center_controller=*/bool> { + public: + NotificationCenterTrayTest() + : NotificationCenterTrayTestBase( + /*enable_notification_center_controller=*/GetParam()) {} +}; + +INSTANTIATE_TEST_SUITE_P( + All, + NotificationCenterTrayTest, + /*enable_notification_center_controller=*/testing::Bool()); + // Test the initial state. -TEST_F(NotificationCenterTrayTest, ShowTrayButtonOnNotificationAvailability) { +TEST_P(NotificationCenterTrayTest, ShowTrayButtonOnNotificationAvailability) { EXPECT_FALSE(test_api()->GetTray()->GetVisible()); std::string id = test_api()->AddNotification(); @@ -65,7 +87,7 @@ } // Bubble creation and destruction. -TEST_F(NotificationCenterTrayTest, ShowAndHideBubbleOnUserInteraction) { +TEST_P(NotificationCenterTrayTest, ShowAndHideBubbleOnUserInteraction) { test_api()->AddNotification(); auto* tray = test_api()->GetTray(); @@ -81,7 +103,7 @@ // Hitting escape after opening the bubble should destroy the bubble // gracefully. -TEST_F(NotificationCenterTrayTest, EscapeClosesBubble) { +TEST_P(NotificationCenterTrayTest, EscapeClosesBubble) { auto* tray = test_api()->GetTray(); LeftClickOn(tray); PressAndReleaseKey(ui::KeyboardCode::VKEY_ESCAPE); @@ -91,7 +113,7 @@ // Removing all notifications by hitting the `clear_all_button_` should result // in the bubble being destroyed and the tray bubble going invisible. -TEST_F(NotificationCenterTrayTest, +TEST_P(NotificationCenterTrayTest, ClearAllNotificationsDestroysBubbleAndHidesTray) { test_api()->AddNotification(); test_api()->AddNotification(); @@ -107,8 +129,8 @@ // The last notification being removed directly by the // `message_center::MessageCenter` API should result in the bubble being -// destroyed and tray visibilty being updated. -TEST_F(NotificationCenterTrayTest, NotificationsRemovedByMessageCenterApi) { +// destroyed and tray visibility being updated. +TEST_P(NotificationCenterTrayTest, NotificationsRemovedByMessageCenterApi) { std::string id = test_api()->AddNotification(); test_api()->RemoveNotification(id); @@ -119,7 +141,7 @@ // When the only notifications present are all in the same group, removing the // parent notification of that group should result in the bubble being destroyed // and the tray being hidden. -TEST_F(NotificationCenterTrayTest, +TEST_P(NotificationCenterTrayTest, RemovingGroupParentDestroysBubbleAndHidesTray) { // Add two notifications that belong to the same group. const std::string url = "http://test-url.com"; @@ -145,7 +167,7 @@ // Tests that clicking on the tray immediately after all notifications have been // removed does not result in an empty bubble being shown. This addresses // b/293174118. -TEST_F(NotificationCenterTrayTest, ClickOnTrayAfterRemovingNotifications) { +TEST_P(NotificationCenterTrayTest, ClickOnTrayAfterRemovingNotifications) { // Add a notification to make the tray visible. Note that animations complete // immediately in this part of the test. std::string id = test_api()->AddNotification(); @@ -173,7 +195,7 @@ // Tests that opening the bubble results in existing popups being dismissed // and no new ones being created. -TEST_F(NotificationCenterTrayTest, NotificationPopupsHiddenWithBubble) { +TEST_P(NotificationCenterTrayTest, NotificationPopupsHiddenWithBubble) { // Adding a notification should generate a popup. std::string id = test_api()->AddNotification(); EXPECT_TRUE(test_api()->IsPopupShown(id)); @@ -189,7 +211,7 @@ } // Tests that popups are shown after the notification center is closed. -TEST_F(NotificationCenterTrayTest, NotificationPopupsShownAfterBubbleClose) { +TEST_P(NotificationCenterTrayTest, NotificationPopupsShownAfterBubbleClose) { test_api()->AddNotification(); // Open and close bubble to dismiss existing popups. @@ -202,7 +224,7 @@ } // Keyboard accelerator shows/hides the bubble. -TEST_F(NotificationCenterTrayTest, AcceleratorTogglesBubble) { +TEST_P(NotificationCenterTrayTest, AcceleratorTogglesBubble) { test_api()->AddNotification(); EXPECT_FALSE(test_api()->IsBubbleShown()); // Pressing the accelerator should show the bubble. @@ -216,7 +238,7 @@ } // Keyboard accelerator shows a toast when there are no notifications. -TEST_F(NotificationCenterTrayTest, AcceleratorShowsToastWhenNoNotifications) { +TEST_P(NotificationCenterTrayTest, AcceleratorShowsToastWhenNoNotifications) { ASSERT_EQ(test_api()->GetNotificationCount(), 0u); EXPECT_FALSE(ToastManager::Get()->IsToastShown( kNotificationCenterTrayNoNotificationsToastId)); @@ -230,7 +252,7 @@ // Tests that the bubble automatically hides if it is visible when another // bubble becomes visible, and otherwise does not automatically show or hide. -TEST_F(NotificationCenterTrayTest, BubbleHideBehavior) { +TEST_P(NotificationCenterTrayTest, BubbleHideBehavior) { // Basic verification test that the notification center tray bubble can // show/hide itself when no other bubbles are visible. EXPECT_FALSE(test_api()->IsBubbleShown()); @@ -259,7 +281,7 @@ // Tests that visibility of the Do not disturb icon changes with Do not disturb // mode. -TEST_F(NotificationCenterTrayTest, DoNotDisturbIconVisibility) { +TEST_P(NotificationCenterTrayTest, DoNotDisturbIconVisibility) { // Test the case where the tray is not initially visible. ASSERT_FALSE(test_api()->IsTrayShown()); EXPECT_FALSE(test_api()->IsDoNotDisturbIconShown()); @@ -282,7 +304,7 @@ EXPECT_FALSE(test_api()->IsDoNotDisturbIconShown()); } -TEST_F(NotificationCenterTrayTest, DoNotDisturbUpdatesPinnedIcons) { +TEST_P(NotificationCenterTrayTest, DoNotDisturbUpdatesPinnedIcons) { test_api()->AddPinnedNotification(); EXPECT_TRUE(test_api()->IsNotificationIconShown()); @@ -293,7 +315,7 @@ EXPECT_TRUE(test_api()->IsNotificationIconShown()); } -TEST_F(NotificationCenterTrayTest, NoPrivacyIndicatorsWhenVcEnabled) { +TEST_P(NotificationCenterTrayTest, NoPrivacyIndicatorsWhenVcEnabled) { // No privacy indicators when `kVideoConference` is enabled. base::test::ScopedFeatureList scoped_feature_list; scoped_feature_list.InitWithFeatures( @@ -308,7 +330,7 @@ // Tests that the focus ring is visible and has proper size when the // notification center tray is focused. -TEST_F(NotificationCenterTrayTest, FocusRing) { +TEST_P(NotificationCenterTrayTest, FocusRing) { // Add a notification to make the notification center tray visible. test_api()->AddNotification(); ASSERT_TRUE(test_api()->IsTrayShown()); @@ -328,7 +350,7 @@ // Tests that removing all notifications while the lock screen is showing hides // the tray. -TEST_F(NotificationCenterTrayTest, +TEST_P(NotificationCenterTrayTest, RemovingAllNotificationsOnLockScreenHidesTray) { // Add a notification to make the notification center tray visible. const std::string id = test_api()->AddNotification(); @@ -346,7 +368,7 @@ // Tests that adding an initial notification while the lock screen is showing // shows the tray. -TEST_F(NotificationCenterTrayTest, AddingNotificationOnLockScreenShowsTray) { +TEST_P(NotificationCenterTrayTest, AddingNotificationOnLockScreenShowsTray) { // Show the lock screen. BlockUserSession(BLOCKED_BY_LOCK_SCREEN); ASSERT_FALSE(test_api()->IsTrayShown()); @@ -361,7 +383,7 @@ // Tests that `NotificationCounterView` is not still visible on secondary // display after logging in with a pinned notification present. This covers // b/284139989. -TEST_F(NotificationCenterTrayTest, +TEST_P(NotificationCenterTrayTest, NotificationCounterVisibilityForMultiDisplay) { // The behavior under test relies on `TrayItemView` animations being // scheduled, but `TrayItemView` animations are bypassed when the animation @@ -406,28 +428,33 @@ } // Test fixture that disables notification popups. -class NotificationCenterTrayNoPopupsTest : public NotificationCenterTrayTest { +class NotificationCenterTrayNoPopupsTest + : public NotificationCenterTrayTestBase, + public testing::WithParamInterface< + /*enable_notification_center_controller=*/bool> { public: - NotificationCenterTrayNoPopupsTest() = default; - NotificationCenterTrayNoPopupsTest( - const NotificationCenterTrayNoPopupsTest&) = delete; - NotificationCenterTrayNoPopupsTest& operator=( - const NotificationCenterTrayNoPopupsTest&) = delete; - ~NotificationCenterTrayNoPopupsTest() override = default; + NotificationCenterTrayNoPopupsTest() + : NotificationCenterTrayTestBase( + /*enable_notification_center_controller=*/GetParam()) {} void SetUp() override { base::CommandLine::ForCurrentProcess()->AppendSwitch( switches::kSuppressMessageCenterPopups); - NotificationCenterTrayTest::SetUp(); + NotificationCenterTrayTestBase::SetUp(); } }; +INSTANTIATE_TEST_SUITE_P( + All, + NotificationCenterTrayNoPopupsTest, + /*enable_notification_center_controller=*/testing::Bool()); + // Tests that `NotificationCenterTray`'s `TrayItemView`s show up when adding a // secondary display. Notification popups are disabled for this test because the // presence of a popup actually hides the issue (i.e. the secondary display's // `NotificationCenterTray`'s `TrayItemView`s work as intended when a popup is // present). This covers b/281158734. -TEST_F(NotificationCenterTrayNoPopupsTest, +TEST_P(NotificationCenterTrayNoPopupsTest, TrayItemsVisibleWhenAddingSecondaryDisplay) { // Start with one display. UpdateDisplay("800x799");
diff --git a/ash/system/notification_center/views/notification_center_view_unittest.cc b/ash/system/notification_center/views/notification_center_view_unittest.cc index 3b8f1f2..60713868 100644 --- a/ash/system/notification_center/views/notification_center_view_unittest.cc +++ b/ash/system/notification_center/views/notification_center_view_unittest.cc
@@ -39,16 +39,17 @@ namespace ash { -class NotificationCenterViewTest : public AshTestBase, - public views::ViewObserver { +class NotificationCenterViewTest + : public AshTestBase, + public views::ViewObserver, + public testing::WithParamInterface< + /*enable_notification_center_controller=*/bool> { public: - NotificationCenterViewTest() = default; - - NotificationCenterViewTest(const NotificationCenterViewTest&) = delete; - NotificationCenterViewTest& operator=(const NotificationCenterViewTest&) = - delete; - - ~NotificationCenterViewTest() override = default; + NotificationCenterViewTest() { + scoped_feature_list_.InitWithFeatureState( + features::kNotificationCenterController, + IsNotificationCenterControllerEnabled()); + } // AshTestBase: void SetUp() override { @@ -73,6 +74,8 @@ ++size_changed_count_; } + bool IsNotificationCenterControllerEnabled() const { return GetParam(); } + protected: // Adds more than enough notifications to make the message center scrollable. std::vector<std::string> AddManyNotifications() { @@ -212,10 +215,15 @@ int size_changed_count_ = 0; std::unique_ptr<NotificationCenterTestApi> test_api_; - std::unique_ptr<base::test::ScopedFeatureList> scoped_feature_list_; + base::test::ScopedFeatureList scoped_feature_list_; }; -TEST_F(NotificationCenterViewTest, ContentsRelayout) { +INSTANTIATE_TEST_SUITE_P( + All, + NotificationCenterViewTest, + /*enable_notification_center_controller=*/testing::Bool()); + +TEST_P(NotificationCenterViewTest, ContentsRelayout) { std::vector<std::string> ids = AddManyNotifications(); test_api()->ToggleBubble(); EXPECT_TRUE(notification_center_view()->GetVisible()); @@ -237,7 +245,7 @@ GetNotificationListView()->height()); } -TEST_F(NotificationCenterViewTest, VisibleWhenLocked) { +TEST_P(NotificationCenterViewTest, VisibleWhenLocked) { // This test is only valid if the lock screen feature is enabled. // TODO(yoshiki): Clean up after the feature is launched crbug.com/913764. if (!features::IsLockScreenNotificationsEnabled()) { @@ -261,7 +269,7 @@ EXPECT_TRUE(notification_center_view()->GetVisible()); } -TEST_F(NotificationCenterViewTest, ClearAllPressed) { +TEST_P(NotificationCenterViewTest, ClearAllPressed) { test_api()->AddNotification(); test_api()->AddNotification(); test_api()->ToggleBubble(); @@ -273,7 +281,7 @@ notification_center_view()->ClearAllNotifications(); } -TEST_F(NotificationCenterViewTest, InitialPosition) { +TEST_P(NotificationCenterViewTest, InitialPosition) { test_api()->AddNotification(); test_api()->AddNotification(); test_api()->ToggleBubble(); @@ -284,7 +292,7 @@ notification_center_view()->bounds().height()); } -TEST_F(NotificationCenterViewTest, InitialPositionMaxOut) { +TEST_P(NotificationCenterViewTest, InitialPositionMaxOut) { AddManyNotifications(); test_api()->ToggleBubble(); EXPECT_TRUE(notification_center_view()->GetVisible()); @@ -295,7 +303,7 @@ } // Tests basic layout of the StackingNotificationBar. -TEST_F(NotificationCenterViewTest, StackingCounterLabelLayout) { +TEST_P(NotificationCenterViewTest, StackingCounterLabelLayout) { UpdateDisplay("800x500"); AddManyNotifications(); @@ -318,7 +326,7 @@ } // Tests that the NotificationBarLabel is invisible when scrolled to the top. -TEST_F(NotificationCenterViewTest, StackingCounterLabelInvisible) { +TEST_P(NotificationCenterViewTest, StackingCounterLabelInvisible) { UpdateDisplay("800x500"); AddManyNotifications(); @@ -337,7 +345,7 @@ // Tests that the NotificationBarLabel is visible when there are enough excess // notifications. -TEST_F(NotificationCenterViewTest, StackingCounterLabelVisible) { +TEST_P(NotificationCenterViewTest, StackingCounterLabelVisible) { UpdateDisplay("800x500"); AddManyNotifications(); @@ -349,7 +357,7 @@ } // Tests that the +n notifications label hides after being shown. -TEST_F(NotificationCenterViewTest, StackingCounterLabelHidesAfterShown) { +TEST_P(NotificationCenterViewTest, StackingCounterLabelHidesAfterShown) { UpdateDisplay("800x500"); AddManyNotifications(); @@ -383,7 +391,7 @@ // time (this prevents the user from over-scrolling and showing multiple // animations when they scroll very quickly). Before, users could scroll fast // and have a large amount of icons, instead of keeping it to 3. -TEST_F(NotificationCenterViewTest, StackingIconsNeverMoreThanThree) { +TEST_P(NotificationCenterViewTest, StackingIconsNeverMoreThanThree) { for (int i = 0; i < 20; ++i) { test_api()->AddNotification(); } @@ -419,7 +427,7 @@ } } -TEST_F(NotificationCenterViewTest, StackingCounterLabelRelaidOutOnScroll) { +TEST_P(NotificationCenterViewTest, StackingCounterLabelRelaidOutOnScroll) { // Open the message center at the top of the notification list so the stacking // bar is hidden by default. std::string id = test_api()->AddNotification(); @@ -456,7 +464,7 @@ EXPECT_GT(GetNotificationBarLabel()->bounds().width(), label_width); } -TEST_F(NotificationCenterViewTest, FocusClearedAfterNotificationRemoval) { +TEST_P(NotificationCenterViewTest, FocusClearedAfterNotificationRemoval) { test_api()->AddNotification(); auto id1 = test_api()->AddNotification(); @@ -473,7 +481,7 @@ EXPECT_FALSE(notification_center_view()->GetFocusManager()->GetFocusedView()); } -TEST_F(NotificationCenterViewTest, ClearAllButtonHeight) { +TEST_P(NotificationCenterViewTest, ClearAllButtonHeight) { std::string id0 = test_api()->AddNotification(); std::string id1 = test_api()->AddNotification(); test_api()->ToggleBubble(); @@ -494,7 +502,7 @@ } // Tests that the "Clear all" button is not focusable when it is disabled. -TEST_F(NotificationCenterViewTest, ClearAllNotFocusableWhenDisabled) { +TEST_P(NotificationCenterViewTest, ClearAllNotFocusableWhenDisabled) { // Add a pinned notification and toggle the bubble. test_api()->AddPinnedNotification(); test_api()->ToggleBubble(); @@ -510,7 +518,7 @@ EXPECT_FALSE(GetNotificationBarClearAllButton()->HasFocus()); } -TEST_F(NotificationCenterViewTest, StackedNotificationCount) { +TEST_P(NotificationCenterViewTest, StackedNotificationCount) { // There should not be any stacked notifications in the message // center with just one notification added. test_api()->AddNotification(); @@ -529,7 +537,7 @@ } // Test for notification swipe control visibility. -TEST_F(NotificationCenterViewTest, NotificationPartialSwipe) { +TEST_P(NotificationCenterViewTest, NotificationPartialSwipe) { auto id1 = test_api()->AddNotification(); test_api()->ToggleBubble(); auto* view = test_api()->GetNotificationViewForId(id1);
diff --git a/ash/system/notification_center/views/notification_list_view_unittest.cc b/ash/system/notification_center/views/notification_list_view_unittest.cc index b24f2b68..8b89ef9 100644 --- a/ash/system/notification_center/views/notification_list_view_unittest.cc +++ b/ash/system/notification_center/views/notification_list_view_unittest.cc
@@ -4,15 +4,17 @@ #include "ash/system/notification_center/views/notification_list_view.h" -#include "ash/system/notification_center/views/ash_notification_view.h" +#include "ash/constants/ash_features.h" #include "ash/system/notification_center/message_center_constants.h" #include "ash/system/notification_center/notification_center_test_api.h" +#include "ash/system/notification_center/views/ash_notification_view.h" #include "ash/system/unified/unified_system_tray_model.h" #include "ash/test/ash_test_base.h" #include "base/memory/raw_ptr.h" #include "base/memory/scoped_refptr.h" #include "base/run_loop.h" #include "base/strings/string_number_conversions.h" +#include "base/test/scoped_feature_list.h" #include "base/time/time.h" #include "ui/base/models/image_model.h" #include "ui/compositor/layer.h" @@ -126,15 +128,17 @@ // The base test class, has no params so tests with no params can inherit from // this. -class NotificationListViewTest : public AshTestBase, - public views::ViewObserver { +class NotificationListViewTest + : public AshTestBase, + public views::ViewObserver, + public testing::WithParamInterface< + /*enable_notification_center_controller=*/bool> { public: - NotificationListViewTest() = default; - - NotificationListViewTest(const NotificationListViewTest&) = delete; - NotificationListViewTest& operator=(const NotificationListViewTest&) = delete; - - ~NotificationListViewTest() override = default; + NotificationListViewTest() { + scoped_feature_list_.InitWithFeatureState( + features::kNotificationCenterController, + IsNotificationCenterControllerEnabled()); + } void SetUp() override { AshTestBase::SetUp(); @@ -158,6 +162,8 @@ NotificationCenterTestApi* test_api() { return test_api_.get(); } + bool IsNotificationCenterControllerEnabled() const { return GetParam(); } + protected: std::string AddNotification(bool pinned = false, bool expandable = false) { std::string id = base::NumberToString(id_++); @@ -252,12 +258,18 @@ int id_ = 0; int size_changed_count_ = 0; + base::test::ScopedFeatureList scoped_feature_list_; std::unique_ptr<NotificationCenterTestApi> test_api_; scoped_refptr<UnifiedSystemTrayModel> model_; std::unique_ptr<TestNotificationListView> notification_list_view_; }; -TEST_F(NotificationListViewTest, Open) { +INSTANTIATE_TEST_SUITE_P( + All, + NotificationListViewTest, + /*enable_notification_center_controller=*/testing::Bool()); + +TEST_P(NotificationListViewTest, Open) { auto id0 = AddNotification(); auto id1 = AddNotification(); auto id2 = AddNotification(); @@ -294,7 +306,7 @@ EXPECT_LT(0, message_list_view()->GetPreferredSize().height()); } -TEST_F(NotificationListViewTest, AddNotifications) { +TEST_P(NotificationListViewTest, AddNotifications) { CreateMessageListView(); EXPECT_EQ(0, message_list_view()->GetPreferredSize().height()); @@ -332,7 +344,7 @@ EXPECT_EQ(top_bottom_corner_radius, GetMessageViewAt(1)->bottom_radius()); } -TEST_F(NotificationListViewTest, RemoveNotification) { +TEST_P(NotificationListViewTest, RemoveNotification) { auto id0 = AddNotification(); auto id1 = AddNotification(); @@ -365,7 +377,7 @@ EXPECT_EQ(0, message_list_view()->GetPreferredSize().height()); } -TEST_F(NotificationListViewTest, CollapseOlderNotifications) { +TEST_P(NotificationListViewTest, CollapseOlderNotifications) { AddNotification(); CreateMessageListView(); EXPECT_TRUE(GetMessageViewAt(0)->IsExpanded()); @@ -393,7 +405,7 @@ EXPECT_FALSE(GetMessageViewAt(3)->IsExpanded()); } -TEST_F(NotificationListViewTest, RemovingNotificationAnimation) { +TEST_P(NotificationListViewTest, RemovingNotificationAnimation) { auto id0 = AddNotification(/*pinned=*/false); auto id1 = AddNotification(); auto id2 = AddNotification(); @@ -432,7 +444,7 @@ } // Flaky: https://crbug.com/1292774. -TEST_F(NotificationListViewTest, DISABLED_ResetAnimation) { +TEST_P(NotificationListViewTest, DISABLED_ResetAnimation) { auto id0 = AddNotification(); auto id1 = AddNotification(); CreateMessageListView(); @@ -451,7 +463,7 @@ EXPECT_EQ(id2, GetMessageViewAt(1)->notification_id()); } -TEST_F(NotificationListViewTest, KeepManuallyExpanded) { +TEST_P(NotificationListViewTest, KeepManuallyExpanded) { AddNotification(); AddNotification(); CreateMessageListView(); @@ -494,7 +506,7 @@ EXPECT_FALSE(GetMessageViewAt(0)->IsManuallyExpandedOrCollapsed()); } -TEST_F(NotificationListViewTest, ClearAllWithOnlyVisibleNotifications) { +TEST_P(NotificationListViewTest, ClearAllWithOnlyVisibleNotifications) { AddNotification(); AddNotification(); CreateMessageListView(); @@ -536,7 +548,7 @@ EXPECT_FALSE(IsAnimating()); } -TEST_F(NotificationListViewTest, ClearAllWithStackingNotifications) { +TEST_P(NotificationListViewTest, ClearAllWithStackingNotifications) { AddNotification(); AddNotification(); AddNotification(); @@ -583,7 +595,7 @@ EXPECT_FALSE(IsAnimating()); } -TEST_F(NotificationListViewTest, ClearAllClosedInTheMiddle) { +TEST_P(NotificationListViewTest, ClearAllClosedInTheMiddle) { AddNotification(); AddNotification(); AddNotification(); @@ -596,7 +608,7 @@ EXPECT_TRUE(MessageCenter::Get()->GetVisibleNotifications().empty()); } -TEST_F(NotificationListViewTest, ClearAllInterrupted) { +TEST_P(NotificationListViewTest, ClearAllInterrupted) { AddNotification(); AddNotification(); AddNotification(); @@ -610,7 +622,7 @@ EXPECT_TRUE(MessageCenter::Get()->FindVisibleNotificationById(new_id)); } -TEST_F(NotificationListViewTest, ClearAllWithPinnedNotifications) { +TEST_P(NotificationListViewTest, ClearAllWithPinnedNotifications) { AddNotification(/*pinned=*/true); AddNotification(); AddNotification(); @@ -621,7 +633,7 @@ EXPECT_EQ(1u, message_list_view()->children().size()); } -TEST_F(NotificationListViewTest, ClearAllWithStackingAndPinnedNotifications) { +TEST_P(NotificationListViewTest, ClearAllWithStackingAndPinnedNotifications) { AddNotification(/*pinned=*/true); AddNotification(/*pinned=*/true); AddNotification(); @@ -637,7 +649,7 @@ } // Flaky: https://crbug.com/1292701. -TEST_F(NotificationListViewTest, DISABLED_UserSwipesAwayNotification) { +TEST_P(NotificationListViewTest, DISABLED_UserSwipesAwayNotification) { // Show message list with two notifications. AddNotification(); auto id1 = AddNotification(); @@ -663,7 +675,7 @@ EXPECT_FALSE(message_list_view()->IsAnimating()); } -TEST_F(NotificationListViewTest, InitInSortedOrder) { +TEST_P(NotificationListViewTest, InitInSortedOrder) { // MessageViews should be ordered, from top down: [ id1, id2, id0 ]. auto id0 = AddNotification(/*pinned=*/true); OffsetNotificationTimestamp(id0, 2000 /* milliseconds */); @@ -678,7 +690,7 @@ EXPECT_EQ(id0, GetMessageViewAt(0)->notification_id()); } -TEST_F(NotificationListViewTest, NotificationAddedInSortedOrder) { +TEST_P(NotificationListViewTest, NotificationAddedInSortedOrder) { auto id0 = AddNotification(/*pinned=*/true); OffsetNotificationTimestamp(id0, 3000 /* milliseconds */); auto id1 = AddNotification(); @@ -704,7 +716,7 @@ EXPECT_EQ(id3, GetMessageViewAt(0)->notification_id()); } -TEST_F(NotificationListViewTest, OnChildNotificationViewUpdated) { +TEST_P(NotificationListViewTest, OnChildNotificationViewUpdated) { const std::string source_url = "http://test-url.com"; std::string id0; @@ -753,7 +765,7 @@ } // Tests that preferred size changes upon toggle of expand/collapse. -TEST_F(NotificationListViewTest, PreferredSizeChangesOnToggle) { +TEST_P(NotificationListViewTest, PreferredSizeChangesOnToggle) { AddNotification(/*pinned=*/false, /*expandable=*/true); AddNotification(/*pinned=*/false, /*expandable=*/true); CreateMessageListView(); @@ -787,7 +799,7 @@ // Tests that expanding a notification while a different notification is // expanding is handled gracefully. -TEST_F(NotificationListViewTest, TwoExpandsInARow) { +TEST_P(NotificationListViewTest, TwoExpandsInARow) { AddNotification(/*pinned=*/false, /*expandable=*/true); AddNotification(/*pinned=*/false, /*expandable=*/true); CreateMessageListView(); @@ -828,7 +840,7 @@ } // Tests that collapsing/expanding is reversible. -TEST_F(NotificationListViewTest, ReverseExpand) { +TEST_P(NotificationListViewTest, ReverseExpand) { AddNotification(/*pinned=*/false, /*expandable=*/true); AddNotification(/*pinned=*/false, /*expandable=*/true); CreateMessageListView(); @@ -856,7 +868,7 @@ } // Tests that destroying during a collapse animation does not crash. -TEST_F(NotificationListViewTest, DestroyMessageListViewDuringCollapse) { +TEST_P(NotificationListViewTest, DestroyMessageListViewDuringCollapse) { AddNotification(/*pinned=*/false, /*expandable=*/true); AddNotification(/*pinned=*/false, /*expandable=*/true); CreateMessageListView(); @@ -869,7 +881,7 @@ // Tests that closing a notification while its collapse animation is ongoing // works properly. -TEST_F(NotificationListViewTest, RemoveNotificationDuringCollapse) { +TEST_P(NotificationListViewTest, RemoveNotificationDuringCollapse) { auto id1 = AddNotification(/*pinned=*/false, /*expandable=*/true); CreateMessageListView(); auto* message_view = GetMessageViewAt(0); @@ -895,7 +907,7 @@ // Tests that expanding a notification at various stages while it is being // closed does not result in an animation. // TODO(crbug.com/1292775): Test is flaky. -TEST_F(NotificationListViewTest, +TEST_P(NotificationListViewTest, DISABLED_CollapseDuringCloseResultsInNoCollapseAnimation) { auto id1 = AddNotification(/*pinned=*/false, /*expandable=*/true); AddNotification(/*pinned=*/false, /*expandable=*/true); @@ -933,7 +945,7 @@ // Tests that collapsing a notification while it is being moved automatically // completes both animations. // TODO(crbug.com/1292816): Test is flaky. -TEST_F(NotificationListViewTest, DISABLED_CollapseDuringMoveNoAnimation) { +TEST_P(NotificationListViewTest, DISABLED_CollapseDuringMoveNoAnimation) { auto to_be_removed_notification = AddNotification(/*pinned=*/false, /*expandable=*/true); auto to_be_collapsed_notification = @@ -969,7 +981,7 @@ // Tests that moving a notification while it is already collapsing completes // both animations. -TEST_F(NotificationListViewTest, MoveDuringCollapseNoAnimation) { +TEST_P(NotificationListViewTest, MoveDuringCollapseNoAnimation) { auto to_be_removed_notification = AddNotification(/*pinned=*/false, /*expandable=*/true); auto to_be_collapsed_notification = @@ -999,7 +1011,7 @@ to_be_collapsed_message_view_container->GetPreferredSize().height()); } -TEST_F(NotificationListViewTest, SlideNotification) { +TEST_P(NotificationListViewTest, SlideNotification) { // Show message list with four notifications. auto id0 = AddNotification(); auto id1 = AddNotification();
diff --git a/ash/system/time/calendar_event_list_view.cc b/ash/system/time/calendar_event_list_view.cc index d5c4e56..b0aefa2 100644 --- a/ash/system/time/calendar_event_list_view.cc +++ b/ash/system/time/calendar_event_list_view.cc
@@ -193,6 +193,20 @@ gradient_helper_->UpdateGradientMask(); } + // If `CalendarEventListItemView` or the join button is focused, do not scroll + // to the current or next event. Otherwise `scroll_view_` won't scroll with + // the focus change. + if (GetFocusManager() && GetFocusManager()->GetFocusedView()) { + const auto focused_view_class_name = + std::string_view(GetFocusManager()->GetFocusedView()->GetClassName()); + if (focused_view_class_name == + std::string_view(CalendarEventListItemView::kViewClassName) || + focused_view_class_name == + std::string_view(PillButton::kViewClassName)) { + return; + } + } + const std::optional<base::Time> selected_date = calendar_view_controller_->selected_date();
diff --git a/ash/system/time/calendar_event_list_view_unittest.cc b/ash/system/time/calendar_event_list_view_unittest.cc index 71501ba..ea79337 100644 --- a/ash/system/time/calendar_event_list_view_unittest.cc +++ b/ash/system/time/calendar_event_list_view_unittest.cc
@@ -335,6 +335,53 @@ } TEST_P(CalendarViewEventListViewTest, + DoNotScrollToCurrentOrNextEventWhenFocused) { + // Sets the timezone to GMT. Otherwise in other timezones events can become + // multi-day events that will be ignored when calculating index. + ash::system::ScopedTimezoneSettings timezone_settings(u"GMT"); + + // Sets today to be a day with many events, so `event_list_view()` is + // scrollable. + base::Time date; + ASSERT_TRUE(base::Time::FromString("23 Nov 2021 08:00 GMT", &date)); + CreateEventListView(date); + + SetSelectedDate(date); + + // Sets the current time to be a time that event id_9 has started. + base::Time current_time; + ASSERT_TRUE(base::Time::FromString("23 Nov 2021 02:40 GMT", ¤t_time)); + SetFakeNow(current_time); + base::subtle::ScopedTimeClockOverrides time_override( + &CalendarViewEventListViewTest::FakeTimeNow, + /*time_ticks_override=*/nullptr, /*thread_ticks_override=*/nullptr); + UpdateEventList(); + views::test::RunScheduledLayout(event_list_view()); + + // The current or next event should be the second event(event id_9). + EXPECT_EQ(1, current_or_next_event_index()); + + // The top of `scroll_view()` visible rect should be the same with the top of + // the current or next event. + auto scroll_view_visible_bounds = scroll_view()->GetVisibleBounds(); + views::View::ConvertRectToScreen(scroll_view(), &scroll_view_visible_bounds); + auto current_item_bounds = + GetHighlightView(current_or_next_event_index())->GetBoundsInScreen(); + EXPECT_EQ(scroll_view_visible_bounds.y(), current_item_bounds.y()); + + // Focus on first item in `event_list_view()`, and `scroll_view()` should + // scroll up along with the focus change. + GetHighlightView(0)->RequestFocus(); + views::test::RunScheduledLayout(event_list_view()); + + scroll_view_visible_bounds = scroll_view()->GetVisibleBounds(); + views::View::ConvertRectToScreen(scroll_view(), &scroll_view_visible_bounds); + current_item_bounds = + GetHighlightView(current_or_next_event_index())->GetBoundsInScreen(); + EXPECT_LT(scroll_view_visible_bounds.y(), current_item_bounds.y()); +} + +TEST_P(CalendarViewEventListViewTest, ScrollToCurrentOrNextEvent_WithMultiDayEvents) { // Sets the timezone to HST. The first two events become multi-day events, and // will be ignored when calculating index.
diff --git a/ash/system/time/calendar_utils.cc b/ash/system/time/calendar_utils.cc index b074240..5083dcd7 100644 --- a/ash/system/time/calendar_utils.cc +++ b/ash/system/time/calendar_utils.cc
@@ -26,8 +26,7 @@ namespace calendar_utils { bool IsForGlanceablesV2() { - return features::AreGlanceablesV2Enabled() && - features::IsGlanceablesV2CalendarViewEnabled(); + return features::IsGlanceablesV2CalendarViewEnabled(); } bool IsToday(const base::Time selected_date) {
diff --git a/ash/webui/common/mojom/sea_pen.mojom b/ash/webui/common/mojom/sea_pen.mojom index 1f118b4..176c927 100644 --- a/ash/webui/common/mojom/sea_pen.mojom +++ b/ash/webui/common/mojom/sea_pen.mojom
@@ -7,12 +7,21 @@ import "mojo/public/mojom/base/file_path.mojom"; import "url/mojom/url.mojom"; +// Generated by sea_pen_client_generator.py, do not edit. +// TODO(b/318565684): Move generated code to a separate file. + // The unique ID to identify a template. enum SeaPenTemplateId { kFlower = 0, kMineral, kLandscape, kScifi, + kArt, + kCharacters, + kTerrain, + kCurious, + kDreamscapes, + kTranslucent, }; // A variable in the template text that can be mapped to multiple option values. @@ -25,11 +34,26 @@ kLandscapeLighting, kScifiFeature, kScifiColor, + kArtFeature, + kArtMovement, + kCharactersColor, + kCharactersSubjects, + kCharactersBackground, + kTerrainFeature, + kTerrainColor, + kCuriousSubject, + kCuriousFeature, + kCuriousColor, + kDreamscapesObject, + kDreamscapesMaterial, + kDreamscapesColors, + kTranslucentItem, + kTranslucentColor, }; // The valid option values of each chip. enum SeaPenTemplateOption { - // Flower Type + // <flower_type> kFlowerTypeRose = 0, kFlowerTypeCallaLily, kFlowerTypeWindflower, @@ -40,7 +64,7 @@ kFlowerTypeRanunculus, kFlowerTypeDaisy, kFlowerTypeHydrangeas, - // Flower Color + // <flower_color> kFlowerColorPink, kFlowerColorPurple, kFlowerColorBlue, @@ -49,7 +73,7 @@ kFlowerColorYellow, kFlowerColorGreen, kFlowerColorRed, - // Mineral Name + // <mineral_name> kMineralNameAgate, kMineralNameAmethyst, kMineralNameAquamarine, @@ -71,7 +95,7 @@ kMineralNameSapphire, kMineralNameQuartz, kMineralNameTourmaline, - // Mineral Color + // <mineral_color> kMineralColorWarm, kMineralColorCool, kMineralColorNeutral, @@ -83,7 +107,7 @@ kMineralColorNeon, kMineralColorTonal, kMineralColorGray, - // Landscape Biome + // <landscape_biome> kLandscapeBiomeTaiga, kLandscapeBiomeDesert, kLandscapeBiomeRainforest, @@ -93,7 +117,7 @@ kLandscapeBiomeSwamp, kLandscapeBiomeGrassland, kLandscapeBiomeForest, - // Landscape Lighting + // <landscape_lighting> kLandscapeLightingDiffuse, kLandscapeLightingNorthernLights, kLandscapeLightingSunRays, @@ -101,7 +125,7 @@ kLandscapeLightingEarlyMorning, kLandscapeLightingBlueHour, kLandscapeLightingMidday, - // Scifi Feature + // <scifi_feature> kScifiFeatureStreet, kScifiFeatureSkyline, kScifiFeatureSwamp, @@ -115,14 +139,319 @@ kScifiFeatureSmallTown, kScifiFeatureFarm, kScifiFeatureUnderwater, - // Scifi Color + // <scifi_color> kScifiColorEarthy, kScifiColorVibrant, kScifiColorSilver, kScifiColorEerie, kScifiColorComplementary, kScifiColorNeutral, + // <art_feature> + kArtFeatureCanyon, + kArtFeatureMountain, + kArtFeatureBeach, + kArtFeatureCave, + kArtFeatureCliff, + kArtFeatureForest, + kArtFeatureGlacier, + kArtFeatureIsland, + kArtFeatureJungle, + kArtFeatureLake, + kArtFeatureMeadow, + kArtFeatureOcean, + kArtFeatureRiver, + kArtFeatureDune, + kArtFeatureSwamp, + kArtFeatureValley, + kArtFeatureWaterfall, + kArtFeatureField, + kArtFeatureCityscape, + kArtFeatureVillage, + // <art_movement> + kArtMovementAvantGarde, + kArtMovementRealism, + kArtMovementExpressionism, + kArtMovementImpressionism, + kArtMovementPostImpressionism, + kArtMovementArtNouveau, + kArtMovementBaroque, + kArtMovementBauhaus, + kArtMovementClassicism, + kArtMovementWatercolor, + kArtMovementAbstract, + kArtMovementPointillism, + kArtMovementGraphicDesign, + kArtMovementModernArt, + // <characters_color> + kCharactersColorYellow, + kCharactersColorPink, + kCharactersColorRed, + kCharactersColorBlue, + kCharactersColorIndigo, + kCharactersColorGreen, + kCharactersColorEmerald, + kCharactersColorTeal, + kCharactersColorCyan, + kCharactersColorPurple, + kCharactersColorBrown, + kCharactersColorGold, + kCharactersColorBurntOrange, + kCharactersColorRust, + kCharactersColorOlive, + kCharactersColorGray, + kCharactersColorViolet, + kCharactersColorWhite, + kCharactersColorBeige, + kCharactersColorIvory, + kCharactersColorCream, + kCharactersColorMagenta, + kCharactersColorLimeGreen, + kCharactersColorFuschia, + kCharactersColorElectricBlue, + kCharactersColorHotPink, + kCharactersColorNeonGreen, + kCharactersColorSkyBlue, + kCharactersColorElectricPurple, + kCharactersColorFireEngineRed, + kCharactersColorNeonPink, + kCharactersColorChartreuse, + kCharactersColorCobalt, + kCharactersColorLemonYellow, + kCharactersColorCoralPink, + kCharactersColorVibrantViolet, + kCharactersColorPeacockBlue, + // <characters_subjects> + kCharactersSubjectsLemons, + kCharactersSubjectsFlowers, + kCharactersSubjectsApples, + kCharactersSubjectsCherries, + kCharactersSubjectsOranges, + kCharactersSubjectsPineapples, + kCharactersSubjectsStrawberries, + kCharactersSubjectsWatermelons, + kCharactersSubjectsPotatoes, + kCharactersSubjectsSushi, + kCharactersSubjectsBaconAndEggs, + kCharactersSubjectsPizza, + kCharactersSubjectsHotDogs, + kCharactersSubjectsHamburgers, + kCharactersSubjectsRamen, + kCharactersSubjectsTacos, + kCharactersSubjectsBunnies, + kCharactersSubjectsCats, + kCharactersSubjectsDogs, + kCharactersSubjectsKoalas, + kCharactersSubjectsPandas, + kCharactersSubjectsPenguins, + kCharactersSubjectsPigs, + kCharactersSubjectsSloths, + kCharactersSubjectsPonies, + kCharactersSubjectsElephants, + kCharactersSubjectsFoxes, + kCharactersSubjectsOwls, + kCharactersSubjectsCrabs, + kCharactersSubjectsBees, + kCharactersSubjectsButterflies, + kCharactersSubjectsBicycles, + kCharactersSubjectsBoats, + kCharactersSubjectsBooks, + kCharactersSubjectsCutlery, + kCharactersSubjectsUmbrellas, + kCharactersSubjectsInstruments, + // <characters_background> + kCharactersBackgroundPurple, + kCharactersBackgroundBlue, + kCharactersBackgroundIndigo, + kCharactersBackgroundGreen, + kCharactersBackgroundEmerald, + kCharactersBackgroundTeal, + kCharactersBackgroundCyan, + kCharactersBackgroundBrown, + kCharactersBackgroundGold, + kCharactersBackgroundRed, + kCharactersBackgroundBurntOrange, + kCharactersBackgroundRust, + kCharactersBackgroundOlive, + kCharactersBackgroundPink, + kCharactersBackgroundGray, + kCharactersBackgroundYellow, + kCharactersBackgroundViolet, + kCharactersBackgroundWhite, + kCharactersBackgroundBeige, + kCharactersBackgroundIvory, + kCharactersBackgroundCream, + kCharactersBackgroundMagenta, + kCharactersBackgroundLimeGreen, + kCharactersBackgroundFuschia, + kCharactersBackgroundElectricBlue, + kCharactersBackgroundHotPink, + kCharactersBackgroundNeonGreen, + kCharactersBackgroundSkyBlue, + kCharactersBackgroundElectricPurple, + kCharactersBackgroundFireEngineRed, + kCharactersBackgroundNeonPink, + kCharactersBackgroundChartreuse, + kCharactersBackgroundCobalt, + kCharactersBackgroundLemonYellow, + kCharactersBackgroundCoralPink, + kCharactersBackgroundVibrantViolet, + kCharactersBackgroundPeacockBlue, + // <terrain_feature> + kTerrainFeatureSaltLake, + kTerrainFeatureRiver, + kTerrainFeatureNorthernLights, + kTerrainFeatureWhiteDunes, + kTerrainFeatureClayHills, + kTerrainFeatureSandyLagoons, + kTerrainFeatureMountains, + kTerrainFeatureBioluminescentBeach, + kTerrainFeatureFireflyForest, + kTerrainFeatureSandDunes, + // <terrain_color> + kTerrainColorPink, + kTerrainColorTeal, + kTerrainColorWhite, + kTerrainColorPurple, + kTerrainColorBlue, + kTerrainColorYellow, + kTerrainColorMaroonPink, + kTerrainColorBluePurple, + kTerrainColorPinkYellow, + kTerrainColorBluePink, + // <curious_subject> + kCuriousSubjectCherryBlossoms, + kCuriousSubjectJasmineFlowers, + kCuriousSubjectDaisies, + kCuriousSubjectTulips, + kCuriousSubjectCarnations, + kCuriousSubjectDaffodils, + kCuriousSubjectForgetMeNots, + kCuriousSubjectSunflowers, + kCuriousSubjectBougainvilleas, + kCuriousSubjectAirPlants, + kCuriousSubjectSucculents, + // <curious_feature> + kCuriousFeatureAlpineLake, + kCuriousFeatureGalaxy, + kCuriousFeatureSandDunes, + kCuriousFeatureSwamp, + kCuriousFeatureBeach, + kCuriousFeatureMountains, + kCuriousFeatureRiver, + kCuriousFeatureWaterfall, + // <curious_color> + kCuriousColorBlue, + kCuriousColorRed, + kCuriousColorYellow, + kCuriousColorGreen, + kCuriousColorPurple, + kCuriousColorOrange, + kCuriousColorPink, + kCuriousColorBrown, + kCuriousColorBlack, + kCuriousColorTurquoise, + kCuriousColorMagenta, + kCuriousColorLavender, + kCuriousColorMaroon, + kCuriousColorNavy, + kCuriousColorOlive, + kCuriousColorCoral, + kCuriousColorCream, + kCuriousColorIndigo, + kCuriousColorFuchsia, + // <dreamscapes_object> + kDreamscapesObjectBicycle, + kDreamscapesObjectCastle, + kDreamscapesObjectBuilding, + kDreamscapesObjectBoat, + kDreamscapesObjectLamp, + kDreamscapesObjectTable, + kDreamscapesObjectBridge, + kDreamscapesObjectLighthouse, + kDreamscapesObjectPagoda, + kDreamscapesObjectPalace, + kDreamscapesObjectTower, + kDreamscapesObjectUfo, + // <dreamscapes_material> + kDreamscapesMaterialFlowers, + kDreamscapesMaterialSilk, + kDreamscapesMaterialFelt, + kDreamscapesMaterialBurlap, + kDreamscapesMaterialChiffon, + kDreamscapesMaterialCotton, + kDreamscapesMaterialFur, + kDreamscapesMaterialLace, + kDreamscapesMaterialLinen, + kDreamscapesMaterialOrganza, + kDreamscapesMaterialTulle, + kDreamscapesMaterialWool, + kDreamscapesMaterialYarn, + kDreamscapesMaterialFleece, + kDreamscapesMaterialClay, + kDreamscapesMaterialStone, + kDreamscapesMaterialWood, + kDreamscapesMaterialAmethyst, + kDreamscapesMaterialLapisLuzuli, + kDreamscapesMaterialObsidian, + kDreamscapesMaterialOpal, + kDreamscapesMaterialSapphire, + // <dreamscapes_colors> + kDreamscapesColorsPinkPurple, + kDreamscapesColorsCoralTan, + kDreamscapesColorsCreamOrange, + kDreamscapesColorsBlueIndigo, + kDreamscapesColorsGreenTeal, + kDreamscapesColorsBurgundyMaroon, + kDreamscapesColorsYellowTeal, + // <translucent_item> + kTranslucentItemApple, + kTranslucentItemAzalea, + kTranslucentItemBegonia, + kTranslucentItemBluebell, + kTranslucentItemCherryBlossom, + kTranslucentItemChrysanthemum, + kTranslucentItemClemati, + kTranslucentItemDaffodil, + kTranslucentItemDaisy, + kTranslucentItemDandelion, + kTranslucentItemRose, + kTranslucentItemDogwood, + kTranslucentItemHibiscus, + kTranslucentItemHydrangea, + kTranslucentItemLeaf, + kTranslucentItemLily, + kTranslucentItemPansy, + kTranslucentItemPear, + kTranslucentItemPeony, + kTranslucentItemPhilodendron, + kTranslucentItemPoppy, + kTranslucentItemSunflower, + kTranslucentItemPea, + kTranslucentItemTulip, + kTranslucentItemButterfly, + kTranslucentItemDragonfly, + // <translucent_color> + kTranslucentColorPink, + kTranslucentColorBlue, + kTranslucentColorIndigo, + kTranslucentColorGreen, + kTranslucentColorEmerald, + kTranslucentColorTeal, + kTranslucentColorCyan, + kTranslucentColorPurple, + kTranslucentColorGold, + kTranslucentColorRed, + kTranslucentColorRust, + kTranslucentColorOlive, + kTranslucentColorGray, + kTranslucentColorYellow, + kTranslucentColorViolet, + kTranslucentColorIvory, + kTranslucentColorMagenta, + kTranslucentColorPeach, + kTranslucentColorBlack, }; +// End of generated code. // Encapsulates metadata for a thumbnail image, which can be displayed as an // image tile in the SeaPen search result page.
diff --git a/ash/webui/common/resources/sea_pen/constants.ts b/ash/webui/common/resources/sea_pen/constants.ts index 1672787..a12b3d1 100644 --- a/ash/webui/common/resources/sea_pen/constants.ts +++ b/ash/webui/common/resources/sea_pen/constants.ts
@@ -36,10 +36,12 @@ } export function getSeaPenTemplates(): SeaPenTemplate[] { + // Generated by sea_pen_client_generator.py, do not edit. + // TODO(b/318565684): Move generated code to a separate file. const templates = [ { id: SeaPenTemplateId.kFlower.toString(), - title: 'Airbrushed', + title: 'Airbrush', text: `A radiant <${SeaPenTemplateChip.kFlowerColor}> <${ SeaPenTemplateChip.kFlowerType}> in bloom`, preview: [{ @@ -47,51 +49,6 @@ }], options: new Map([ [ - SeaPenTemplateChip.kFlowerType, - [ - { - value: SeaPenTemplateOption.kFlowerTypeRose, - translation: 'rose', - }, - { - value: SeaPenTemplateOption.kFlowerTypeCallaLily, - translation: 'calla lily', - }, - { - value: SeaPenTemplateOption.kFlowerTypeWindflower, - translation: 'windflower', - }, - { - value: SeaPenTemplateOption.kFlowerTypeTulip, - translation: 'tulip', - }, - { - value: SeaPenTemplateOption.kFlowerTypeLilyOfTheValley, - translation: 'lily of the valley', - }, - { - value: SeaPenTemplateOption.kFlowerTypeBirdOfParadise, - translation: 'bird-of-paradise flower', - }, - { - value: SeaPenTemplateOption.kFlowerTypeOrchid, - translation: 'orchid', - }, - { - value: SeaPenTemplateOption.kFlowerTypeRanunculus, - translation: 'ranunculus', - }, - { - value: SeaPenTemplateOption.kFlowerTypeDaisy, - translation: 'daisy', - }, - { - value: SeaPenTemplateOption.kFlowerTypeHydrangeas, - translation: 'hydrangeas', - }, - ], - ], - [ SeaPenTemplateChip.kFlowerColor, [ { @@ -128,6 +85,51 @@ }, ], ], + [ + SeaPenTemplateChip.kFlowerType, + [ + { + value: SeaPenTemplateOption.kFlowerTypeRose, + translation: 'rose', + }, + { + value: SeaPenTemplateOption.kFlowerTypeCallaLily, + translation: 'calla lily', + }, + { + value: SeaPenTemplateOption.kFlowerTypeWindflower, + translation: 'windflower', + }, + { + value: SeaPenTemplateOption.kFlowerTypeTulip, + translation: 'tulip', + }, + { + value: SeaPenTemplateOption.kFlowerTypeLilyOfTheValley, + translation: 'lily of the valley', + }, + { + value: SeaPenTemplateOption.kFlowerTypeBirdOfParadise, + translation: 'bird of paradise', + }, + { + value: SeaPenTemplateOption.kFlowerTypeOrchid, + translation: 'orchid', + }, + { + value: SeaPenTemplateOption.kFlowerTypeRanunculus, + translation: 'ranunculus', + }, + { + value: SeaPenTemplateOption.kFlowerTypeDaisy, + translation: 'daisy', + }, + { + value: SeaPenTemplateOption.kFlowerTypeHydrangeas, + translation: 'hydrangeas', + }, + ], + ], ]), }, { @@ -366,7 +368,7 @@ }, { id: SeaPenTemplateId.kScifi.toString(), - title: 'Sci-fi', + title: 'Scifi', text: `Otherworldly <${SeaPenTemplateChip.kScifiFeature}> in <${ SeaPenTemplateChip.kScifiColor}> colors`, preview: [{ @@ -390,7 +392,7 @@ }, { value: SeaPenTemplateOption.kScifiFeatureTransport, - translation: 'transport hub', + translation: 'transport', }, { value: SeaPenTemplateOption.kScifiFeatureBusStop, @@ -461,7 +463,1308 @@ ], ]), }, + { + id: SeaPenTemplateId.kArt.toString(), + title: 'Classic Art', + text: `A painting of a <${SeaPenTemplateChip.kArtFeature}> in the <${ + SeaPenTemplateChip.kArtMovement}> style`, + preview: [{ + url: 'chrome://personalization/images/sea_pen_tile.svg', + }], + options: new Map([ + [ + SeaPenTemplateChip.kArtFeature, + [ + { + value: SeaPenTemplateOption.kArtFeatureCanyon, + translation: 'canyon', + }, + { + value: SeaPenTemplateOption.kArtFeatureMountain, + translation: 'mountain', + }, + { + value: SeaPenTemplateOption.kArtFeatureBeach, + translation: 'beach', + }, + { + value: SeaPenTemplateOption.kArtFeatureCave, + translation: 'cave', + }, + { + value: SeaPenTemplateOption.kArtFeatureCliff, + translation: 'cliff', + }, + { + value: SeaPenTemplateOption.kArtFeatureForest, + translation: 'forest', + }, + { + value: SeaPenTemplateOption.kArtFeatureGlacier, + translation: 'glacier', + }, + { + value: SeaPenTemplateOption.kArtFeatureIsland, + translation: 'island', + }, + { + value: SeaPenTemplateOption.kArtFeatureJungle, + translation: 'jungle', + }, + { + value: SeaPenTemplateOption.kArtFeatureLake, + translation: 'lake', + }, + { + value: SeaPenTemplateOption.kArtFeatureMeadow, + translation: 'meadow', + }, + { + value: SeaPenTemplateOption.kArtFeatureOcean, + translation: 'ocean', + }, + { + value: SeaPenTemplateOption.kArtFeatureRiver, + translation: 'river', + }, + { + value: SeaPenTemplateOption.kArtFeatureDune, + translation: 'dune', + }, + { + value: SeaPenTemplateOption.kArtFeatureSwamp, + translation: 'swamp', + }, + { + value: SeaPenTemplateOption.kArtFeatureValley, + translation: 'valley', + }, + { + value: SeaPenTemplateOption.kArtFeatureWaterfall, + translation: 'waterfall', + }, + { + value: SeaPenTemplateOption.kArtFeatureField, + translation: 'field', + }, + { + value: SeaPenTemplateOption.kArtFeatureCityscape, + translation: 'cityscape', + }, + { + value: SeaPenTemplateOption.kArtFeatureVillage, + translation: 'village', + }, + ], + ], + [ + SeaPenTemplateChip.kArtMovement, + [ + { + value: SeaPenTemplateOption.kArtMovementAvantGarde, + translation: 'avant garde', + }, + { + value: SeaPenTemplateOption.kArtMovementRealism, + translation: 'realism', + }, + { + value: SeaPenTemplateOption.kArtMovementExpressionism, + translation: 'expressionism', + }, + { + value: SeaPenTemplateOption.kArtMovementImpressionism, + translation: 'impressionism', + }, + { + value: SeaPenTemplateOption.kArtMovementPostImpressionism, + translation: 'post impressionism', + }, + { + value: SeaPenTemplateOption.kArtMovementArtNouveau, + translation: 'art nouveau', + }, + { + value: SeaPenTemplateOption.kArtMovementBaroque, + translation: 'baroque', + }, + { + value: SeaPenTemplateOption.kArtMovementBauhaus, + translation: 'bauhaus', + }, + { + value: SeaPenTemplateOption.kArtMovementClassicism, + translation: 'classicism', + }, + { + value: SeaPenTemplateOption.kArtMovementWatercolor, + translation: 'watercolor', + }, + { + value: SeaPenTemplateOption.kArtMovementAbstract, + translation: 'abstract', + }, + { + value: SeaPenTemplateOption.kArtMovementPointillism, + translation: 'pointillism', + }, + { + value: SeaPenTemplateOption.kArtMovementGraphicDesign, + translation: 'graphic design', + }, + { + value: SeaPenTemplateOption.kArtMovementModernArt, + translation: 'modern art', + }, + ], + ], + ]), + }, + { + id: SeaPenTemplateId.kCharacters.toString(), + title: 'Characters', + text: `<${SeaPenTemplateChip.kCharactersColor}> <${ + SeaPenTemplateChip.kCharactersSubjects}> on a <${ + SeaPenTemplateChip.kCharactersBackground}> background`, + preview: [{ + url: 'chrome://personalization/images/sea_pen_tile.svg', + }], + options: new Map([ + [ + SeaPenTemplateChip.kCharactersColor, + [ + { + value: SeaPenTemplateOption.kCharactersColorYellow, + translation: 'yellow', + }, + { + value: SeaPenTemplateOption.kCharactersColorPink, + translation: 'pink', + }, + { + value: SeaPenTemplateOption.kCharactersColorRed, + translation: 'red', + }, + { + value: SeaPenTemplateOption.kCharactersColorBlue, + translation: 'blue', + }, + { + value: SeaPenTemplateOption.kCharactersColorIndigo, + translation: 'indigo', + }, + { + value: SeaPenTemplateOption.kCharactersColorGreen, + translation: 'green', + }, + { + value: SeaPenTemplateOption.kCharactersColorEmerald, + translation: 'emerald', + }, + { + value: SeaPenTemplateOption.kCharactersColorTeal, + translation: 'teal', + }, + { + value: SeaPenTemplateOption.kCharactersColorCyan, + translation: 'cyan', + }, + { + value: SeaPenTemplateOption.kCharactersColorPurple, + translation: 'purple', + }, + { + value: SeaPenTemplateOption.kCharactersColorBrown, + translation: 'brown', + }, + { + value: SeaPenTemplateOption.kCharactersColorGold, + translation: 'gold', + }, + { + value: SeaPenTemplateOption.kCharactersColorBurntOrange, + translation: 'burnt orange', + }, + { + value: SeaPenTemplateOption.kCharactersColorRust, + translation: 'rust', + }, + { + value: SeaPenTemplateOption.kCharactersColorOlive, + translation: 'olive', + }, + { + value: SeaPenTemplateOption.kCharactersColorGray, + translation: 'gray', + }, + { + value: SeaPenTemplateOption.kCharactersColorViolet, + translation: 'violet', + }, + { + value: SeaPenTemplateOption.kCharactersColorWhite, + translation: 'white', + }, + { + value: SeaPenTemplateOption.kCharactersColorBeige, + translation: 'beige', + }, + { + value: SeaPenTemplateOption.kCharactersColorIvory, + translation: 'ivory', + }, + { + value: SeaPenTemplateOption.kCharactersColorCream, + translation: 'cream', + }, + { + value: SeaPenTemplateOption.kCharactersColorMagenta, + translation: 'magenta', + }, + { + value: SeaPenTemplateOption.kCharactersColorLimeGreen, + translation: 'lime green', + }, + { + value: SeaPenTemplateOption.kCharactersColorFuschia, + translation: 'fuschia', + }, + { + value: SeaPenTemplateOption.kCharactersColorElectricBlue, + translation: 'electric blue', + }, + { + value: SeaPenTemplateOption.kCharactersColorHotPink, + translation: 'hot pink', + }, + { + value: SeaPenTemplateOption.kCharactersColorNeonGreen, + translation: 'neon green', + }, + { + value: SeaPenTemplateOption.kCharactersColorSkyBlue, + translation: 'sky blue', + }, + { + value: SeaPenTemplateOption.kCharactersColorElectricPurple, + translation: 'electric purple', + }, + { + value: SeaPenTemplateOption.kCharactersColorFireEngineRed, + translation: 'fire engine red', + }, + { + value: SeaPenTemplateOption.kCharactersColorNeonPink, + translation: 'neon pink', + }, + { + value: SeaPenTemplateOption.kCharactersColorChartreuse, + translation: 'chartreuse', + }, + { + value: SeaPenTemplateOption.kCharactersColorCobalt, + translation: 'cobalt', + }, + { + value: SeaPenTemplateOption.kCharactersColorLemonYellow, + translation: 'lemon yellow', + }, + { + value: SeaPenTemplateOption.kCharactersColorCoralPink, + translation: 'coral pink', + }, + { + value: SeaPenTemplateOption.kCharactersColorVibrantViolet, + translation: 'vibrant violet', + }, + { + value: SeaPenTemplateOption.kCharactersColorPeacockBlue, + translation: 'peacock blue', + }, + ], + ], + [ + SeaPenTemplateChip.kCharactersSubjects, + [ + { + value: SeaPenTemplateOption.kCharactersSubjectsLemons, + translation: 'lemons', + }, + { + value: SeaPenTemplateOption.kCharactersSubjectsFlowers, + translation: 'flowers', + }, + { + value: SeaPenTemplateOption.kCharactersSubjectsApples, + translation: 'apples', + }, + { + value: SeaPenTemplateOption.kCharactersSubjectsCherries, + translation: 'cherries', + }, + { + value: SeaPenTemplateOption.kCharactersSubjectsOranges, + translation: 'oranges', + }, + { + value: SeaPenTemplateOption.kCharactersSubjectsPineapples, + translation: 'pineapples', + }, + { + value: SeaPenTemplateOption.kCharactersSubjectsStrawberries, + translation: 'strawberries', + }, + { + value: SeaPenTemplateOption.kCharactersSubjectsWatermelons, + translation: 'watermelons', + }, + { + value: SeaPenTemplateOption.kCharactersSubjectsPotatoes, + translation: 'potatoes', + }, + { + value: SeaPenTemplateOption.kCharactersSubjectsSushi, + translation: 'sushi', + }, + { + value: SeaPenTemplateOption.kCharactersSubjectsBaconAndEggs, + translation: 'bacon and eggs', + }, + { + value: SeaPenTemplateOption.kCharactersSubjectsPizza, + translation: 'pizza', + }, + { + value: SeaPenTemplateOption.kCharactersSubjectsHotDogs, + translation: 'hot dogs', + }, + { + value: SeaPenTemplateOption.kCharactersSubjectsHamburgers, + translation: 'hamburgers', + }, + { + value: SeaPenTemplateOption.kCharactersSubjectsRamen, + translation: 'ramen', + }, + { + value: SeaPenTemplateOption.kCharactersSubjectsTacos, + translation: 'tacos', + }, + { + value: SeaPenTemplateOption.kCharactersSubjectsBunnies, + translation: 'bunnies', + }, + { + value: SeaPenTemplateOption.kCharactersSubjectsCats, + translation: 'cats', + }, + { + value: SeaPenTemplateOption.kCharactersSubjectsDogs, + translation: 'dogs', + }, + { + value: SeaPenTemplateOption.kCharactersSubjectsKoalas, + translation: 'koalas', + }, + { + value: SeaPenTemplateOption.kCharactersSubjectsPandas, + translation: 'pandas', + }, + { + value: SeaPenTemplateOption.kCharactersSubjectsPenguins, + translation: 'penguins', + }, + { + value: SeaPenTemplateOption.kCharactersSubjectsPigs, + translation: 'pigs', + }, + { + value: SeaPenTemplateOption.kCharactersSubjectsSloths, + translation: 'sloths', + }, + { + value: SeaPenTemplateOption.kCharactersSubjectsPonies, + translation: 'ponies', + }, + { + value: SeaPenTemplateOption.kCharactersSubjectsElephants, + translation: 'elephants', + }, + { + value: SeaPenTemplateOption.kCharactersSubjectsFoxes, + translation: 'foxes', + }, + { + value: SeaPenTemplateOption.kCharactersSubjectsOwls, + translation: 'owls', + }, + { + value: SeaPenTemplateOption.kCharactersSubjectsCrabs, + translation: 'crabs', + }, + { + value: SeaPenTemplateOption.kCharactersSubjectsBees, + translation: 'bees', + }, + { + value: SeaPenTemplateOption.kCharactersSubjectsButterflies, + translation: 'butterflies', + }, + { + value: SeaPenTemplateOption.kCharactersSubjectsBicycles, + translation: 'bicycles', + }, + { + value: SeaPenTemplateOption.kCharactersSubjectsBoats, + translation: 'boats', + }, + { + value: SeaPenTemplateOption.kCharactersSubjectsBooks, + translation: 'books', + }, + { + value: SeaPenTemplateOption.kCharactersSubjectsCutlery, + translation: 'cutlery', + }, + { + value: SeaPenTemplateOption.kCharactersSubjectsUmbrellas, + translation: 'umbrellas', + }, + { + value: SeaPenTemplateOption.kCharactersSubjectsInstruments, + translation: 'instruments', + }, + ], + ], + [ + SeaPenTemplateChip.kCharactersBackground, + [ + { + value: SeaPenTemplateOption.kCharactersBackgroundPurple, + translation: 'purple', + }, + { + value: SeaPenTemplateOption.kCharactersBackgroundBlue, + translation: 'blue', + }, + { + value: SeaPenTemplateOption.kCharactersBackgroundIndigo, + translation: 'indigo', + }, + { + value: SeaPenTemplateOption.kCharactersBackgroundGreen, + translation: 'green', + }, + { + value: SeaPenTemplateOption.kCharactersBackgroundEmerald, + translation: 'emerald', + }, + { + value: SeaPenTemplateOption.kCharactersBackgroundTeal, + translation: 'teal', + }, + { + value: SeaPenTemplateOption.kCharactersBackgroundCyan, + translation: 'cyan', + }, + { + value: SeaPenTemplateOption.kCharactersBackgroundBrown, + translation: 'brown', + }, + { + value: SeaPenTemplateOption.kCharactersBackgroundGold, + translation: 'gold', + }, + { + value: SeaPenTemplateOption.kCharactersBackgroundRed, + translation: 'red', + }, + { + value: SeaPenTemplateOption.kCharactersBackgroundBurntOrange, + translation: 'burnt orange', + }, + { + value: SeaPenTemplateOption.kCharactersBackgroundRust, + translation: 'rust', + }, + { + value: SeaPenTemplateOption.kCharactersBackgroundOlive, + translation: 'olive', + }, + { + value: SeaPenTemplateOption.kCharactersBackgroundPink, + translation: 'pink', + }, + { + value: SeaPenTemplateOption.kCharactersBackgroundGray, + translation: 'gray', + }, + { + value: SeaPenTemplateOption.kCharactersBackgroundYellow, + translation: 'yellow', + }, + { + value: SeaPenTemplateOption.kCharactersBackgroundViolet, + translation: 'violet', + }, + { + value: SeaPenTemplateOption.kCharactersBackgroundWhite, + translation: 'white', + }, + { + value: SeaPenTemplateOption.kCharactersBackgroundBeige, + translation: 'beige', + }, + { + value: SeaPenTemplateOption.kCharactersBackgroundIvory, + translation: 'ivory', + }, + { + value: SeaPenTemplateOption.kCharactersBackgroundCream, + translation: 'cream', + }, + { + value: SeaPenTemplateOption.kCharactersBackgroundMagenta, + translation: 'magenta', + }, + { + value: SeaPenTemplateOption.kCharactersBackgroundLimeGreen, + translation: 'lime green', + }, + { + value: SeaPenTemplateOption.kCharactersBackgroundFuschia, + translation: 'fuschia', + }, + { + value: SeaPenTemplateOption.kCharactersBackgroundElectricBlue, + translation: 'electric blue', + }, + { + value: SeaPenTemplateOption.kCharactersBackgroundHotPink, + translation: 'hot pink', + }, + { + value: SeaPenTemplateOption.kCharactersBackgroundNeonGreen, + translation: 'neon green', + }, + { + value: SeaPenTemplateOption.kCharactersBackgroundSkyBlue, + translation: 'sky blue', + }, + { + value: SeaPenTemplateOption.kCharactersBackgroundElectricPurple, + translation: 'electric purple', + }, + { + value: SeaPenTemplateOption.kCharactersBackgroundFireEngineRed, + translation: 'fire engine red', + }, + { + value: SeaPenTemplateOption.kCharactersBackgroundNeonPink, + translation: 'neon pink', + }, + { + value: SeaPenTemplateOption.kCharactersBackgroundChartreuse, + translation: 'chartreuse', + }, + { + value: SeaPenTemplateOption.kCharactersBackgroundCobalt, + translation: 'cobalt', + }, + { + value: SeaPenTemplateOption.kCharactersBackgroundLemonYellow, + translation: 'lemon yellow', + }, + { + value: SeaPenTemplateOption.kCharactersBackgroundCoralPink, + translation: 'coral pink', + }, + { + value: SeaPenTemplateOption.kCharactersBackgroundVibrantViolet, + translation: 'vibrant violet', + }, + { + value: SeaPenTemplateOption.kCharactersBackgroundPeacockBlue, + translation: 'peacock blue', + }, + ], + ], + ]), + }, + { + id: SeaPenTemplateId.kTerrain.toString(), + title: 'Terrain', + text: `<${SeaPenTemplateChip.kTerrainFeature}> in shades of <${ + SeaPenTemplateChip.kTerrainColor}>`, + preview: [{ + url: 'chrome://personalization/images/sea_pen_tile.svg', + }], + options: new Map([ + [ + SeaPenTemplateChip.kTerrainFeature, + [ + { + value: SeaPenTemplateOption.kTerrainFeatureSaltLake, + translation: 'salt lake', + }, + { + value: SeaPenTemplateOption.kTerrainFeatureRiver, + translation: 'river', + }, + { + value: SeaPenTemplateOption.kTerrainFeatureNorthernLights, + translation: 'northern lights', + }, + { + value: SeaPenTemplateOption.kTerrainFeatureWhiteDunes, + translation: 'white dunes', + }, + { + value: SeaPenTemplateOption.kTerrainFeatureClayHills, + translation: 'clay hills', + }, + { + value: SeaPenTemplateOption.kTerrainFeatureSandyLagoons, + translation: 'sandy lagoons', + }, + { + value: SeaPenTemplateOption.kTerrainFeatureMountains, + translation: 'mountains', + }, + { + value: SeaPenTemplateOption.kTerrainFeatureBioluminescentBeach, + translation: 'bioluminescent beach', + }, + { + value: SeaPenTemplateOption.kTerrainFeatureFireflyForest, + translation: 'firefly forest', + }, + { + value: SeaPenTemplateOption.kTerrainFeatureSandDunes, + translation: 'sand dunes', + }, + ], + ], + [ + SeaPenTemplateChip.kTerrainColor, + [ + { + value: SeaPenTemplateOption.kTerrainColorPink, + translation: 'pink', + }, + { + value: SeaPenTemplateOption.kTerrainColorTeal, + translation: 'teal', + }, + { + value: SeaPenTemplateOption.kTerrainColorWhite, + translation: 'white', + }, + { + value: SeaPenTemplateOption.kTerrainColorPurple, + translation: 'purple', + }, + { + value: SeaPenTemplateOption.kTerrainColorBlue, + translation: 'blue', + }, + { + value: SeaPenTemplateOption.kTerrainColorYellow, + translation: 'yellow', + }, + { + value: SeaPenTemplateOption.kTerrainColorMaroonPink, + translation: 'maroon pink', + }, + { + value: SeaPenTemplateOption.kTerrainColorBluePurple, + translation: 'blue purple', + }, + { + value: SeaPenTemplateOption.kTerrainColorPinkYellow, + translation: 'pink yellow', + }, + { + value: SeaPenTemplateOption.kTerrainColorBluePink, + translation: 'blue pink', + }, + ], + ], + ]), + }, + { + id: SeaPenTemplateId.kCurious.toString(), + title: 'Curious World', + text: `A <${SeaPenTemplateChip.kCuriousColor}> <${ + SeaPenTemplateChip.kCuriousFeature}> with <${ + SeaPenTemplateChip.kCuriousSubject}>`, + preview: [{ + url: 'chrome://personalization/images/sea_pen_tile.svg', + }], + options: new Map([ + [ + SeaPenTemplateChip.kCuriousColor, + [ + { + value: SeaPenTemplateOption.kCuriousColorBlue, + translation: 'blue', + }, + { + value: SeaPenTemplateOption.kCuriousColorRed, + translation: 'red', + }, + { + value: SeaPenTemplateOption.kCuriousColorYellow, + translation: 'yellow', + }, + { + value: SeaPenTemplateOption.kCuriousColorGreen, + translation: 'green', + }, + { + value: SeaPenTemplateOption.kCuriousColorPurple, + translation: 'purple', + }, + { + value: SeaPenTemplateOption.kCuriousColorOrange, + translation: 'orange', + }, + { + value: SeaPenTemplateOption.kCuriousColorPink, + translation: 'pink', + }, + { + value: SeaPenTemplateOption.kCuriousColorBrown, + translation: 'brown', + }, + { + value: SeaPenTemplateOption.kCuriousColorBlack, + translation: 'black', + }, + { + value: SeaPenTemplateOption.kCuriousColorTurquoise, + translation: 'turquoise', + }, + { + value: SeaPenTemplateOption.kCuriousColorMagenta, + translation: 'magenta', + }, + { + value: SeaPenTemplateOption.kCuriousColorLavender, + translation: 'lavender', + }, + { + value: SeaPenTemplateOption.kCuriousColorMaroon, + translation: 'maroon', + }, + { + value: SeaPenTemplateOption.kCuriousColorNavy, + translation: 'navy', + }, + { + value: SeaPenTemplateOption.kCuriousColorOlive, + translation: 'olive', + }, + { + value: SeaPenTemplateOption.kCuriousColorCoral, + translation: 'coral', + }, + { + value: SeaPenTemplateOption.kCuriousColorCream, + translation: 'cream', + }, + { + value: SeaPenTemplateOption.kCuriousColorIndigo, + translation: 'indigo', + }, + { + value: SeaPenTemplateOption.kCuriousColorFuchsia, + translation: 'fuchsia', + }, + ], + ], + [ + SeaPenTemplateChip.kCuriousFeature, + [ + { + value: SeaPenTemplateOption.kCuriousFeatureAlpineLake, + translation: 'alpine lake', + }, + { + value: SeaPenTemplateOption.kCuriousFeatureGalaxy, + translation: 'galaxy', + }, + { + value: SeaPenTemplateOption.kCuriousFeatureSandDunes, + translation: 'sand dunes', + }, + { + value: SeaPenTemplateOption.kCuriousFeatureSwamp, + translation: 'swamp', + }, + { + value: SeaPenTemplateOption.kCuriousFeatureBeach, + translation: 'beach', + }, + { + value: SeaPenTemplateOption.kCuriousFeatureMountains, + translation: 'mountains', + }, + { + value: SeaPenTemplateOption.kCuriousFeatureRiver, + translation: 'river', + }, + { + value: SeaPenTemplateOption.kCuriousFeatureWaterfall, + translation: 'waterfall', + }, + ], + ], + [ + SeaPenTemplateChip.kCuriousSubject, + [ + { + value: SeaPenTemplateOption.kCuriousSubjectCherryBlossoms, + translation: 'cherry blossoms', + }, + { + value: SeaPenTemplateOption.kCuriousSubjectJasmineFlowers, + translation: 'jasmine flowers', + }, + { + value: SeaPenTemplateOption.kCuriousSubjectDaisies, + translation: 'daisies', + }, + { + value: SeaPenTemplateOption.kCuriousSubjectTulips, + translation: 'tulips', + }, + { + value: SeaPenTemplateOption.kCuriousSubjectCarnations, + translation: 'carnations', + }, + { + value: SeaPenTemplateOption.kCuriousSubjectDaffodils, + translation: 'daffodils', + }, + { + value: SeaPenTemplateOption.kCuriousSubjectForgetMeNots, + translation: 'forget me nots', + }, + { + value: SeaPenTemplateOption.kCuriousSubjectSunflowers, + translation: 'sunflowers', + }, + { + value: SeaPenTemplateOption.kCuriousSubjectBougainvilleas, + translation: 'bougainvilleas', + }, + { + value: SeaPenTemplateOption.kCuriousSubjectAirPlants, + translation: 'air plants', + }, + { + value: SeaPenTemplateOption.kCuriousSubjectSucculents, + translation: 'succulents', + }, + ], + ], + ]), + }, + { + id: SeaPenTemplateId.kDreamscapes.toString(), + title: 'Dreamscapes', + text: `A surreal <${SeaPenTemplateChip.kDreamscapesObject}> made of <${ + SeaPenTemplateChip.kDreamscapesMaterial}> in <${ + SeaPenTemplateChip.kDreamscapesColors}>`, + preview: [{ + url: 'chrome://personalization/images/sea_pen_tile.svg', + }], + options: new Map([ + [ + SeaPenTemplateChip.kDreamscapesObject, + [ + { + value: SeaPenTemplateOption.kDreamscapesObjectBicycle, + translation: 'bicycle', + }, + { + value: SeaPenTemplateOption.kDreamscapesObjectCastle, + translation: 'castle', + }, + { + value: SeaPenTemplateOption.kDreamscapesObjectBuilding, + translation: 'building', + }, + { + value: SeaPenTemplateOption.kDreamscapesObjectBoat, + translation: 'boat', + }, + { + value: SeaPenTemplateOption.kDreamscapesObjectLamp, + translation: 'lamp', + }, + { + value: SeaPenTemplateOption.kDreamscapesObjectTable, + translation: 'table', + }, + { + value: SeaPenTemplateOption.kDreamscapesObjectBridge, + translation: 'bridge', + }, + { + value: SeaPenTemplateOption.kDreamscapesObjectLighthouse, + translation: 'lighthouse', + }, + { + value: SeaPenTemplateOption.kDreamscapesObjectPagoda, + translation: 'pagoda', + }, + { + value: SeaPenTemplateOption.kDreamscapesObjectPalace, + translation: 'palace', + }, + { + value: SeaPenTemplateOption.kDreamscapesObjectTower, + translation: 'tower', + }, + { + value: SeaPenTemplateOption.kDreamscapesObjectUfo, + translation: 'UFO', + }, + ], + ], + [ + SeaPenTemplateChip.kDreamscapesMaterial, + [ + { + value: SeaPenTemplateOption.kDreamscapesMaterialFlowers, + translation: 'flowers', + }, + { + value: SeaPenTemplateOption.kDreamscapesMaterialSilk, + translation: 'silk', + }, + { + value: SeaPenTemplateOption.kDreamscapesMaterialFelt, + translation: 'felt', + }, + { + value: SeaPenTemplateOption.kDreamscapesMaterialBurlap, + translation: 'burlap', + }, + { + value: SeaPenTemplateOption.kDreamscapesMaterialChiffon, + translation: 'chiffon', + }, + { + value: SeaPenTemplateOption.kDreamscapesMaterialCotton, + translation: 'cotton', + }, + { + value: SeaPenTemplateOption.kDreamscapesMaterialFur, + translation: 'fur', + }, + { + value: SeaPenTemplateOption.kDreamscapesMaterialLace, + translation: 'lace', + }, + { + value: SeaPenTemplateOption.kDreamscapesMaterialLinen, + translation: 'linen', + }, + { + value: SeaPenTemplateOption.kDreamscapesMaterialOrganza, + translation: 'organza', + }, + { + value: SeaPenTemplateOption.kDreamscapesMaterialTulle, + translation: 'tulle', + }, + { + value: SeaPenTemplateOption.kDreamscapesMaterialWool, + translation: 'wool', + }, + { + value: SeaPenTemplateOption.kDreamscapesMaterialYarn, + translation: 'yarn', + }, + { + value: SeaPenTemplateOption.kDreamscapesMaterialFleece, + translation: 'fleece', + }, + { + value: SeaPenTemplateOption.kDreamscapesMaterialClay, + translation: 'clay', + }, + { + value: SeaPenTemplateOption.kDreamscapesMaterialStone, + translation: 'stone', + }, + { + value: SeaPenTemplateOption.kDreamscapesMaterialWood, + translation: 'wood', + }, + { + value: SeaPenTemplateOption.kDreamscapesMaterialAmethyst, + translation: 'amethyst', + }, + { + value: SeaPenTemplateOption.kDreamscapesMaterialLapisLuzuli, + translation: 'lapis luzuli', + }, + { + value: SeaPenTemplateOption.kDreamscapesMaterialObsidian, + translation: 'obsidian', + }, + { + value: SeaPenTemplateOption.kDreamscapesMaterialOpal, + translation: 'opal', + }, + { + value: SeaPenTemplateOption.kDreamscapesMaterialSapphire, + translation: 'sapphire', + }, + ], + ], + [ + SeaPenTemplateChip.kDreamscapesColors, + [ + { + value: SeaPenTemplateOption.kDreamscapesColorsPinkPurple, + translation: 'pink purple', + }, + { + value: SeaPenTemplateOption.kDreamscapesColorsCoralTan, + translation: 'coral tan', + }, + { + value: SeaPenTemplateOption.kDreamscapesColorsCreamOrange, + translation: 'cream orange', + }, + { + value: SeaPenTemplateOption.kDreamscapesColorsBlueIndigo, + translation: 'blue indigo', + }, + { + value: SeaPenTemplateOption.kDreamscapesColorsGreenTeal, + translation: 'green teal', + }, + { + value: SeaPenTemplateOption.kDreamscapesColorsBurgundyMaroon, + translation: 'burgundy maroon', + }, + { + value: SeaPenTemplateOption.kDreamscapesColorsYellowTeal, + translation: 'yellow teal', + }, + ], + ], + ]), + }, + { + id: SeaPenTemplateId.kTranslucent.toString(), + title: 'Translucent', + text: `Translucent <${SeaPenTemplateChip.kTranslucentItem}> in <${ + SeaPenTemplateChip.kTranslucentColor}>`, + preview: [{ + url: 'chrome://personalization/images/sea_pen_tile.svg', + }], + options: new Map([ + [ + SeaPenTemplateChip.kTranslucentItem, + [ + { + value: SeaPenTemplateOption.kTranslucentItemApple, + translation: 'apple', + }, + { + value: SeaPenTemplateOption.kTranslucentItemAzalea, + translation: 'azalea', + }, + { + value: SeaPenTemplateOption.kTranslucentItemBegonia, + translation: 'begonia', + }, + { + value: SeaPenTemplateOption.kTranslucentItemBluebell, + translation: 'bluebell', + }, + { + value: SeaPenTemplateOption.kTranslucentItemCherryBlossom, + translation: 'cherry blossom', + }, + { + value: SeaPenTemplateOption.kTranslucentItemChrysanthemum, + translation: 'chrysanthemum', + }, + { + value: SeaPenTemplateOption.kTranslucentItemClemati, + translation: 'clemati', + }, + { + value: SeaPenTemplateOption.kTranslucentItemDaffodil, + translation: 'daffodil', + }, + { + value: SeaPenTemplateOption.kTranslucentItemDaisy, + translation: 'daisy', + }, + { + value: SeaPenTemplateOption.kTranslucentItemDandelion, + translation: 'dandelion', + }, + { + value: SeaPenTemplateOption.kTranslucentItemRose, + translation: 'rose', + }, + { + value: SeaPenTemplateOption.kTranslucentItemDogwood, + translation: 'dogwood', + }, + { + value: SeaPenTemplateOption.kTranslucentItemHibiscus, + translation: 'hibiscus', + }, + { + value: SeaPenTemplateOption.kTranslucentItemHydrangea, + translation: 'hydrangea', + }, + { + value: SeaPenTemplateOption.kTranslucentItemLeaf, + translation: 'leaf', + }, + { + value: SeaPenTemplateOption.kTranslucentItemLily, + translation: 'lily', + }, + { + value: SeaPenTemplateOption.kTranslucentItemPansy, + translation: 'pansy', + }, + { + value: SeaPenTemplateOption.kTranslucentItemPear, + translation: 'pear', + }, + { + value: SeaPenTemplateOption.kTranslucentItemPeony, + translation: 'peony', + }, + { + value: SeaPenTemplateOption.kTranslucentItemPhilodendron, + translation: 'philodendron', + }, + { + value: SeaPenTemplateOption.kTranslucentItemPoppy, + translation: 'poppy', + }, + { + value: SeaPenTemplateOption.kTranslucentItemSunflower, + translation: 'sunflower', + }, + { + value: SeaPenTemplateOption.kTranslucentItemPea, + translation: 'pea', + }, + { + value: SeaPenTemplateOption.kTranslucentItemTulip, + translation: 'tulip', + }, + { + value: SeaPenTemplateOption.kTranslucentItemButterfly, + translation: 'butterfly', + }, + { + value: SeaPenTemplateOption.kTranslucentItemDragonfly, + translation: 'dragonfly', + }, + ], + ], + [ + SeaPenTemplateChip.kTranslucentColor, + [ + { + value: SeaPenTemplateOption.kTranslucentColorPink, + translation: 'pink', + }, + { + value: SeaPenTemplateOption.kTranslucentColorBlue, + translation: 'blue', + }, + { + value: SeaPenTemplateOption.kTranslucentColorIndigo, + translation: 'indigo', + }, + { + value: SeaPenTemplateOption.kTranslucentColorGreen, + translation: 'green', + }, + { + value: SeaPenTemplateOption.kTranslucentColorEmerald, + translation: 'emerald', + }, + { + value: SeaPenTemplateOption.kTranslucentColorTeal, + translation: 'teal', + }, + { + value: SeaPenTemplateOption.kTranslucentColorCyan, + translation: 'cyan', + }, + { + value: SeaPenTemplateOption.kTranslucentColorPurple, + translation: 'purple', + }, + { + value: SeaPenTemplateOption.kTranslucentColorGold, + translation: 'gold', + }, + { + value: SeaPenTemplateOption.kTranslucentColorRed, + translation: 'red', + }, + { + value: SeaPenTemplateOption.kTranslucentColorRust, + translation: 'rust', + }, + { + value: SeaPenTemplateOption.kTranslucentColorOlive, + translation: 'olive', + }, + { + value: SeaPenTemplateOption.kTranslucentColorGray, + translation: 'gray', + }, + { + value: SeaPenTemplateOption.kTranslucentColorYellow, + translation: 'yellow', + }, + { + value: SeaPenTemplateOption.kTranslucentColorViolet, + translation: 'violet', + }, + { + value: SeaPenTemplateOption.kTranslucentColorIvory, + translation: 'ivory', + }, + { + value: SeaPenTemplateOption.kTranslucentColorMagenta, + translation: 'magenta', + }, + { + value: SeaPenTemplateOption.kTranslucentColorPeach, + translation: 'peach', + }, + { + value: SeaPenTemplateOption.kTranslucentColorBlack, + translation: 'black', + }, + ], + ], + ]), + }, ]; + // End of generated code. if (isSeaPenTextInputEnabled()) { templates.push({ preview: [{
diff --git a/ash/webui/shimless_rma/resources/BUILD.gn b/ash/webui/shimless_rma/resources/BUILD.gn index 0b99c75..30e4a20 100644 --- a/ash/webui/shimless_rma/resources/BUILD.gn +++ b/ash/webui/shimless_rma/resources/BUILD.gn
@@ -48,7 +48,7 @@ "onboarding_select_components_page.ts", "onboarding_update_page.ts", "onboarding_wait_for_manual_wp_disable_page.ts", - "onboarding_wp_disable_complete_page.js", + "onboarding_wp_disable_complete_page.ts", "reboot_page.js", "reimaging_calibration_failed_page.js", "reimaging_calibration_run_page.js",
diff --git a/ash/webui/shimless_rma/resources/onboarding_wp_disable_complete_page.js b/ash/webui/shimless_rma/resources/onboarding_wp_disable_complete_page.ts similarity index 66% rename from ash/webui/shimless_rma/resources/onboarding_wp_disable_complete_page.js rename to ash/webui/shimless_rma/resources/onboarding_wp_disable_complete_page.ts index 982abd8..fcbaee1 100644 --- a/ash/webui/shimless_rma/resources/onboarding_wp_disable_complete_page.js +++ b/ash/webui/shimless_rma/resources/onboarding_wp_disable_complete_page.ts
@@ -5,16 +5,19 @@ import './shimless_rma_shared.css.js'; import './base_page.js'; -import {I18nBehavior, I18nBehaviorInterface} from 'chrome://resources/ash/common/i18n_behavior.js'; -import {mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js'; import {getShimlessRmaService} from './mojo_interface_provider.js'; import {getTemplate} from './onboarding_wp_disable_complete_page.html.js'; import {ShimlessRmaServiceInterface, StateResult, WriteProtectDisableCompleteAction} from './shimless_rma.mojom-webui.js'; import {enableNextButton, focusPageTitle} from './shimless_rma_util.js'; -/** @type {!Object<WriteProtectDisableCompleteAction, string>} */ -const disableActionTextKeys = { +type DisableActionTextKeys = { + [key in WriteProtectDisableCompleteAction]: string; +}; + +const disableActionTextKeys: DisableActionTextKeys = { [WriteProtectDisableCompleteAction.kSkippedAssembleDevice]: 'wpDisableReassembleNowText', [WriteProtectDisableCompleteAction.kCompleteAssembleDevice]: @@ -29,19 +32,12 @@ * disable was successful, and what steps must be taken next. */ -/** - * @constructor - * @extends {PolymerElement} - * @implements {I18nBehaviorInterface} - */ -const OnboardingWpDisableCompletePageBase = - mixinBehaviors([I18nBehavior], PolymerElement); +const OnboardingWpDisableCompletePageBase = I18nMixin(PolymerElement); -/** @polymer */ export class OnboardingWpDisableCompletePage extends OnboardingWpDisableCompletePageBase { static get is() { - return 'onboarding-wp-disable-complete-page'; + return 'onboarding-wp-disable-complete-page' as const; } static get template() { @@ -50,7 +46,6 @@ static get properties() { return { - /** @protected */ actionString: { type: String, computed: 'getActionString(action)', @@ -58,8 +53,11 @@ }; } - /** @override */ - ready() { + shimlessRmaService: ShimlessRmaServiceInterface = getShimlessRmaService(); + protected actionString: string; + private action: WriteProtectDisableCompleteAction = WriteProtectDisableCompleteAction.kUnknown; + + override ready() { super.ready(); enableNextButton(this); @@ -68,40 +66,27 @@ constructor() { super(); - /** @private {ShimlessRmaServiceInterface} */ - this.shimlessRmaService = getShimlessRmaService(); - /** @private {WriteProtectDisableCompleteAction} */ - this.action = WriteProtectDisableCompleteAction.kUnknown; this.shimlessRmaService.getWriteProtectDisableCompleteAction().then( - (res) => { + (res: {action: WriteProtectDisableCompleteAction }) => { if (res) { this.action = res.action; } }); } - /** - * @return {string} - * @protected - */ - getActionString() { + protected getActionString(): string { return (this.action === WriteProtectDisableCompleteAction.kUnknown || this.action === WriteProtectDisableCompleteAction.kCompleteNoOp) ? '' : this.i18n(disableActionTextKeys[this.action]); } - /** @return {!Promise<!{stateResult: !StateResult}>} */ - onNextButtonClick() { + onNextButtonClick(): Promise<{stateResult: StateResult}> { return this.shimlessRmaService.confirmManualWpDisableComplete(); } - /** - * @return {string} - * @protected - */ - getVerificationIcon() { + protected getVerificationIcon(): string { return (this.action === WriteProtectDisableCompleteAction.kUnknown || this.action === WriteProtectDisableCompleteAction.kCompleteNoOp) ? '' : @@ -109,5 +94,11 @@ } } +declare global { + interface HTMLElementTagNameMap { + [OnboardingWpDisableCompletePage.is]: OnboardingWpDisableCompletePage; + } +} + customElements.define( OnboardingWpDisableCompletePage.is, OnboardingWpDisableCompletePage);
diff --git a/ash/webui/shortcut_customization_ui/resources/js/shortcut_customization_app.ts b/ash/webui/shortcut_customization_ui/resources/js/shortcut_customization_app.ts index 4feed4d..aac0b2c 100644 --- a/ash/webui/shortcut_customization_ui/resources/js/shortcut_customization_app.ts +++ b/ash/webui/shortcut_customization_ui/resources/js/shortcut_customization_app.ts
@@ -18,6 +18,7 @@ import {NavigationViewPanelElement} from 'chrome://resources/ash/common/navigation_view_panel.js'; import {strictQuery} from 'chrome://resources/ash/common/typescript_utils/strict_query.js'; import {ColorChangeUpdater} from 'chrome://resources/cr_components/color_change_listener/colors_css_updater.js'; +import {CrDialogElement} from 'chrome://resources/cr_elements/cr_dialog/cr_dialog.js'; import {CrToolbarSearchFieldElement} from 'chrome://resources/cr_elements/cr_toolbar/cr_toolbar_search_field.js'; import {FindShortcutMixin} from 'chrome://resources/cr_elements/find_shortcut_mixin.js'; import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js'; @@ -319,7 +320,7 @@ } protected onCancelRestoreButtonClicked(): void { - this.closeRestoreAllDialog(); + strictQuery('#restoreDialog', this.shadowRoot, CrDialogElement).close(); } protected onConfirmRestoreButtonClicked(): void { @@ -327,7 +328,7 @@ // TODO(jimmyxgong): Explore error state with restore all. if (result.result === AcceleratorConfigResult.kSuccess) { this.shortcutProvider.recordUserAction(UserAction.kResetAll); - this.closeRestoreAllDialog(); + strictQuery('#restoreDialog', this.shadowRoot, CrDialogElement).close(); } }); }
diff --git a/ash/wm/desks/desk_button_base.cc b/ash/wm/desks/desk_button_base.cc index 75a4b21..57cf2d8d 100644 --- a/ash/wm/desks/desk_button_base.cc +++ b/ash/wm/desks/desk_button_base.cc
@@ -5,8 +5,8 @@ #include "ash/wm/desks/desk_button_base.h" #include "ash/wm/desks/desk_bar_view_base.h" -#include "ash/wm/overview/overview_constants.h" #include "ash/wm/overview/overview_utils.h" +#include "ash/wm/wm_constants.h" #include "ui/base/metadata/metadata_impl_macros.h" #include "ui/compositor/layer.h" #include "ui/views/border.h" @@ -49,7 +49,7 @@ SetBorder(views::CreateEmptyBorder(gfx::Insets())); views::InstallRoundRectHighlightPathGenerator( - this, gfx::Insets(kFocusRingHaloInset), kFocusRingRadius); + this, gfx::Insets(kWindowMiniViewFocusRingHaloInset), kFocusRingRadius); views::FocusRing* focus_ring = views::FocusRing::Get(this); focus_ring->SetOutsetFocusRingDisabled(true); focus_ring->SetColorId(ui::kColorAshFocusRing);
diff --git a/ash/wm/desks/desk_icon_button.cc b/ash/wm/desks/desk_icon_button.cc index c959d2b..f9f5c87 100644 --- a/ash/wm/desks/desk_icon_button.cc +++ b/ash/wm/desks/desk_icon_button.cc
@@ -11,7 +11,7 @@ #include "ash/wm/desks/desk_mini_view.h" #include "ash/wm/desks/desk_preview_view.h" #include "ash/wm/desks/desks_controller.h" -#include "ash/wm/overview/overview_constants.h" +#include "ash/wm/wm_constants.h" #include "base/check_op.h" #include "ui/base/metadata/metadata_impl_macros.h" #include "ui/chromeos/styles/cros_tokens_color_mappings.h" @@ -68,7 +68,7 @@ background_color_id_(background_color_id) { SetEnabled(initially_enabled); views::InstallRoundRectHighlightPathGenerator( - this, gfx::Insets(kFocusRingHaloInset), + this, gfx::Insets(kWindowMiniViewFocusRingHaloInset), GetFocusRingRadiusForState(state_)); if (bar_view_->type() == DeskBarViewBase::Type::kOverview) { auto* focus_ring = views::FocusRing::Get(this); @@ -114,7 +114,7 @@ SetBackground(views::CreateRoundedRectBackground( background()->get_color(), GetCornerRadiusOnState(state_))); views::InstallRoundRectHighlightPathGenerator( - this, gfx::Insets(kFocusRingHaloInset), + this, gfx::Insets(kWindowMiniViewFocusRingHaloInset), GetFocusRingRadiusForState(state_)); }
diff --git a/ash/wm/desks/desk_mini_view.cc b/ash/wm/desks/desk_mini_view.cc index c8b1ae2..9d64743 100644 --- a/ash/wm/desks/desk_mini_view.cc +++ b/ash/wm/desks/desk_mini_view.cc
@@ -28,9 +28,9 @@ #include "ash/wm/desks/desks_controller.h" #include "ash/wm/desks/desks_restore_util.h" #include "ash/wm/float/float_controller.h" -#include "ash/wm/overview/overview_constants.h" #include "ash/wm/overview/overview_grid.h" #include "ash/wm/overview/overview_utils.h" +#include "ash/wm/wm_constants.h" #include "base/functional/bind.h" #include "base/i18n/rtl.h" #include "base/metrics/histogram_functions.h" @@ -142,7 +142,8 @@ views::FocusRing* preview_focus_ring = views::FocusRing::Get(desk_preview_); preview_focus_ring->SetOutsetFocusRingDisabled(true); views::InstallRoundRectHighlightPathGenerator( - desk_preview_, gfx::Insets(kFocusRingHaloInset), kPreviewFocusRingRadius); + desk_preview_, gfx::Insets(kWindowMiniViewFocusRingHaloInset), + kPreviewFocusRingRadius); preview_focus_ring->SetHasFocusPredicate(base::BindRepeating( [](const DeskMiniView* mini_view, const views::View* view) { @@ -186,6 +187,19 @@ }, base::Unretained(this))); + // Only show profile avatar button when there is more than one profile logged + // in. + auto* desk_profile_delegate = Shell::Get()->GetDeskProfilesDelegate(); + if (chromeos::features::IsDeskProfilesEnabled() && + (g_force_show_desk_profiles_button || + (desk_profile_delegate && + desk_profile_delegate->GetProfilesSnapshot().size() > 1))) { + desk_profile_button_ = AddChildView(std::make_unique<DeskProfilesButton>( + base::BindRepeating(&DeskMiniView::OnDeskProfilesButtonPressed, + base::Unretained(this)), + desk)); + } + desk_action_view_ = AddChildView(std::make_unique<DeskActionView>( desks_controller->GetCombineDesksTargetName(desk_), /*combine_desks_callback=*/ @@ -240,18 +254,6 @@ desk_shortcut_view_->SetVisible(false); desk_shortcut_view_->SetCanProcessEventsWithinSubtree(false); } - // Only show profile avatar button when there is more than one profile logged - // in. - auto* desk_profile_delegate = Shell::Get()->GetDeskProfilesDelegate(); - if (chromeos::features::IsDeskProfilesEnabled() && - (g_force_show_desk_profiles_button || - (desk_profile_delegate && - desk_profile_delegate->GetProfilesSnapshot().size() > 1))) { - desk_profile_button_ = AddChildView(std::make_unique<DeskProfilesButton>( - base::BindRepeating(&DeskMiniView::OnDeskProfilesButtonPressed, - base::Unretained(this)), - desk)); - } UpdateDeskButtonVisibility(); } @@ -283,6 +285,8 @@ auto* controller = DesksController::Get(); + bool desk_profile_button_is_focused = + desk_profile_button_ && desk_profile_button_->HasFocus(); // Don't show desk buttons when hovered while the dragged window is on // the desk bar view. // For switch access, setting desk buttons to visible allows users to @@ -293,7 +297,8 @@ (IsMouseHovered() || force_show_desk_buttons_ || Shell::Get()->accessibility_controller()->IsSwitchAccessRunning() || (owner_bar_->type() == DeskBarViewBase::Type::kDeskButton && - (desk_preview_->HasFocus() || desk_action_view_->ChildHasFocus()))); + (desk_preview_->HasFocus() || desk_profile_button_is_focused || + desk_action_view_->ChildHasFocus()))); // Only show the combine desks button if there are app windows in the desk, // or if the desk is active and there are windows that should be visible on
diff --git a/ash/wm/desks/desk_profiles_view.cc b/ash/wm/desks/desk_profiles_view.cc index a9aa9f87..0139003 100644 --- a/ash/wm/desks/desk_profiles_view.cc +++ b/ash/wm/desks/desk_profiles_view.cc
@@ -26,6 +26,7 @@ #include "ui/views/accessibility/view_accessibility.h" #include "ui/views/context_menu_controller.h" #include "ui/views/controls/button/image_button.h" +#include "ui/views/controls/highlight_path_generator.h" #include "ui/views/controls/menu/menu_item_view.h" #include "ui/views/controls/menu/menu_model_adapter.h" #include "ui/views/layout/box_layout_view.h" @@ -233,11 +234,20 @@ : desk_(desk) { desk_->AddObserver(this); SetFocusBehavior(views::View::FocusBehavior::ALWAYS); + SetPreferredSize(kIconButtonSize); SetPaintToLayer(); layer()->SetFillsBoundsOpaquely(false); icon_ = AddChildView(std::make_unique<views::ImageView>()); icon_->SetSize(kIconButtonSize); icon_->SetImageSize(kIconButtonSize); + auto* focus_ring = views::FocusRing::Get(this); + focus_ring->SetOutsetFocusRingDisabled(true); + focus_ring->SetColorId(cros_tokens::kCrosSysFocusRing); + focus_ring->SetPathGenerator( + std::make_unique<views::CircleHighlightPathGenerator>( + -gfx::Insets(focus_ring->GetHaloThickness() / 2))); + views::InstallCircleHighlightPathGenerator(this); + UpdateIcon(); icon_->SetPaintToLayer(); icon_->layer()->SetFillsBoundsOpaquely(false); @@ -269,6 +279,7 @@ desk_->lacros_profile_id())) { icon_image_ = summary->icon; icon_->SetImage(icon_image_); + icon_->SetTooltipText(base::UTF8ToUTF16(summary->name)); } }
diff --git a/ash/wm/desks/templates/saved_desk_item_view.cc b/ash/wm/desks/templates/saved_desk_item_view.cc index d9c3f53..03677456 100644 --- a/ash/wm/desks/templates/saved_desk_item_view.cc +++ b/ash/wm/desks/templates/saved_desk_item_view.cc
@@ -24,12 +24,12 @@ #include "ash/wm/desks/templates/saved_desk_name_view.h" #include "ash/wm/desks/templates/saved_desk_presenter.h" #include "ash/wm/desks/templates/saved_desk_util.h" -#include "ash/wm/overview/overview_constants.h" #include "ash/wm/overview/overview_controller.h" #include "ash/wm/overview/overview_focus_cycler.h" #include "ash/wm/overview/overview_grid.h" #include "ash/wm/overview/overview_session.h" #include "ash/wm/overview/overview_utils.h" +#include "ash/wm/wm_constants.h" #include "base/i18n/time_formatting.h" #include "base/task/single_thread_task_runner.h" #include "base/time/time.h" @@ -279,7 +279,7 @@ kSaveDeskCornerRadius); views::FocusRing* focus_ring = - StyleUtil::SetUpFocusRingForView(this, kFocusRingHaloInset); + StyleUtil::SetUpFocusRingForView(this, kWindowMiniViewFocusRingHaloInset); focus_ring->SetHasFocusPredicate( base::BindRepeating([](const views::View* view) { const auto* v = views::AsViewClass<SavedDeskItemView>(view);
diff --git a/ash/wm/overview/overview_constants.h b/ash/wm/overview/overview_constants.h index 40d3e4f..897c240 100644 --- a/ash/wm/overview/overview_constants.h +++ b/ash/wm/overview/overview_constants.h
@@ -24,24 +24,11 @@ // The amount we want to enlarge the dragged overview window. constexpr int kDraggingEnlargeDp = 10; -// Height of an item header. -constexpr int kHeaderHeightDp = WindowMiniView::kHeaderHeightDp; - -// Corner radius of the overview item. -constexpr int kOverviewItemCornerRadius = - WindowMiniView::kWindowMiniViewCornerRadius; - // Windows whose aspect ratio surpass this (width twice as large as height // or vice versa) will be classified as too wide or too tall and will be // handled slightly differently in overview mode. constexpr float kExtremeWindowRatioThreshold = 2.f; -// Inset for the focus ring around the focusable overview items. The ring is 2px -// thick and should have a 2px gap from the view it is associated with. Since -// the thickness is 2px and the stroke is in the middle, we use a -3px inset to -// achieve this. -constexpr int kFocusRingHaloInset = -3; - // The shadow types corresponding to the default and dragged states. constexpr SystemShadow::Type kDefaultShadowType = SystemShadow::Type::kElevation12;
diff --git a/ash/wm/overview/overview_drop_target.cc b/ash/wm/overview/overview_drop_target.cc index d187e4e..a94502a 100644 --- a/ash/wm/overview/overview_drop_target.cc +++ b/ash/wm/overview/overview_drop_target.cc
@@ -7,9 +7,9 @@ #include "ash/public/cpp/window_properties.h" #include "ash/style/ash_color_id.h" #include "ash/wm/desks/desks_util.h" -#include "ash/wm/overview/overview_constants.h" #include "ash/wm/overview/overview_grid.h" #include "ash/wm/overview/overview_utils.h" +#include "ash/wm/wm_constants.h" #include "base/memory/raw_ptr.h" #include "ui/base/metadata/metadata_header_macros.h" #include "ui/base/metadata/metadata_impl_macros.h" @@ -36,11 +36,11 @@ background_view_ = AddChildView(std::make_unique<views::View>()); background_view_->SetBackground(views::CreateThemedRoundedRectBackground( - kColorAshShieldAndBase20, kOverviewItemCornerRadius, + kColorAshShieldAndBase20, kWindowMiniViewCornerRadius, /*for_border_thickness=*/0)); SetBorder(views::CreateThemedRoundedRectBorder( - kDropTargetBorderThickness, kOverviewItemCornerRadius, + kDropTargetBorderThickness, kWindowMiniViewCornerRadius, cros_tokens::kCrosSysSystemBaseElevated)); } OverviewDropTargetView(const OverviewDropTargetView&) = delete;
diff --git a/ash/wm/overview/overview_grid.cc b/ash/wm/overview/overview_grid.cc index 4fe46d46..b081426 100644 --- a/ash/wm/overview/overview_grid.cc +++ b/ash/wm/overview/overview_grid.cc
@@ -63,6 +63,7 @@ #include "ash/wm/window_restore/pine_contents_view.h" #include "ash/wm/window_state_delegate.h" #include "ash/wm/window_util.h" +#include "ash/wm/wm_constants.h" #include "ash/wm/workspace/backdrop_controller.h" #include "ash/wm/workspace/workspace_layout_manager.h" #include "ash/wm/workspace_controller.h" @@ -1746,7 +1747,7 @@ scale = ScopedOverviewTransformWindow::GetItemScale( target_size.height(), height, GetTopViewInset(dragged_windows), - kHeaderHeightDp); + kWindowMiniViewHeaderHeight); } } @@ -1771,7 +1772,8 @@ // is nothing from the original window to be shown and nothing to be clipped. std::optional<gfx::RectF> split_view_bounds = GetSplitviewBoundsMaintainingAspectRatio(); - if (!split_view_bounds || split_view_bounds->height() < kHeaderHeightDp) { + if (!split_view_bounds || + split_view_bounds->height() < kWindowMiniViewHeaderHeight) { item->set_unclipped_size(std::nullopt); return width; } @@ -1785,7 +1787,7 @@ const float target_aspect_ratio = split_view_bounds->width() / split_view_bounds->height(); const bool clip_horizontally = aspect_ratio > target_aspect_ratio; - const int window_height = height - kHeaderHeightDp; + const int window_height = height - kWindowMiniViewHeaderHeight; gfx::Size unclipped_size; if (clip_horizontally) { unclipped_size.set_width(width); @@ -1807,7 +1809,7 @@ const int unclipped_height = width * target_size.height() / target_size.width(); unclipped_size.set_width(width); - unclipped_size.set_height(unclipped_height + kHeaderHeightDp); + unclipped_size.set_height(unclipped_height + kWindowMiniViewHeaderHeight); } DCHECK(!unclipped_size.IsEmpty());
diff --git a/ash/wm/overview/overview_group_item.cc b/ash/wm/overview/overview_group_item.cc index 335e25b..14cc02c 100644 --- a/ash/wm/overview/overview_group_item.cc +++ b/ash/wm/overview/overview_group_item.cc
@@ -16,6 +16,7 @@ #include "ash/wm/snap_group/snap_group.h" #include "ash/wm/snap_group/snap_group_controller.h" #include "ash/wm/window_util.h" +#include "ash/wm/wm_constants.h" #include "base/check_op.h" #include "base/containers/unique_ptr_adapters.h" #include "base/functional/callback_helpers.h" @@ -220,7 +221,8 @@ gfx::RectF OverviewGroupItem::GetTargetBoundsWithInsets() const { gfx::RectF target_bounds_with_insets = target_bounds_; - target_bounds_with_insets.Inset(gfx::InsetsF::TLBR(kHeaderHeightDp, 0, 0, 0)); + target_bounds_with_insets.Inset( + gfx::InsetsF::TLBR(kWindowMiniViewHeaderHeight, 0, 0, 0)); return target_bounds_with_insets; }
diff --git a/ash/wm/overview/overview_item.cc b/ash/wm/overview/overview_item.cc index 46a1b49a..e05fb94 100644 --- a/ash/wm/overview/overview_item.cc +++ b/ash/wm/overview/overview_item.cc
@@ -38,6 +38,7 @@ #include "ash/wm/window_state.h" #include "ash/wm/window_transient_descendant_iterator.h" #include "ash/wm/window_util.h" +#include "ash/wm/wm_constants.h" #include "base/auto_reset.h" #include "base/functional/bind.h" #include "base/functional/callback_helpers.h" @@ -376,7 +377,7 @@ if (unclipped_size_) { gfx::SizeF target_size(*unclipped_size_); gfx::SizeF preview_size = GetTargetBoundsWithInsets().size(); - target_size.Enlarge(0, -kHeaderHeightDp); + target_size.Enlarge(0, -kWindowMiniViewHeaderHeight); const float x_scale = target_size.width() / preview_size.width(); const float y_scale = target_size.height() / preview_size.height(); @@ -443,7 +444,8 @@ const int top_view_inset = transform_window_.GetTopInset(); gfx::RectF overview_item_bounds = transform_window_.ShrinkRectToFitPreservingAspectRatio( - screen_rect, transformed_bounds, top_view_inset, kHeaderHeightDp); + screen_rect, transformed_bounds, top_view_inset, + kWindowMiniViewHeaderHeight); if (transform_window_.type() == OverviewGridWindowFillMode::kNormal || transform_window_.type() == OverviewGridWindowFillMode::kLetterBoxed) { @@ -464,7 +466,8 @@ overview_item_bounds.set_y( overview_item_view_->header_view()->GetBoundsInScreen().bottom() - window_top_inset_target_height); - overview_item_bounds.set_height(target_bounds.height() - kHeaderHeightDp + + overview_item_bounds.set_height(target_bounds.height() - + kWindowMiniViewHeaderHeight + window_top_inset_target_height); } } @@ -517,7 +520,7 @@ gfx::RectF OverviewItem::GetTargetBoundsWithInsets() const { gfx::RectF target_bounds = target_bounds_; - target_bounds.Inset(gfx::InsetsF::TLBR(kHeaderHeightDp, 0, 0, 0)); + target_bounds.Inset(gfx::InsetsF::TLBR(kWindowMiniViewHeaderHeight, 0, 0, 0)); return target_bounds; } @@ -528,7 +531,7 @@ float OverviewItem::GetItemScale(int height) { return ScopedOverviewTransformWindow::GetItemScale( GetWindowsUnionScreenBounds().height(), height, - transform_window_.GetTopInset(), kHeaderHeightDp); + transform_window_.GetTopInset(), kWindowMiniViewHeaderHeight); } void OverviewItem::ScaleUpSelectedItem(OverviewAnimationType animation_type) {
diff --git a/ash/wm/overview/overview_item_base.cc b/ash/wm/overview/overview_item_base.cc index d65e864..d349510 100644 --- a/ash/wm/overview/overview_item_base.cc +++ b/ash/wm/overview/overview_item_base.cc
@@ -21,6 +21,7 @@ #include "ash/wm/snap_group/snap_group.h" #include "ash/wm/snap_group/snap_group_controller.h" #include "ash/wm/splitview/split_view_utils.h" +#include "ash/wm/wm_constants.h" #include "base/memory/raw_ptr.h" namespace ash { @@ -81,7 +82,7 @@ gfx::Rect shadow_content_bounds( gfx::ToRoundedRect(shadow_bounds_in_screen).size()); shadow_->SetContentBounds(shadow_content_bounds); - shadow_->SetRoundedCornerRadius(kOverviewItemCornerRadius); + shadow_->SetRoundedCornerRadius(kWindowMiniViewCornerRadius); } void OverviewItemBase::UpdateShadowTypeForDrag(bool is_dragging) {
diff --git a/ash/wm/overview/overview_item_view.cc b/ash/wm/overview/overview_item_view.cc index 5a27419..09ddafd7c 100644 --- a/ash/wm/overview/overview_item_view.cc +++ b/ash/wm/overview/overview_item_view.cc
@@ -8,19 +8,20 @@ #include "ash/strings/grit/ash_strings.h" #include "ash/style/close_button.h" -#include "ash/wm/overview/overview_constants.h" #include "ash/wm/overview/overview_grid.h" #include "ash/wm/overview/overview_item.h" #include "ash/wm/snap_group/snap_group.h" #include "ash/wm/snap_group/snap_group_controller.h" #include "ash/wm/window_mini_view_header_view.h" #include "ash/wm/window_preview_view.h" +#include "ash/wm/wm_constants.h" #include "base/containers/contains.h" #include "ui/accessibility/ax_node_data.h" #include "ui/aura/window.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/metadata/metadata_impl_macros.h" #include "ui/compositor/layer.h" +#include "ui/gfx/geometry/rounded_corners_f.h" #include "ui/gfx/geometry/size_conversions.h" #include "ui/strings/grit/ui_strings.h" #include "ui/views/animation/animation_builder.h" @@ -184,13 +185,13 @@ SetRoundedCornersRadius( window == snap_group->window1() ? gfx::RoundedCornersF( - /*upper_left=*/kOverviewItemCornerRadius, + /*upper_left=*/kWindowMiniViewCornerRadius, /*upper_right=*/0, /*lower_right=*/0, - /*lower_left=*/kOverviewItemCornerRadius) + /*lower_left=*/kWindowMiniViewCornerRadius) : gfx::RoundedCornersF( /*upper_left=*/0, - /*upper_right=*/kOverviewItemCornerRadius, - /*lower_right=*/kOverviewItemCornerRadius, + /*upper_right=*/kWindowMiniViewCornerRadius, + /*lower_right=*/kWindowMiniViewCornerRadius, /*lower_left=*/0)); } }
diff --git a/ash/wm/overview/overview_session_unittest.cc b/ash/wm/overview/overview_session_unittest.cc index a7fbb4d..be8d5191 100644 --- a/ash/wm/overview/overview_session_unittest.cc +++ b/ash/wm/overview/overview_session_unittest.cc
@@ -80,6 +80,7 @@ #include "ash/wm/window_state.h" #include "ash/wm/window_state_delegate.h" #include "ash/wm/window_util.h" +#include "ash/wm/wm_constants.h" #include "ash/wm/wm_event.h" #include "ash/wm/workspace/workspace_window_resizer.h" #include "base/containers/contains.h" @@ -864,7 +865,8 @@ std::unique_ptr<views::Widget> widget(CreateTestWidget()); widget->SetBounds(gfx::Rect(650, 0, 400, 400)); aura::Window* window2 = widget->GetNativeWindow(); - window2->SetProperty(aura::client::kTopViewInset, kHeaderHeightDp); + window2->SetProperty(aura::client::kTopViewInset, + kWindowMiniViewHeaderHeight); views::Widget::ReparentNativeView(window2, window->parent()); ASSERT_EQ(Shell::GetAllRootWindows()[1], window2->GetRootWindow());
diff --git a/ash/wm/overview/overview_window_drag_controller.cc b/ash/wm/overview/overview_window_drag_controller.cc index 0463ffa4..687fdc2d 100644 --- a/ash/wm/overview/overview_window_drag_controller.cc +++ b/ash/wm/overview/overview_window_drag_controller.cc
@@ -30,6 +30,7 @@ #include "ash/wm/splitview/split_view_utils.h" #include "ash/wm/window_positioning_utils.h" #include "ash/wm/window_util.h" +#include "ash/wm/wm_constants.h" #include "base/debug/crash_logging.h" #include "base/functional/bind.h" #include "base/functional/callback_helpers.h" @@ -150,7 +151,8 @@ } // Add the margins overview mode adds around the window's contents. - scaled_size.Enlarge(kDraggingEnlargeDp, kDraggingEnlargeDp + kHeaderHeightDp); + scaled_size.Enlarge(kDraggingEnlargeDp, + kDraggingEnlargeDp + kWindowMiniViewHeaderHeight); return scaled_size; } @@ -398,8 +400,9 @@ // bottom-edge of the desks bar (may be different edges if we are dragging // from different directions). gfx::SizeF item_no_header_size = original_scaled_size_; - item_no_header_size.Enlarge(float{-kDraggingEnlargeDp}, - float{-kDraggingEnlargeDp - kHeaderHeightDp}); + item_no_header_size.Enlarge( + float{-kDraggingEnlargeDp}, + float{-kDraggingEnlargeDp - kWindowMiniViewHeaderHeight}); // We must update the desks bar widget bounds before we cache its bounds // below, in case it needs to be pushed down due to splitview indicators.
diff --git a/ash/wm/overview/scoped_overview_transform_window.cc b/ash/wm/overview/scoped_overview_transform_window.cc index f6d962b..bf333bf 100644 --- a/ash/wm/overview/scoped_overview_transform_window.cc +++ b/ash/wm/overview/scoped_overview_transform_window.cc
@@ -3,7 +3,6 @@ // found in the LICENSE file. #include "ash/wm/overview/scoped_overview_transform_window.h" -#include "base/memory/raw_ptr.h" #include <algorithm> #include <utility> @@ -29,7 +28,9 @@ #include "ash/wm/window_state.h" #include "ash/wm/window_transient_descendant_iterator.h" #include "ash/wm/window_util.h" +#include "ash/wm/wm_constants.h" #include "base/functional/bind.h" +#include "base/memory/raw_ptr.h" #include "base/task/single_thread_task_runner.h" #include "chromeos/ui/base/window_properties.h" #include "ui/aura/client/aura_constants.h" @@ -110,12 +111,12 @@ /*upper_left=*/0, /*upper_right=*/0, /*lower_right=*/0, /*lower_left=*/ - kOverviewItemCornerRadius / scale) + kWindowMiniViewCornerRadius / scale) : gfx::RoundedCornersF( /*upper_left=*/0, /*upper_right=*/0, /*lower_right=*/ - kOverviewItemCornerRadius / scale, + kWindowMiniViewCornerRadius / scale, /*lower_left=*/0); } } @@ -123,8 +124,8 @@ return gfx::RoundedCornersF( /*upper_left=*/0, /*upper_right=*/0, - /*lower_right=*/kOverviewItemCornerRadius / scale, - /*lower_left=*/kOverviewItemCornerRadius / scale); + /*lower_right=*/kWindowMiniViewCornerRadius / scale, + /*lower_left=*/kWindowMiniViewCornerRadius / scale); } } // namespace
diff --git a/ash/wm/snap_group/snap_group_unittest.cc b/ash/wm/snap_group/snap_group_unittest.cc index 0598e68..a401397 100644 --- a/ash/wm/snap_group/snap_group_unittest.cc +++ b/ash/wm/snap_group/snap_group_unittest.cc
@@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "ash/wm/snap_group/snap_group.h" + #include <memory> #include <vector> @@ -34,7 +36,6 @@ #include "ash/wm/overview/overview_utils.h" #include "ash/wm/overview/overview_window_drag_controller.h" #include "ash/wm/overview/scoped_overview_transform_window.h" -#include "ash/wm/snap_group/snap_group.h" #include "ash/wm/snap_group/snap_group_controller.h" #include "ash/wm/splitview/split_view_constants.h" #include "ash/wm/splitview/split_view_controller.h" @@ -51,6 +52,7 @@ #include "ash/wm/window_resizer.h" #include "ash/wm/window_state.h" #include "ash/wm/window_util.h" +#include "ash/wm/wm_constants.h" #include "ash/wm/wm_event.h" #include "ash/wm/wm_metrics.h" #include "ash/wm/workspace/multi_window_resize_controller.h" @@ -87,8 +89,6 @@ using WindowCyclingDirection = WindowCycleController::WindowCyclingDirection; -constexpr int kWindowMiniViewCornerRadius = 16; - SplitViewController* split_view_controller() { return SplitViewController::Get(Shell::GetPrimaryRootWindow()); }
diff --git a/ash/wm/window_cycle/window_cycle_item_view.cc b/ash/wm/window_cycle/window_cycle_item_view.cc index fdae31db..7593497 100644 --- a/ash/wm/window_cycle/window_cycle_item_view.cc +++ b/ash/wm/window_cycle/window_cycle_item_view.cc
@@ -15,6 +15,7 @@ #include "ash/wm/window_mini_view_header_view.h" #include "ash/wm/window_preview_view.h" #include "ash/wm/window_util.h" +#include "ash/wm/wm_constants.h" #include "ui/accessibility/ax_action_data.h" #include "ui/aura/window.h" #include "ui/base/metadata/metadata_impl_macros.h" @@ -124,7 +125,7 @@ std::clamp(preview_size.width(), kMinPreviewWidthDp, kMaxPreviewWidthDp)); const int margin = GetInsets().width(); - preview_size.Enlarge(margin, margin + WindowMiniView::kHeaderHeightDp); + preview_size.Enlarge(margin, margin + kWindowMiniViewHeaderHeight); return preview_size; } @@ -202,13 +203,13 @@ void GroupContainerCycleView::RefreshItemVisuals() { if (mini_views_.size() == 2u) { mini_views_[0]->SetRoundedCornersRadius(gfx::RoundedCornersF( - /*upper_left=*/WindowMiniView::kWindowMiniViewCornerRadius, + /*upper_left=*/kWindowMiniViewCornerRadius, /*upper_right=*/0, /*lower_right=*/0, - /*lower_left=*/WindowMiniView::kWindowMiniViewCornerRadius)); + /*lower_left=*/kWindowMiniViewCornerRadius)); mini_views_[1]->SetRoundedCornersRadius(gfx::RoundedCornersF( /*upper_left=*/0, - /*upper_right=*/WindowMiniView::kWindowMiniViewCornerRadius, - /*lower_right=*/WindowMiniView::kWindowMiniViewCornerRadius, + /*upper_right=*/kWindowMiniViewCornerRadius, + /*lower_right=*/kWindowMiniViewCornerRadius, /*lower_left=*/0)); }
diff --git a/ash/wm/window_cycle/window_cycle_view.cc b/ash/wm/window_cycle/window_cycle_view.cc index ea9cf05..5ef138e 100644 --- a/ash/wm/window_cycle/window_cycle_view.cc +++ b/ash/wm/window_cycle/window_cycle_view.cc
@@ -24,6 +24,7 @@ #include "ash/wm/window_cycle/window_cycle_item_view.h" #include "ash/wm/window_cycle/window_cycle_list.h" #include "ash/wm/window_mini_view.h" +#include "ash/wm/wm_constants.h" #include "base/check_op.h" #include "base/functional/bind.h" #include "base/memory/raw_ptr.h" @@ -240,13 +241,12 @@ no_recent_items_label_->font_list().GetFontSize()) .DeriveWithWeight(gfx::Font::Weight::NORMAL)); no_recent_items_label_->SetVisible(windows.empty()); - no_recent_items_label_->SetPreferredSize( - gfx::Size(tab_slider_->GetPreferredSize().width() + - 2 * WindowCycleView::kInsideBorderHorizontalPaddingDp, - WindowCycleItemView::kFixedPreviewHeightDp + - WindowMiniView::kHeaderHeightDp + - kMirrorContainerVerticalPaddingDp + - kInsideBorderVerticalPaddingDp + 8)); + no_recent_items_label_->SetPreferredSize(gfx::Size( + tab_slider_->GetPreferredSize().width() + + 2 * WindowCycleView::kInsideBorderHorizontalPaddingDp, + WindowCycleItemView::kFixedPreviewHeightDp + + kWindowMiniViewHeaderHeight + kMirrorContainerVerticalPaddingDp + + kInsideBorderVerticalPaddingDp + 8)); } for (aura::Window* window : windows) {
diff --git a/ash/wm/window_mini_view.cc b/ash/wm/window_mini_view.cc index bb69758..3f28c538 100644 --- a/ash/wm/window_mini_view.cc +++ b/ash/wm/window_mini_view.cc
@@ -7,12 +7,12 @@ #include <memory> #include "ash/shell.h" -#include "ash/wm/overview/overview_constants.h" #include "ash/wm/snap_group/snap_group.h" #include "ash/wm/snap_group/snap_group_controller.h" #include "ash/wm/window_mini_view_header_view.h" #include "ash/wm/window_preview_view.h" #include "ash/wm/window_util.h" +#include "ash/wm/wm_constants.h" #include "chromeos/constants/chromeos_features.h" #include "chromeos/ui/base/window_properties.h" #include "ui/accessibility/ax_node_data.h" @@ -63,9 +63,8 @@ raw_value.lower_left()); } - return gfx::RoundedCornersF( - 0, 0, WindowMiniView::kWindowMiniViewCornerRadius / scale, - WindowMiniView::kWindowMiniViewCornerRadius / scale); + return gfx::RoundedCornersF(0, 0, kWindowMiniViewCornerRadius / scale, + kWindowMiniViewCornerRadius / scale); } } // namespace @@ -156,9 +155,18 @@ return; } + const auto header_rounded_corners = + header_view_->GetHeaderRoundedCorners(source_window_); if (header_view_rounded_corners_.has_value()) { + if (header_rounded_corners == header_view_rounded_corners_.value()) { + return; + } header_view_->SetHeaderViewRoundedCornerRadius( header_view_rounded_corners_.value()); + } else if (header_rounded_corners == + gfx::RoundedCornersF(kWindowMiniViewHeaderCornerRadius, + kWindowMiniViewHeaderCornerRadius, 0, 0)) { + return; } header_view_->RefreshHeaderViewRoundedCorners(); @@ -229,7 +237,7 @@ gfx::Rect WindowMiniView::GetHeaderBounds() const { gfx::Rect header_bounds = GetContentsBounds(); - header_bounds.set_height(kHeaderHeightDp); + header_bounds.set_height(kWindowMiniViewHeaderHeight); return header_bounds; } @@ -247,7 +255,7 @@ gfx::Rect WindowMiniView::GetContentAreaBounds() const { gfx::Rect bounds(GetContentsBounds()); - bounds.Inset(gfx::Insets::TLBR(kHeaderHeightDp, 0, 0, 0)); + bounds.Inset(gfx::Insets::TLBR(kWindowMiniViewHeaderHeight, 0, 0, 0)); return bounds; } @@ -336,12 +344,12 @@ ? 0 : kFocusRingCornerRadius; return std::make_unique<views::RoundRectHighlightPathGenerator>( - gfx::Insets(kFocusRingHaloInset), + gfx::Insets(kWindowMiniViewFocusRingHaloInset), gfx::RoundedCornersF(upper_left, upper_right, lower_right, lower_left)); } return std::make_unique<views::RoundRectHighlightPathGenerator>( - gfx::Insets(kFocusRingHaloInset), + gfx::Insets(kWindowMiniViewFocusRingHaloInset), gfx::RoundedCornersF(kFocusRingCornerRadius)); }
diff --git a/ash/wm/window_mini_view.h b/ash/wm/window_mini_view.h index ecc392b..3cd11ce 100644 --- a/ash/wm/window_mini_view.h +++ b/ash/wm/window_mini_view.h
@@ -107,19 +107,10 @@ WindowMiniView& operator=(const WindowMiniView&) = delete; ~WindowMiniView() override; - static constexpr int kHeaderHeightDp = 40; // The size in dp of the window icon shown on the alt-tab/overview window next // to the title. static constexpr gfx::Size kIconSize = gfx::Size(24, 24); - // The corner radius for WindowMiniView. Note that instead of setting the - // corner radius directly on the window mini view, setting the corner radius - // on its children (header view, preview header). The reasons are: - // 1. The WindowMiniView might have a non-empty border. - // 2. The focus ring which is a child view of the WindowMiniView couldn't be - // drawn correctly if its parent's layer is clipped. - static constexpr int kWindowMiniViewCornerRadius = 16; - aura::Window* source_window() { return source_window_; } const aura::Window* source_window() const { return source_window_; } WindowMiniViewHeaderView* header_view() { return header_view_; }
diff --git a/ash/wm/window_mini_view_header_view.cc b/ash/wm/window_mini_view_header_view.cc index 0b4bc9e..f84aa482 100644 --- a/ash/wm/window_mini_view_header_view.cc +++ b/ash/wm/window_mini_view_header_view.cc
@@ -9,6 +9,7 @@ #include "ash/wm/snap_group/snap_group.h" #include "ash/wm/snap_group/snap_group_controller.h" #include "ash/wm/window_mini_view.h" +#include "ash/wm/wm_constants.h" #include "chromeos/ui/base/window_properties.h" #include "ui/aura/client/aura_constants.h" #include "ui/base/metadata/metadata_impl_macros.h" @@ -33,9 +34,6 @@ // Padding between header items. constexpr int kHeaderPaddingDp = 8; -// The corner radius for the top corners for the header. -constexpr int kHeaderTopCornerRadius = 16; - // The size in dp of the window icon shown on the alt-tab/overview window next // to the title. constexpr gfx::Size kIconSize = gfx::Size(24, 24); @@ -127,8 +125,9 @@ gfx::RoundedCornersF WindowMiniViewHeaderView::GetHeaderRoundedCorners( aura::Window* window) const { - return header_view_rounded_corners_.value_or(gfx::RoundedCornersF( - kHeaderTopCornerRadius, kHeaderTopCornerRadius, 0, 0)); + return header_view_rounded_corners_.value_or( + gfx::RoundedCornersF(kWindowMiniViewHeaderCornerRadius, + kWindowMiniViewHeaderCornerRadius, 0, 0)); } BEGIN_METADATA(WindowMiniViewHeaderView, views::View)
diff --git a/ash/wm/wm_constants.h b/ash/wm/wm_constants.h new file mode 100644 index 0000000..53235ae --- /dev/null +++ b/ash/wm/wm_constants.h
@@ -0,0 +1,34 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_WM_WM_CONSTANTS_H_ +#define ASH_WM_WM_CONSTANTS_H_ + +#include "ash/ash_export.h" + +namespace ash { + +// The corner radius for the top corners of `WindowMiniView`. +ASH_EXPORT constexpr int kWindowMiniViewHeaderCornerRadius = 16; + +// The corner radius for WindowMiniView. Note that instead of setting the +// corner radius directly on the window mini view, setting the corner radius +// on its children (header view, preview header). The reasons are: +// 1. The WindowMiniView might have a non-empty border. +// 2. The focus ring which is a child view of the WindowMiniView couldn't be +// drawn correctly if its parent's layer is clipped. +ASH_EXPORT constexpr int kWindowMiniViewCornerRadius = 16; + +// Height value for the header view. +ASH_EXPORT constexpr int kWindowMiniViewHeaderHeight = 40; + +// Inset for the focus ring around the focusable `WindowMiniView` items. The +// ring is 2px thick and should have a 2px gap from the view it is associated +// with. Since the thickness is 2px and the stroke is in the middle, we use a +// -3px inset to achieve this. +constexpr int kWindowMiniViewFocusRingHaloInset = -3; + +} // namespace ash + +#endif // ASH_WM_WM_CONSTANTS_H_
diff --git a/base/containers/heap_array.h b/base/containers/heap_array.h index e0bcf91..f45bef9 100644 --- a/base/containers/heap_array.h +++ b/base/containers/heap_array.h
@@ -91,31 +91,31 @@ T* data() ABSL_ATTRIBUTE_LIFETIME_BOUND { return data_.get(); } const T* data() const ABSL_ATTRIBUTE_LIFETIME_BOUND { return data_.get(); } - iterator begin() ABSL_ATTRIBUTE_LIFETIME_BOUND { return span().begin(); } + iterator begin() ABSL_ATTRIBUTE_LIFETIME_BOUND { return as_span().begin(); } const_iterator begin() const ABSL_ATTRIBUTE_LIFETIME_BOUND { - return span().begin(); + return as_span().begin(); } - iterator end() ABSL_ATTRIBUTE_LIFETIME_BOUND { return span().end(); } + iterator end() ABSL_ATTRIBUTE_LIFETIME_BOUND { return as_span().end(); } const_iterator end() const ABSL_ATTRIBUTE_LIFETIME_BOUND { - return span().end(); + return as_span().end(); } T& operator[](size_t idx) ABSL_ATTRIBUTE_LIFETIME_BOUND { - return span()[idx]; + return as_span()[idx]; } const T& operator[](size_t idx) const ABSL_ATTRIBUTE_LIFETIME_BOUND { - return span()[idx]; + return as_span()[idx]; } // Access the HeapArray via spans. Note that span<T> is implicilty - // constructible from HeapArray<T>, so an explicit call to .span() is + // constructible from HeapArray<T>, so an explicit call to .as_span() is // most useful, say, when the compiler can't deduce a template // argument type. - base::span<T> span() ABSL_ATTRIBUTE_LIFETIME_BOUND { + base::span<T> as_span() ABSL_ATTRIBUTE_LIFETIME_BOUND { return base::span<T>(data_.get(), size_); } - base::span<const T> span() const ABSL_ATTRIBUTE_LIFETIME_BOUND { + base::span<const T> as_span() const ABSL_ATTRIBUTE_LIFETIME_BOUND { return base::span<const T>(data_.get(), size_); } @@ -126,30 +126,30 @@ // the HeapArray. base::span<T> subspan(size_t offset, size_t count = base::dynamic_extent) ABSL_ATTRIBUTE_LIFETIME_BOUND { - return span().subspan(offset, count); + return as_span().subspan(offset, count); } base::span<const T> subspan(size_t offset, size_t count = base::dynamic_extent) const ABSL_ATTRIBUTE_LIFETIME_BOUND { - return span().subspan(offset, count); + return as_span().subspan(offset, count); } // Returns a span over the first `count` elements of the HeapArray. A CHECK() // occurs if the `count` is larger than size of the HeapArray. base::span<T> first(size_t count) ABSL_ATTRIBUTE_LIFETIME_BOUND { - return span().first(count); + return as_span().first(count); } base::span<const T> first(size_t count) const ABSL_ATTRIBUTE_LIFETIME_BOUND { - return span().first(count); + return as_span().first(count); } // Returns a span over the last `count` elements of the HeapArray. A CHECK() // occurs if the `count` is larger than size of the HeapArray. base::span<T> last(size_t count) ABSL_ATTRIBUTE_LIFETIME_BOUND { - return span().last(count); + return as_span().last(count); } base::span<const T> last(size_t count) const ABSL_ATTRIBUTE_LIFETIME_BOUND { - return span().last(count); + return as_span().last(count); } private:
diff --git a/base/containers/heap_array_nocompile.nc b/base/containers/heap_array_nocompile.nc index dda34838..03d73ff 100644 --- a/base/containers/heap_array_nocompile.nc +++ b/base/containers/heap_array_nocompile.nc
@@ -58,7 +58,7 @@ } base::span<int> WontCompileSpanLifetime() { - return HeapArray<int>::WithSize(1u).span(); // expected-error {{returning address}} + return HeapArray<int>::WithSize(1u).as_span(); // expected-error {{returning address}} } } // namespace
diff --git a/base/containers/heap_array_unittest.cc b/base/containers/heap_array_unittest.cc index 94940c0..32d236c 100644 --- a/base/containers/heap_array_unittest.cc +++ b/base/containers/heap_array_unittest.cc
@@ -110,6 +110,23 @@ EXPECT_DEATH_IF_SUPPORTED(vec[2], ""); } +TEST(HeapArray, AsSpan) { + { + auto vec = HeapArray<uint32_t>::WithSize(2u); + auto s = vec.as_span(); + static_assert(std::same_as<decltype(s), span<uint32_t>>); + EXPECT_EQ(s.size(), 2u); + EXPECT_EQ(s.data(), vec.data()); + } + { + const auto vec = HeapArray<uint32_t>::WithSize(2u); + auto s = vec.as_span(); + static_assert(std::same_as<decltype(s), span<const uint32_t>>); + EXPECT_EQ(s.size(), 2u); + EXPECT_EQ(s.data(), vec.data()); + } +} + TEST(HeapArray, Subspan) { auto vec = HeapArray<uint32_t>::WithSize(4u); for (size_t i = 0; i < vec.size(); ++i) {
diff --git a/base/containers/span.h b/base/containers/span.h index 6c83166..db8d969 100644 --- a/base/containers/span.h +++ b/base/containers/span.h
@@ -8,6 +8,7 @@ #include <stddef.h> #include <stdint.h> +#include <algorithm> #include <array> #include <concepts> #include <iterator> @@ -186,6 +187,7 @@ // - as_chars() function. // - as_writable_chars() function. // - as_byte_span() function. +// - copy_from() method. // // Furthermore, all constructors and methods are marked noexcept due to the lack // of exceptions in Chromium. @@ -341,6 +343,24 @@ return reverse_iterator(begin()); } + // Bounds-checked copy of spans into spans. The spans must be the exact + // same size or a hard CHECK() occurs. This is a non-std extension that + // is inspired by the Rust slice::copy_from_slice() method. + template <typename U, size_t M> + void copy_from(const span<U, M>& other) + requires(M != dynamic_extent && internal::LegalDataConversion<T, U>) + { + static_assert(N == M, "span size mismatch"); + std::ranges::copy(other, data()); + } + template <typename U, size_t M> + void copy_from(const span<U, M>& other) + requires(M == dynamic_extent && internal::LegalDataConversion<T, U>) + { + CHECK_EQ(size_bytes(), other.size_bytes()); + std::ranges::copy(other, data()); + } + private: // This field is not a raw_ptr<> because it was filtered by the rewriter // for: #constexpr-ctor-field-initializer, #global-scope, #union @@ -490,6 +510,17 @@ return reverse_iterator(begin()); } + // Bounds-checked copy of spans into spans. The spans must be the exact + // same size or a hard CHECK() occurs. This is a non-std extension that + // is inspired by the Rust slice::copy_from_slice() method. + template <typename U, size_t M> + void copy_from(const span<U, M>& other) + requires(internal::LegalDataConversion<T, U>) + { + CHECK_EQ(size_bytes(), other.size_bytes()); + std::ranges::copy(other, data()); + } + private: // This field is not a raw_ptr<> because it was filtered by the rewriter // for: #constexpr-ctor-field-initializer, #global-scope, #union
diff --git a/base/containers/span_nocompile.nc b/base/containers/span_nocompile.nc index 20b0a41..7651649 100644 --- a/base/containers/span_nocompile.nc +++ b/base/containers/span_nocompile.nc
@@ -172,4 +172,10 @@ span<int> s(array); // expected-error {{no matching constructor for initialization of 'span<int>'}} } +void FixedSizeCopyTooSmall() { + const int src[] = {1, 2, 3}; + int dst[2]; + base::make_span(dst).copy_from(base::make_span(src)); // expected-error@*:* {{span size mismatch}} +} + } // namespace base
diff --git a/base/containers/span_unittest.cc b/base/containers/span_unittest.cc index 789d0ff..afa9e3f 100644 --- a/base/containers/span_unittest.cc +++ b/base/containers/span_unittest.cc
@@ -1672,4 +1672,41 @@ static_assert(EXTENT(plain_array) == kSize, "EXTENT broken for plain arrays"); } +TEST(SpanTest, CopyFrom) { + int arr[] = {1, 2, 3}; + span<int, 0> empty_static_span; + span<int, 3> static_span = base::make_span(arr); + + std::vector<int> vec = {4, 5, 6}; + span<int> empty_dynamic_span; + span<int> dynamic_span = base::make_span(vec); + + // Handle empty cases gracefully. + empty_static_span.copy_from(empty_dynamic_span); + empty_dynamic_span.copy_from(empty_static_span); + static_span.first(empty_static_span.size()).copy_from(empty_static_span); + dynamic_span.first(empty_dynamic_span.size()).copy_from(empty_dynamic_span); + EXPECT_THAT(arr, ElementsAre(1, 2, 3)); + EXPECT_THAT(vec, ElementsAre(4, 5, 6)); + + // Test too small destinations. + EXPECT_DEATH_IF_SUPPORTED(empty_static_span.copy_from(dynamic_span), ""); + EXPECT_DEATH_IF_SUPPORTED(empty_dynamic_span.copy_from(static_span), ""); + EXPECT_DEATH_IF_SUPPORTED(empty_dynamic_span.copy_from(dynamic_span), ""); + EXPECT_DEATH_IF_SUPPORTED(static_span.first(2).copy_from(dynamic_span), ""); + EXPECT_DEATH_IF_SUPPORTED(dynamic_span.last(2).copy_from(static_span), ""); + + static_span.first(2).copy_from(static_span.last(2)); + EXPECT_THAT(arr, ElementsAre(2, 3, 3)); + + dynamic_span.first(2).copy_from(dynamic_span.last(2)); + EXPECT_THAT(vec, ElementsAre(5, 6, 6)); + + static_span.last(1).copy_from(dynamic_span.last(1)); + EXPECT_THAT(arr, ElementsAre(2, 3, 6)); + + dynamic_span.first(1).copy_from(static_span.first(1)); + EXPECT_THAT(vec, ElementsAre(2, 6, 6)); +} + } // namespace base
diff --git a/base/files/file.cc b/base/files/file.cc index ae486b4..ce02b46 100644 --- a/base/files/file.cc +++ b/base/files/file.cc
@@ -99,26 +99,44 @@ } #endif -bool File::ReadAndCheck(int64_t offset, span<uint8_t> data) { +int File::Read(int64_t offset, span<uint8_t> data) { int size = checked_cast<int>(data.size()); - return Read(offset, reinterpret_cast<char*>(data.data()), size) == size; + return Read(offset, reinterpret_cast<char*>(data.data()), size); +} + +bool File::ReadAndCheck(int64_t offset, span<uint8_t> data) { + // Size checked in span form of Read() above. + return Read(offset, data) == static_cast<int>(data.size()); +} + +int File::ReadAtCurrentPos(span<uint8_t> data) { + int size = checked_cast<int>(data.size()); + return ReadAtCurrentPos(reinterpret_cast<char*>(data.data()), size); } bool File::ReadAtCurrentPosAndCheck(span<uint8_t> data) { + // Size checked in span form of ReadAtCurrentPos() above. + return ReadAtCurrentPos(data) == static_cast<int>(data.size()); +} + +int File::Write(int64_t offset, span<const uint8_t> data) { int size = checked_cast<int>(data.size()); - return ReadAtCurrentPos(reinterpret_cast<char*>(data.data()), size) == size; + return Write(offset, reinterpret_cast<const char*>(data.data()), size); } bool File::WriteAndCheck(int64_t offset, span<const uint8_t> data) { + // Size checked in span form of Write() above. + return Write(offset, data) == static_cast<int>(data.size()); +} + +int File::WriteAtCurrentPos(span<const uint8_t> data) { int size = checked_cast<int>(data.size()); - return Write(offset, reinterpret_cast<const char*>(data.data()), size) == - size; + return WriteAtCurrentPos(reinterpret_cast<const char*>(data.data()), size); } bool File::WriteAtCurrentPosAndCheck(span<const uint8_t> data) { - int size = checked_cast<int>(data.size()); - return WriteAtCurrentPos(reinterpret_cast<const char*>(data.data()), size) == - size; + // Size checked in span form of WriteAtCurrentPos() above. + return WriteAtCurrentPos(data) == static_cast<int>(data.size()); } // static
diff --git a/base/files/file.h b/base/files/file.h index 1e0b440..0d8eb4676 100644 --- a/base/files/file.h +++ b/base/files/file.h
@@ -220,9 +220,11 @@ // normal expectation is that actually |size| bytes are read unless there is // an error. int Read(int64_t offset, char* data, int size); + int Read(int64_t offset, base::span<uint8_t> data); // Same as above but without seek. int ReadAtCurrentPos(char* data, int size); + int ReadAtCurrentPos(base::span<uint8_t> data); // Reads the given number of bytes (or until EOF is reached) starting with the // given offset, but does not make any effort to read all data on all @@ -239,9 +241,11 @@ // Ignores the offset and writes to the end of the file if the file was opened // with FLAG_APPEND. int Write(int64_t offset, const char* data, int size); + int Write(int64_t offset, base::span<const uint8_t> data); // Save as above but without seek. int WriteAtCurrentPos(const char* data, int size); + int WriteAtCurrentPos(base::span<const uint8_t> data); // Save as above but does not make any effort to write all data on all // platforms. Returns the number of bytes written, or -1 on error.
diff --git a/base/files/file_path_watcher_unittest.cc b/base/files/file_path_watcher_unittest.cc index 6727eb0..a10ba93 100644 --- a/base/files/file_path_watcher_unittest.cc +++ b/base/files/file_path_watcher_unittest.cc
@@ -238,7 +238,7 @@ ExpectedEventsSinceLastWait::kNone; }; -class TestDelegateBase : public SupportsWeakPtr<TestDelegateBase> { +class TestDelegateBase { public: TestDelegateBase() = default; TestDelegateBase(const TestDelegateBase&) = delete; @@ -250,12 +250,13 @@ const FilePathWatcher::ChangeInfo& change_info, const FilePath& path, bool error) = 0; + virtual base::WeakPtr<TestDelegateBase> AsWeakPtr() = 0; }; // Receives and accumulates notifications from a specific `FilePathWatcher`. // This class is not thread safe. All methods must be called from the sequence // the instance is constructed on. -class TestDelegate : public TestDelegateBase { +class TestDelegate final : public TestDelegateBase { public: TestDelegate() : id_(g_next_delegate_id.GetNext()) {} TestDelegate(const TestDelegate&) = delete; @@ -276,6 +277,10 @@ received_events_.emplace_back(std::move(event)); } + base::WeakPtr<TestDelegateBase> AsWeakPtr() override { + return weak_ptr_factory_.GetWeakPtr(); + } + // Gives all in-flight events a chance to arrive, then forgets all events that // have been received by this delegate. This method may be a useful reset // after performing a file system operation that may result in a variable @@ -342,6 +347,7 @@ const size_t id_; std::list<Event> received_events_ GUARDED_BY_CONTEXT(sequence_checker_); + base::WeakPtrFactory<TestDelegateBase> weak_ptr_factory_{this}; }; } // namespace @@ -618,7 +624,7 @@ // Used by the DeleteDuringNotify test below. // Deletes the FilePathWatcher when it's notified. -class Deleter : public TestDelegateBase { +class Deleter final : public TestDelegateBase { public: explicit Deleter(OnceClosure done_closure) : watcher_(std::make_unique<FilePathWatcher>()), @@ -638,11 +644,16 @@ std::move(done_closure_).Run(); } + base::WeakPtr<TestDelegateBase> AsWeakPtr() override { + return weak_ptr_factory_.GetWeakPtr(); + } + FilePathWatcher* watcher() const { return watcher_.get(); } private: std::unique_ptr<FilePathWatcher> watcher_; OnceClosure done_closure_; + base::WeakPtrFactory<Deleter> weak_ptr_factory_{this}; }; } // namespace
diff --git a/base/fuchsia/time_zone_data_unittest.cc b/base/fuchsia/time_zone_data_unittest.cc index a1076b98..c87b09f 100644 --- a/base/fuchsia/time_zone_data_unittest.cc +++ b/base/fuchsia/time_zone_data_unittest.cc
@@ -23,7 +23,11 @@ // File path to the text file containing the expected ICU library revision, for // example "2019c". +// TODO(crbug.com/1360077): Remove once tzdata is fully migrated away from +// config-data. I.e. all released Chromium versions in Fuchsia support it. const char kRevisionFilePath[] = "/config/data/tzdata/revision.txt"; +// Same as above, except the modern version. +const char kTZDataRevisionFilePath[] = "/config/tzdata/icu/revision.txt"; } // namespace @@ -63,8 +67,16 @@ // that this test is not skipped. In Chromium build bot setup, this file may // not be present, in which case we skip running this test. TEST_F(TimeZoneDataTest, CompareSystemRevisionWithExpected) { - if (!base::PathExists(base::FilePath(kRevisionFilePath))) { - GTEST_SKIP() << "Skipped test because tzdata config is not present"; + std::string revision_file_path; + if (base::PathExists(base::FilePath(kTZDataRevisionFilePath))) { + revision_file_path = kTZDataRevisionFilePath; + } else if (base::PathExists(base::FilePath(kRevisionFilePath))) { + // Legacy path. + revision_file_path = kRevisionFilePath; + } + + if (revision_file_path.empty()) { + FAIL() << "No revision file found"; } // ResetIcu() ensures that time zone data is loaded from the default location. @@ -75,7 +87,7 @@ ASSERT_TRUE(InitializeICU()); std::string expected; EXPECT_TRUE( - base::ReadFileToString(base::FilePath(kRevisionFilePath), &expected)); + base::ReadFileToString(base::FilePath(revision_file_path), &expected)); std::string actual; GetActualRevision(&actual); EXPECT_EQ(expected, actual);
diff --git a/base/rand_util.cc b/base/rand_util.cc index 7b290f4e4..0be3aaa5 100644 --- a/base/rand_util.cc +++ b/base/rand_util.cc
@@ -115,7 +115,7 @@ std::vector<uint8_t> RandBytesAsVector(size_t length) { std::vector<uint8_t> result(length); if (result.size()) { - RandBytes(result.data(), result.size()); + RandBytes(result); } return result; }
diff --git a/base/rand_util.h b/base/rand_util.h index 8387bc9..00e901a3 100644 --- a/base/rand_util.h +++ b/base/rand_util.h
@@ -14,6 +14,7 @@ #include "base/base_export.h" #include "base/compiler_specific.h" +#include "base/containers/span.h" #include "base/gtest_prod_util.h" #include "build/build_config.h" @@ -83,11 +84,13 @@ // [0, 1). Thread-safe. BASE_EXPORT float BitsToOpenEndedUnitIntervalF(uint64_t bits); -// Fills |output_length| bytes of |output| with random data. Thread-safe. +// Fills `output` with random data. Thread-safe. // // Although implementations are required to use a cryptographically secure // random number source, code outside of base/ that relies on this should use // crypto::RandBytes instead to ensure the requirement is easily discoverable. +BASE_EXPORT void RandBytes(span<uint8_t> output); +// TODO(https://crbug.com/1490484): Migrate callers to the span version. BASE_EXPORT void RandBytes(void* output, size_t output_length); // Creates a vector of `length` bytes, fills it with random data, and returns
diff --git a/base/rand_util_fuchsia.cc b/base/rand_util_fuchsia.cc index b9e5eaa9..7804634 100644 --- a/base/rand_util_fuchsia.cc +++ b/base/rand_util_fuchsia.cc
@@ -8,6 +8,7 @@ #include <atomic> +#include "base/containers/span.h" #include "base/feature_list.h" #include "third_party/boringssl/src/include/openssl/crypto.h" #include "third_party/boringssl/src/include/openssl/rand.h" @@ -39,16 +40,20 @@ } // namespace internal -void RandBytes(void* output, size_t output_length) { +void RandBytes(span<uint8_t> output) { if (internal::UseBoringSSLForRandBytes()) { // Ensure BoringSSL is initialized so it can use things like RDRAND. CRYPTO_library_init(); // BoringSSL's RAND_bytes always returns 1. Any error aborts the program. - (void)RAND_bytes(static_cast<uint8_t*>(output), output_length); + (void)RAND_bytes(output.data(), output.size()); return; } - zx_cprng_draw(output, output_length); + zx_cprng_draw(output.data(), output.size()); +} + +void RandBytes(void* output, size_t output_length) { + RandBytes(make_span(reinterpret_cast<uint8_t*>(output), output_length)); } namespace internal {
diff --git a/base/rand_util_nacl.cc b/base/rand_util_nacl.cc index 6ac810e..dfa7263 100644 --- a/base/rand_util_nacl.cc +++ b/base/rand_util_nacl.cc
@@ -9,19 +9,22 @@ #include <stdint.h> #include "base/check_op.h" +#include "base/containers/span.h" namespace base { -void RandBytes(void* output, size_t output_length) { - char* output_ptr = static_cast<char*>(output); - while (output_length > 0) { +void RandBytes(span<uint8_t> output) { + while (!output.empty()) { size_t nread; - const int error = nacl_secure_random(output_ptr, output_length, &nread); + const int error = nacl_secure_random(output.data(), output.size(), &nread); CHECK_EQ(error, 0); - CHECK_LE(nread, output_length); - output_ptr += nread; - output_length -= nread; + CHECK_LE(nread, output.size()); + output = output.subspan(nread); } } +void RandBytes(void* output, size_t output_length) { + RandBytes(make_span(reinterpret_cast<uint8_t*>(output), output_length)); +} + } // namespace base
diff --git a/base/rand_util_posix.cc b/base/rand_util_posix.cc index 29cd9d0..d0da3d7 100644 --- a/base/rand_util_posix.cc +++ b/base/rand_util_posix.cc
@@ -14,6 +14,7 @@ #include "base/check.h" #include "base/compiler_specific.h" +#include "base/containers/span.h" #include "base/feature_list.h" #include "base/files/file_util.h" #include "base/metrics/histogram_macros.h" @@ -175,14 +176,14 @@ namespace { -void RandBytes(void* output, size_t output_length, bool avoid_allocation) { +void RandBytes(span<uint8_t> output, bool avoid_allocation) { #if !BUILDFLAG(IS_NACL) // The BoringSSL experiment takes priority over everything else. if (!avoid_allocation && internal::UseBoringSSLForRandBytes()) { // Ensure BoringSSL is initialized so it can use things like RDRAND. CRYPTO_library_init(); // BoringSSL's RAND_bytes always returns 1. Any error aborts the program. - (void)RAND_bytes(static_cast<uint8_t*>(output), output_length); + (void)RAND_bytes(output.data(), output.size()); return; } #endif @@ -194,13 +195,14 @@ // support for a syscall before calling. The same check is made on Linux and // ChromeOS to avoid making a syscall that predictably returns ENOSYS. static const bool kernel_has_support = KernelSupportsGetRandom(); - if (kernel_has_support && GetRandomSyscall(output, output_length)) + if (kernel_has_support && GetRandomSyscall(output.data(), output.size())) { return; + } } #elif BUILDFLAG(IS_MAC) // TODO(crbug.com/995996): Enable this on iOS too, when sys/random.h arrives // in its SDK. - if (getentropy(output, output_length) == 0) { + if (getentropy(output.data(), output.size()) == 0) { return; } #endif @@ -211,8 +213,7 @@ // TODO(crbug.com/995996): When we no longer need to support old Linux // kernels, we can get rid of this /dev/urandom branch altogether. const int urandom_fd = GetUrandomFD(); - const bool success = ReadFromFD( - urandom_fd, make_span(static_cast<char*>(output), output_length)); + const bool success = ReadFromFD(urandom_fd, as_writable_chars(output)); CHECK(success); } @@ -222,15 +223,20 @@ double RandDoubleAvoidAllocation() { uint64_t number; - RandBytes(&number, sizeof(number), /*avoid_allocation=*/true); + RandBytes(as_writable_bytes(make_span(&number, 1u)), + /*avoid_allocation=*/true); // This transformation is explained in rand_util.cc. return (number >> 11) * 0x1.0p-53; } } // namespace internal +void RandBytes(span<uint8_t> output) { + RandBytes(output, /*avoid_allocation=*/false); +} + void RandBytes(void* output, size_t output_length) { - RandBytes(output, output_length, /*avoid_allocation=*/false); + RandBytes(make_span(reinterpret_cast<uint8_t*>(output), output_length)); } int GetUrandomFD() {
diff --git a/base/rand_util_unittest.cc b/base/rand_util_unittest.cc index e4b0491..7c731b2 100644 --- a/base/rand_util_unittest.cc +++ b/base/rand_util_unittest.cc
@@ -13,6 +13,7 @@ #include <memory> #include <vector> +#include "base/containers/span.h" #include "base/logging.h" #include "base/time/time.h" #include "testing/gtest/include/gtest/gtest.h" @@ -121,9 +122,9 @@ TEST(RandUtilTest, RandBytes) { const size_t buffer_size = 50; - char buffer[buffer_size]; + uint8_t buffer[buffer_size]; memset(buffer, 0, buffer_size); - base::RandBytes(buffer, buffer_size); + base::RandBytes(buffer); std::sort(buffer, buffer + buffer_size); // Probability of occurrence of less than 25 unique bytes in 50 random bytes // is below 10^-25. @@ -132,6 +133,7 @@ // Verify that calling base::RandBytes with an empty buffer doesn't fail. TEST(RandUtilTest, RandBytes0) { + base::RandBytes(span<uint8_t>()); base::RandBytes(nullptr, 0); } @@ -256,7 +258,7 @@ std::unique_ptr<uint8_t[]> buffer(new uint8_t[kTestBufferSize]); const base::TimeTicks now = base::TimeTicks::Now(); for (int i = 0; i < kTestIterations; ++i) - base::RandBytes(buffer.get(), kTestBufferSize); + base::RandBytes(make_span(buffer.get(), kTestBufferSize)); const base::TimeTicks end = base::TimeTicks::Now(); LOG(INFO) << "RandBytes(" << kTestBufferSize
diff --git a/base/rand_util_win.cc b/base/rand_util_win.cc index 549f4362..6aae763 100644 --- a/base/rand_util_win.cc +++ b/base/rand_util_win.cc
@@ -65,32 +65,39 @@ return process_prng_fn; } -void RandBytes(void* output, size_t output_length, bool avoid_allocation) { +void RandBytes(span<uint8_t> output, bool avoid_allocation) { if (!avoid_allocation && internal::UseBoringSSLForRandBytes()) { // Ensure BoringSSL is initialized so it can use things like RDRAND. CRYPTO_library_init(); // BoringSSL's RAND_bytes always returns 1. Any error aborts the program. - (void)RAND_bytes(static_cast<uint8_t*>(output), output_length); + (void)RAND_bytes(output.data(), output.size()); return; } static decltype(&ProcessPrng) process_prng_fn = GetProcessPrng(); - BOOL success = process_prng_fn(static_cast<BYTE*>(output), output_length); + BOOL success = + process_prng_fn(static_cast<BYTE*>(output.data()), output.size()); // ProcessPrng is documented to always return TRUE. CHECK(success); } } // namespace +void RandBytes(span<uint8_t> output) { + RandBytes(output, /*avoid_allocation=*/false); +} + void RandBytes(void* output, size_t output_length) { - RandBytes(output, output_length, /*avoid_allocation=*/false); + RandBytes(make_span(reinterpret_cast<uint8_t*>(output), output_length), + /*avoid_allocation=*/false); } namespace internal { double RandDoubleAvoidAllocation() { uint64_t number; - RandBytes(&number, sizeof(number), /*avoid_allocation=*/true); + RandBytes(as_writable_bytes(make_span(&number, 1u)), + /*avoid_allocation=*/true); // This transformation is explained in rand_util.cc. return (number >> 11) * 0x1.0p-53; }
diff --git a/base/stack_canary_linux.cc b/base/stack_canary_linux.cc index 8fc5297..ace6c11 100644 --- a/base/stack_canary_linux.cc +++ b/base/stack_canary_linux.cc
@@ -65,7 +65,7 @@ void NO_STACK_PROTECTOR ResetStackCanaryIfPossible() { uintptr_t canary; - base::RandBytes(&canary, sizeof(canary)); + base::RandBytes(as_writable_bytes(make_span(&canary, 1u))); // First byte should be the null byte for string functions. canary &= ~static_cast<uintptr_t>(0xff);
diff --git a/base/task/thread_pool/delayed_task_manager.cc b/base/task/thread_pool/delayed_task_manager.cc index 9971868..7be6bb0 100644 --- a/base/task/thread_pool/delayed_task_manager.cc +++ b/base/task/thread_pool/delayed_task_manager.cc
@@ -21,13 +21,9 @@ DelayedTaskManager::DelayedTask::DelayedTask() = default; -DelayedTaskManager::DelayedTask::DelayedTask( - Task task, - PostTaskNowCallback callback, - scoped_refptr<TaskRunner> task_runner) - : task(std::move(task)), - callback(std::move(callback)), - task_runner(std::move(task_runner)) {} +DelayedTaskManager::DelayedTask::DelayedTask(Task task, + PostTaskNowCallback callback) + : task(std::move(task)), callback(std::move(callback)) {} DelayedTaskManager::DelayedTask::DelayedTask( DelayedTaskManager::DelayedTask&& other) = default; @@ -84,8 +80,7 @@ void DelayedTaskManager::AddDelayedTask( Task task, - PostTaskNowCallback post_task_now_callback, - scoped_refptr<TaskRunner> task_runner) { + PostTaskNowCallback post_task_now_callback) { DCHECK(task.task); DCHECK(!task.delayed_run_time.is_null()); DCHECK(!task.queue_time.is_null()); @@ -103,9 +98,8 @@ auto [old_process_ripe_tasks_time, old_delay_policy] = GetTimeAndDelayPolicyToScheduleProcessRipeTasksLockRequired(); - delayed_task_queue_.insert(DelayedTask(std::move(task), - std::move(post_task_now_callback), - std::move(task_runner))); + delayed_task_queue_.insert( + DelayedTask(std::move(task), std::move(post_task_now_callback))); // Not started or already shutdown. if (service_thread_task_runner_ == nullptr) return;
diff --git a/base/task/thread_pool/delayed_task_manager.h b/base/task/thread_pool/delayed_task_manager.h index 79e45d2..d000053 100644 --- a/base/task/thread_pool/delayed_task_manager.h +++ b/base/task/thread_pool/delayed_task_manager.h
@@ -50,11 +50,8 @@ void Start(scoped_refptr<SequencedTaskRunner> service_thread_task_runner); // Schedules a call to |post_task_now_callback| with |task| as argument when - // |task| is ripe for execution. |task_runner| is passed to retain a - // reference until |task| is ripe. - void AddDelayedTask(Task task, - PostTaskNowCallback post_task_now_callback, - scoped_refptr<TaskRunner> task_runner); + // |task| is ripe for execution. + void AddDelayedTask(Task task, PostTaskNowCallback post_task_now_callback); // Pop and post all the ripe tasks in the delayed task queue. void ProcessRipeTasks(); @@ -73,9 +70,7 @@ private: struct DelayedTask { DelayedTask(); - DelayedTask(Task task, - PostTaskNowCallback callback, - scoped_refptr<TaskRunner> task_runner); + DelayedTask(Task task, PostTaskNowCallback callback); DelayedTask(DelayedTask&& other); DelayedTask(const DelayedTask&) = delete; DelayedTask& operator=(const DelayedTask&) = delete; @@ -89,7 +84,6 @@ Task task; PostTaskNowCallback callback; - scoped_refptr<TaskRunner> task_runner; // Mark the delayed task as scheduled. Since the sort key is // |task.delayed_run_time|, it does not alter sort order when it is called.
diff --git a/base/task/thread_pool/delayed_task_manager_unittest.cc b/base/task/thread_pool/delayed_task_manager_unittest.cc index 70f5fe85..6fa4b6a 100644 --- a/base/task/thread_pool/delayed_task_manager_unittest.cc +++ b/base/task/thread_pool/delayed_task_manager_unittest.cc
@@ -86,8 +86,8 @@ // Verify that a delayed task isn't forwarded before Start(). TEST_F(ThreadPoolDelayedTaskManagerTest, DelayedTaskDoesNotRunBeforeStart) { // Send |task| to the DelayedTaskManager. - delayed_task_manager_.AddDelayedTask(std::move(task_), BindOnce(&PostTaskNow), - nullptr); + delayed_task_manager_.AddDelayedTask(std::move(task_), + BindOnce(&PostTaskNow)); // Fast-forward time until the task is ripe for execution. Since Start() has // not been called, the task should not be forwarded to PostTaskNow() @@ -101,8 +101,8 @@ TEST_F(ThreadPoolDelayedTaskManagerTest, DelayedTaskPostedBeforeStartExpiresAfterStartRunsOnExpire) { // Send |task| to the DelayedTaskManager. - delayed_task_manager_.AddDelayedTask(std::move(task_), BindOnce(&PostTaskNow), - nullptr); + delayed_task_manager_.AddDelayedTask(std::move(task_), + BindOnce(&PostTaskNow)); delayed_task_manager_.Start(service_thread_task_runner_); @@ -121,8 +121,8 @@ TEST_F(ThreadPoolDelayedTaskManagerTest, DelayedTaskPostedBeforeStartExpiresBeforeStartRunsOnStart) { // Send |task| to the DelayedTaskManager. - delayed_task_manager_.AddDelayedTask(std::move(task_), BindOnce(&PostTaskNow), - nullptr); + delayed_task_manager_.AddDelayedTask(std::move(task_), + BindOnce(&PostTaskNow)); // Run tasks on the service thread. Don't expect any forwarding to // |task_target_| since the task isn't ripe for execution. @@ -145,8 +145,8 @@ delayed_task_manager_.Start(service_thread_task_runner_); // Send |task| to the DelayedTaskManager. - delayed_task_manager_.AddDelayedTask(std::move(task_), BindOnce(&PostTaskNow), - nullptr); + delayed_task_manager_.AddDelayedTask(std::move(task_), + BindOnce(&PostTaskNow)); // Run tasks that are ripe for execution. Don't expect any forwarding to // PostTaskNow(). @@ -159,8 +159,8 @@ delayed_task_manager_.Start(service_thread_task_runner_); // Send |task| to the DelayedTaskManager. - delayed_task_manager_.AddDelayedTask(std::move(task_), BindOnce(&PostTaskNow), - nullptr); + delayed_task_manager_.AddDelayedTask(std::move(task_), + BindOnce(&PostTaskNow)); // Fast-forward time. Expect the task to be forwarded to PostTaskNow(). EXPECT_CALL(mock_callback_, Run()); @@ -182,8 +182,7 @@ base::subtle::DelayPolicy::kFlexiblePreferEarly); // Send |task| to the DelayedTaskManager. - delayed_task_manager_.AddDelayedTask(std::move(task), BindOnce(&PostTaskNow), - nullptr); + delayed_task_manager_.AddDelayedTask(std::move(task), BindOnce(&PostTaskNow)); // The task isn't forwarded before the earliest run time is reached. service_thread_task_runner_->FastForwardBy(kUnalignedLongDelay - kLeeway - @@ -210,11 +209,11 @@ auto post_cancelable_task_now = BindLambdaForTesting( [&](Task task) { post_cancelable_task_now_invoked = true; }); delayed_task_manager_.AddDelayedTask(std::move(cancelable_task), - post_cancelable_task_now, nullptr); + post_cancelable_task_now); // Add |task_| to the DelayedTaskManager with a long delay. - delayed_task_manager_.AddDelayedTask(std::move(task_), BindOnce(&PostTaskNow), - nullptr); + delayed_task_manager_.AddDelayedTask(std::move(task_), + BindOnce(&PostTaskNow)); // Cancel the cancelable task. cancelable_closure.Cancel(); @@ -247,11 +246,11 @@ // Send tasks to the DelayedTaskManager. delayed_task_manager_.AddDelayedTask(std::move(task_a), - BindOnce(&PostTaskNow), nullptr); + BindOnce(&PostTaskNow)); delayed_task_manager_.AddDelayedTask(std::move(task_b), - BindOnce(&PostTaskNow), nullptr); + BindOnce(&PostTaskNow)); delayed_task_manager_.AddDelayedTask(std::move(task_c), - BindOnce(&PostTaskNow), nullptr); + BindOnce(&PostTaskNow)); // Run tasks that are ripe for execution on the service thread. Don't expect // any call to PostTaskNow(). @@ -290,11 +289,11 @@ // Send tasks to the DelayedTaskManager. delayed_task_manager_.AddDelayedTask(std::move(task_a), - BindOnce(&PostTaskNow), nullptr); + BindOnce(&PostTaskNow)); EXPECT_EQ(base::subtle::DelayPolicy::kFlexibleNoSooner, delayed_task_manager_.TopTaskDelayPolicyForTesting()); delayed_task_manager_.AddDelayedTask(std::move(task_b), - BindOnce(&PostTaskNow), nullptr); + BindOnce(&PostTaskNow)); EXPECT_EQ(base::subtle::DelayPolicy::kPrecise, delayed_task_manager_.TopTaskDelayPolicyForTesting()); @@ -321,8 +320,7 @@ other_thread.task_runner()->PostTask(FROM_HERE, BindLambdaForTesting([&]() { delayed_task_manager_.AddDelayedTask( std::move(task_), - BindOnce(&PostTaskNow), - other_thread.task_runner()); + BindOnce(&PostTaskNow)); task_posted.Signal(); }));
diff --git a/base/task/thread_pool/job_task_source.cc b/base/task/thread_pool/job_task_source.cc index 8f1cc1f4..1b70c2e 100644 --- a/base/task/thread_pool/job_task_source.cc +++ b/base/task/thread_pool/job_task_source.cc
@@ -127,7 +127,7 @@ RepeatingCallback<void(JobDelegate*)> worker_task, MaxConcurrencyCallback max_concurrency_callback, PooledTaskRunnerDelegate* delegate) - : JobTaskSource(traits, nullptr, TaskSourceExecutionMode::kJob), + : JobTaskSource(traits, TaskSourceExecutionMode::kJob), max_concurrency_callback_(std::move(max_concurrency_callback)), worker_task_(std::move(worker_task)), primary_task_(base::BindRepeating( @@ -154,7 +154,7 @@ } ExecutionEnvironment JobTaskSourceNew::GetExecutionEnvironment() { - return {SequenceToken::Create(), nullptr}; + return {SequenceToken::Create()}; } void JobTaskSourceNew::WillEnqueue(int sequence_num, TaskAnnotator& annotator) {
diff --git a/base/task/thread_pool/job_task_source_interface.h b/base/task/thread_pool/job_task_source_interface.h index 7d9a8c3..db65228 100644 --- a/base/task/thread_pool/job_task_source_interface.h +++ b/base/task/thread_pool/job_task_source_interface.h
@@ -43,9 +43,8 @@ protected: JobTaskSource(const TaskTraits& traits, - TaskRunner* task_runner, TaskSourceExecutionMode execution_mode) - : TaskSource(traits, task_runner, execution_mode) {} + : TaskSource(traits, execution_mode) {} ~JobTaskSource() override = default; };
diff --git a/base/task/thread_pool/job_task_source_old.cc b/base/task/thread_pool/job_task_source_old.cc index 1857fe8..5fb4856b 100644 --- a/base/task/thread_pool/job_task_source_old.cc +++ b/base/task/thread_pool/job_task_source_old.cc
@@ -93,7 +93,7 @@ RepeatingCallback<void(JobDelegate*)> worker_task, MaxConcurrencyCallback max_concurrency_callback, PooledTaskRunnerDelegate* delegate) - : JobTaskSource(traits, nullptr, TaskSourceExecutionMode::kJob), + : JobTaskSource(traits, TaskSourceExecutionMode::kJob), max_concurrency_callback_(std::move(max_concurrency_callback)), worker_task_(std::move(worker_task)), primary_task_(base::BindRepeating( @@ -116,7 +116,7 @@ } ExecutionEnvironment JobTaskSourceOld::GetExecutionEnvironment() { - return {SequenceToken::Create(), nullptr}; + return {SequenceToken::Create()}; } void JobTaskSourceOld::WillEnqueue(int sequence_num, TaskAnnotator& annotator) {
diff --git a/base/task/thread_pool/pooled_parallel_task_runner.cc b/base/task/thread_pool/pooled_parallel_task_runner.cc index 23c18568..30fb11a 100644 --- a/base/task/thread_pool/pooled_parallel_task_runner.cc +++ b/base/task/thread_pool/pooled_parallel_task_runner.cc
@@ -28,7 +28,7 @@ // Post the task as part of a one-off single-task Sequence. scoped_refptr<Sequence> sequence = MakeRefCounted<Sequence>( - traits_, this, TaskSourceExecutionMode::kParallel); + traits_, nullptr, TaskSourceExecutionMode::kParallel); return pooled_task_runner_delegate_->PostTaskWithSequence( Task(from_here, std::move(closure), TimeTicks::Now(), delay),
diff --git a/base/task/thread_pool/pooled_single_thread_task_runner_manager.cc b/base/task/thread_pool/pooled_single_thread_task_runner_manager.cc index b89334d..3f73be4 100644 --- a/base/task/thread_pool/pooled_single_thread_task_runner_manager.cc +++ b/base/task/thread_pool/pooled_single_thread_task_runner_manager.cc
@@ -177,7 +177,11 @@ TimeDelta GetSleepTimeout() override { return TimeDelta::Max(); } - bool PostTaskNow(scoped_refptr<Sequence> sequence, Task task) { + // `task_runner` isn't used but is forwarded to keep the task runner + // alive while the task is pending. + bool PostTaskNow(scoped_refptr<Sequence> sequence, + scoped_refptr<SingleThreadTaskRunner> task_runner, + Task task) { auto transaction = sequence->BeginTransaction(); // |task| will be pushed to |sequence|, and |sequence| will be queued @@ -538,15 +542,15 @@ } if (task.delayed_run_time.is_null()) - return GetDelegate()->PostTaskNow(sequence_, std::move(task)); + return GetDelegate()->PostTaskNow(sequence_, nullptr, std::move(task)); // Unretained(GetDelegate()) is safe because this TaskRunner and its // worker are kept alive as long as there are pending Tasks. outer_->delayed_task_manager_->AddDelayedTask( std::move(task), BindOnce(IgnoreResult(&WorkerThreadDelegate::PostTaskNow), - Unretained(GetDelegate()), sequence_), - this); + Unretained(GetDelegate()), sequence_, + base::WrapRefCounted(this))); return true; }
diff --git a/base/task/thread_pool/sequence.cc b/base/task/thread_pool/sequence.cc index 14c9b8c8c..9ff5e35 100644 --- a/base/task/thread_pool/sequence.cc +++ b/base/task/thread_pool/sequence.cc
@@ -330,9 +330,9 @@ } Sequence::Sequence(const TaskTraits& traits, - TaskRunner* task_runner, + SequencedTaskRunner* task_runner, TaskSourceExecutionMode execution_mode) - : TaskSource(traits, task_runner, execution_mode) {} + : TaskSource(traits, execution_mode), task_runner_(task_runner) {} Sequence::~Sequence() = default; @@ -341,7 +341,11 @@ } ExecutionEnvironment Sequence::GetExecutionEnvironment() { - return {token_, &sequence_local_storage_}; + if (execution_mode() == TaskSourceExecutionMode::kSingleThread) { + return {token_, &sequence_local_storage_, + static_cast<SingleThreadTaskRunner*>(task_runner())}; + } + return {token_, &sequence_local_storage_, task_runner()}; } bool Sequence::IsEmpty() const {
diff --git a/base/task/thread_pool/sequence.h b/base/task/thread_pool/sequence.h index 7bbc13b2..c8de9bb6 100644 --- a/base/task/thread_pool/sequence.h +++ b/base/task/thread_pool/sequence.h
@@ -85,7 +85,7 @@ // case |execution_mode| must be kParallel. Otherwise, |execution_mode| is the // execution mode of |task_runner|. Sequence(const TaskTraits& traits, - TaskRunner* task_runner, + SequencedTaskRunner* task_runner, TaskSourceExecutionMode execution_mode); Sequence(const Sequence&) = delete; Sequence& operator=(const Sequence&) = delete; @@ -115,6 +115,12 @@ bool is_immediate_for_testing() const { return is_immediate_; } bool IsEmptyForTesting() const NO_THREAD_SAFETY_ANALYSIS { return IsEmpty(); } + // A reference to TaskRunner is only retained between + // PushImmediateTask()/PushDelayedTask() and when DidProcessTask() returns + // false, guaranteeing it is safe to dereference this pointer. Otherwise, the + // caller should guarantee such TaskRunner still exists before dereferencing. + SequencedTaskRunner* task_runner() const { return task_runner_; } + private: ~Sequence() override; @@ -160,6 +166,15 @@ const SequenceToken token_ = SequenceToken::Create(); + // A pointer to the TaskRunner that posts to this TaskSource, if any. The + // derived class is responsible for calling AddRef() when a TaskSource from + // which no Task is executing becomes non-empty and Release() when + // it becomes empty again (e.g. when DidProcessTask() returns false). + // + // In practise, this pointer is going to become dangling. See task_runner() + // comment. + raw_ptr<SequencedTaskRunner, DisableDanglingPtrDetection> task_runner_; + // Queues of tasks to execute. base::queue<Task> queue_ GUARDED_BY(lock_); base::IntrusiveHeap<Task, DelayedTaskGreater> delayed_queue_
diff --git a/base/task/thread_pool/task_source.cc b/base/task/thread_pool/task_source.cc index 0b484c9e..315dcd1 100644 --- a/base/task/thread_pool/task_source.cc +++ b/base/task/thread_pool/task_source.cc
@@ -15,6 +15,8 @@ namespace base { namespace internal { +ExecutionEnvironment::~ExecutionEnvironment() = default; + TaskSource::Transaction::Transaction(TaskSource* task_source) : task_source_(task_source) { task_source->lock_.Acquire(); @@ -61,16 +63,10 @@ } TaskSource::TaskSource(const TaskTraits& traits, - TaskRunner* task_runner, TaskSourceExecutionMode execution_mode) : traits_(traits), priority_racy_(traits.priority()), - task_runner_(task_runner), - execution_mode_(execution_mode) { - DCHECK(task_runner_ || - execution_mode_ == TaskSourceExecutionMode::kParallel || - execution_mode_ == TaskSourceExecutionMode::kJob); -} + execution_mode_(execution_mode) {} TaskSource::~TaskSource() { // If this fails, a Transaction was likely held while releasing a reference to
diff --git a/base/task/thread_pool/task_source.h b/base/task/thread_pool/task_source.h index c6dd977..1d74a97e 100644 --- a/base/task/thread_pool/task_source.h +++ b/base/task/thread_pool/task_source.h
@@ -35,8 +35,27 @@ }; struct BASE_EXPORT ExecutionEnvironment { - SequenceToken token; - raw_ptr<SequenceLocalStorageMap> sequence_local_storage; + ExecutionEnvironment(SequenceToken token) : token(token) {} + + ExecutionEnvironment(SequenceToken token, + SequenceLocalStorageMap* sequence_local_storage, + SingleThreadTaskRunner* single_thread_task_runner) + : token(token), + sequence_local_storage(sequence_local_storage), + single_thread_task_runner(single_thread_task_runner) {} + + ExecutionEnvironment(SequenceToken token, + SequenceLocalStorageMap* sequence_local_storage, + SequencedTaskRunner* sequenced_task_runner) + : token(token), + sequence_local_storage(sequence_local_storage), + sequenced_task_runner(sequenced_task_runner) {} + ~ExecutionEnvironment(); + + const SequenceToken token; + const raw_ptr<SequenceLocalStorageMap> sequence_local_storage; + const raw_ptr<SingleThreadTaskRunner> single_thread_task_runner; + const raw_ptr<SequencedTaskRunner> sequenced_task_runner; }; // A TaskSource is a virtual class that provides a series of Tasks that must be @@ -137,12 +156,7 @@ }; // |traits| is metadata that applies to all Tasks in the TaskSource. - // |task_runner| is a reference to the TaskRunner feeding this TaskSource. - // |task_runner| can be nullptr only for tasks with no TaskRunner, in which - // case |execution_mode| must be kParallel. Otherwise, |execution_mode| is the - // execution mode of |task_runner|. TaskSource(const TaskTraits& traits, - TaskRunner* task_runner, TaskSourceExecutionMode execution_mode); TaskSource(const TaskSource&) = delete; TaskSource& operator=(const TaskSource&) = delete; @@ -201,12 +215,6 @@ // Transaction because it is never mutated. ThreadPolicy thread_policy() const { return traits_.thread_policy(); } - // A reference to TaskRunner is only retained between - // PushImmediateTask()/PushDelayedTask() and when DidProcessTask() returns - // false, guaranteeing it is safe to dereference this pointer. Otherwise, the - // caller should guarantee such TaskRunner still exists before dereferencing. - TaskRunner* task_runner() const { return task_runner_; } - TaskSourceExecutionMode execution_mode() const { return execution_mode_; } void ClearForTesting(); @@ -253,15 +261,6 @@ // protected by the DelayedPriorityQueue's lock. HeapHandle delayed_pq_heap_handle_; - // A pointer to the TaskRunner that posts to this TaskSource, if any. The - // derived class is responsible for calling AddRef() when a TaskSource from - // which no Task is executing becomes non-empty and Release() when - // it becomes empty again (e.g. when DidProcessTask() returns false). - // - // In practise, this pointer is going to become dangling. See task_runner() - // comment. - raw_ptr<TaskRunner, DisableDanglingPtrDetection> task_runner_; - TaskSourceExecutionMode execution_mode_; };
diff --git a/base/task/thread_pool/task_tracker.cc b/base/task/thread_pool/task_tracker.cc index edcbc19..88ca7092 100644 --- a/base/task/thread_pool/task_tracker.cc +++ b/base/task/thread_pool/task_tracker.cc
@@ -408,6 +408,7 @@ } if (should_run_tasks) AfterRunTask(task_source->shutdown_behavior()); + const bool task_source_must_be_queued = task_source.DidProcessTask(); // |task_source| should be reenqueued iff requested by DidProcessTask(). if (task_source_must_be_queued) @@ -474,20 +475,21 @@ sequenced_task_runner_current_default_handle; absl::optional<SingleThreadTaskRunner::CurrentDefaultHandle> single_thread_task_runner_current_default_handle; - switch (task_source->execution_mode()) { - case TaskSourceExecutionMode::kJob: - case TaskSourceExecutionMode::kParallel: - break; - case TaskSourceExecutionMode::kSequenced: - DCHECK(task_source->task_runner()); - sequenced_task_runner_current_default_handle.emplace( - static_cast<SequencedTaskRunner*>(task_source->task_runner())); - break; - case TaskSourceExecutionMode::kSingleThread: - DCHECK(task_source->task_runner()); - single_thread_task_runner_current_default_handle.emplace( - static_cast<SingleThreadTaskRunner*>(task_source->task_runner())); - break; + if (environment.sequenced_task_runner) { + DCHECK_EQ(TaskSourceExecutionMode::kSequenced, + task_source->execution_mode()); + sequenced_task_runner_current_default_handle.emplace( + environment.sequenced_task_runner.get()); + } else if (environment.single_thread_task_runner) { + DCHECK_EQ(TaskSourceExecutionMode::kSingleThread, + task_source->execution_mode()); + single_thread_task_runner_current_default_handle.emplace( + environment.single_thread_task_runner.get()); + } else { + DCHECK_NE(TaskSourceExecutionMode::kSequenced, + task_source->execution_mode()); + DCHECK_NE(TaskSourceExecutionMode::kSingleThread, + task_source->execution_mode()); } RunTaskWithShutdownBehavior(task, traits, task_source, environment.token);
diff --git a/base/task/thread_pool/task_tracker_unittest.cc b/base/task/thread_pool/task_tracker_unittest.cc index d2795a98..729a712 100644 --- a/base/task/thread_pool/task_tracker_unittest.cc +++ b/base/task/thread_pool/task_tracker_unittest.cc
@@ -540,7 +540,7 @@ TaskTracker* tracker, Task verify_task, TaskTraits traits, - scoped_refptr<TaskRunner> task_runner, + scoped_refptr<SequencedTaskRunner> task_runner, TaskSourceExecutionMode execution_mode) { // Pretend |verify_task| is posted to respect TaskTracker's contract. EXPECT_TRUE(tracker->WillPostTask(&verify_task, traits.shutdown_behavior()));
diff --git a/base/task/thread_pool/test_utils.cc b/base/task/thread_pool/test_utils.cc index f3c1e78c..effc1ed 100644 --- a/base/task/thread_pool/test_utils.cc +++ b/base/task/thread_pool/test_utils.cc
@@ -106,7 +106,7 @@ scoped_refptr<Sequence> CreateSequenceWithTask( Task task, const TaskTraits& traits, - scoped_refptr<TaskRunner> task_runner, + scoped_refptr<SequencedTaskRunner> task_runner, TaskSourceExecutionMode execution_mode) { scoped_refptr<Sequence> sequence = MakeRefCounted<Sequence>(traits, task_runner.get(), execution_mode); @@ -186,12 +186,12 @@ std::move(task), BindOnce( [](scoped_refptr<Sequence> sequence, - MockPooledTaskRunnerDelegate* self, Task task) { + MockPooledTaskRunnerDelegate* self, + scoped_refptr<TaskRunner> task_runner, Task task) { self->PostTaskWithSequenceNow(std::move(task), std::move(sequence)); }, - std::move(sequence), Unretained(this)), - std::move(task_runner)); + std::move(sequence), Unretained(this), std::move(task_runner))); } return true;
diff --git a/base/task/thread_pool/test_utils.h b/base/task/thread_pool/test_utils.h index 78eac67..94311134 100644 --- a/base/task/thread_pool/test_utils.h +++ b/base/task/thread_pool/test_utils.h
@@ -122,7 +122,7 @@ scoped_refptr<Sequence> CreateSequenceWithTask( Task task, const TaskTraits& traits, - scoped_refptr<TaskRunner> task_runner = nullptr, + scoped_refptr<SequencedTaskRunner> task_runner = nullptr, TaskSourceExecutionMode execution_mode = TaskSourceExecutionMode::kParallel);
diff --git a/base/task/thread_pool/thread_pool_impl.cc b/base/task/thread_pool/thread_pool_impl.cc index cea0c79..9606312 100644 --- a/base/task/thread_pool/thread_pool_impl.cc +++ b/base/task/thread_pool/thread_pool_impl.cc
@@ -445,12 +445,12 @@ std::move(task), BindOnce( [](scoped_refptr<Sequence> sequence, - ThreadPoolImpl* thread_pool_impl, Task task) { + ThreadPoolImpl* thread_pool_impl, scoped_refptr<TaskRunner>, + Task task) { thread_pool_impl->PostTaskWithSequenceNow(std::move(task), std::move(sequence)); }, - std::move(sequence), Unretained(this)), - std::move(task_runner)); + std::move(sequence), Unretained(this), std::move(task_runner))); } return true;
diff --git a/base/timer/mock_timer_unittest.cc b/base/timer/mock_timer_unittest.cc index 1c05bd3..1c2d6b9 100644 --- a/base/timer/mock_timer_unittest.cc +++ b/base/timer/mock_timer_unittest.cc
@@ -64,7 +64,7 @@ EXPECT_EQ(1, calls); } -class HasWeakPtr : public base::SupportsWeakPtr<HasWeakPtr> { +class HasWeakPtr { public: HasWeakPtr() = default; @@ -72,6 +72,13 @@ HasWeakPtr& operator=(const HasWeakPtr&) = delete; virtual ~HasWeakPtr() = default; + + base::WeakPtr<HasWeakPtr> AsWeakPtr() { + return weak_ptr_factory_.GetWeakPtr(); + } + + private: + base::WeakPtrFactory<HasWeakPtr> weak_ptr_factory_{this}; }; TEST(MockTimerTest, DoesNotRetainClosure) {
diff --git a/base/tracing/protos/chrome_track_event.proto b/base/tracing/protos/chrome_track_event.proto index a4ababe3..c2492dd 100644 --- a/base/tracing/protos/chrome_track_event.proto +++ b/base/tracing/protos/chrome_track_event.proto
@@ -749,7 +749,7 @@ TASK_TYPE_INTERNAL_NAVIGATION_CANCELLATION = 80; TASK_TYPE_LOW_PRIORITY_SCRIPT_EXECUTION = 81; TASK_TYPE_STORAGE = 82; - TASK_TYPE_NETWORKING_UNFREEZABLE_IMAGE_LOADING = 83; + TASK_TYPE_NETWORKING_UNFREEZABLE_RENDER_BLOCKING_LOADING = 83; TASK_TYPE_MAIN_THREAD_TASK_QUEUE_V8_LOW_PRIORITY = 84; TASK_TYPE_CLIPBOARD = 85; }
diff --git a/base/uuid.cc b/base/uuid.cc index 156dffa5..84173211 100644 --- a/base/uuid.cc +++ b/base/uuid.cc
@@ -9,6 +9,7 @@ #include <ostream> +#include "base/containers/span.h" #include "base/hash/hash.h" #include "base/rand_util.h" #include "base/strings/string_util.h" @@ -67,7 +68,7 @@ uint8_t sixteen_bytes[kGuidV4InputLength]; // Use base::RandBytes instead of crypto::RandBytes, because crypto calls the // base version directly, and to prevent the dependency from base/ to crypto/. - RandBytes(&sixteen_bytes, sizeof(sixteen_bytes)); + RandBytes(sixteen_bytes); return FormatRandomDataAsV4Impl(sixteen_bytes); }
diff --git a/build/config/fuchsia/test/context_provider.shard.test-cml b/build/config/fuchsia/test/context_provider.shard.test-cml index a1bf40a..e5db2f1f 100644 --- a/build/config/fuchsia/test/context_provider.shard.test-cml +++ b/build/config/fuchsia/test/context_provider.shard.test-cml
@@ -26,10 +26,5 @@ from: "parent", to: "#context_provider", }, - { - directory: "tzdata-icu", - from: "parent", - to: "#context_provider", - }, ], }
diff --git a/build/install-build-deps.py b/build/install-build-deps.py index a38ad22e..3d3cdaf 100755 --- a/build/install-build-deps.py +++ b/build/install-build-deps.py
@@ -374,8 +374,6 @@ "libxrender1", "libxtst6", "x11-utils", - "xserver-xorg-core", # TODO(crbug.com/1417069): Experimental. - "xserver-xorg-video-dummy", # TODO(crbug.com/1417069): Experimental. "xvfb", "zlib1g", ]
diff --git a/cc/layers/heads_up_display_layer_impl.cc b/cc/layers/heads_up_display_layer_impl.cc index c7d3283..cb2f808 100644 --- a/cc/layers/heads_up_display_layer_impl.cc +++ b/cc/layers/heads_up_display_layer_impl.cc
@@ -9,10 +9,10 @@ #include <algorithm> #include <iomanip> +#include <optional> #include <utility> #include <vector> -#include <optional> #include "base/logging.h" #include "base/memory/raw_ptr.h" #include "base/memory/shared_memory_mapping.h" @@ -53,6 +53,7 @@ #include "gpu/command_buffer/common/shared_image_trace_utils.h" #include "gpu/command_buffer/common/shared_image_usage.h" #include "gpu/config/gpu_feature_info.h" +#include "gpu/ipc/client/client_shared_image_interface.h" #include "skia/ext/legacy_display_globals.h" #include "third_party/skia/include/core/SkFont.h" #include "third_party/skia/include/core/SkPaint.h" @@ -61,6 +62,7 @@ #include "third_party/skia/include/core/SkTextBlob.h" #include "third_party/skia/include/core/SkTypeface.h" #include "third_party/skia/include/gpu/GrDirectContext.h" +#include "ui/gfx/buffer_format_util.h" #include "ui/gfx/geometry/point.h" #include "ui/gfx/geometry/size.h" #include "ui/gfx/geometry/size_conversions.h" @@ -176,7 +178,14 @@ class HudSoftwareBacking : public ResourcePool::SoftwareBacking { public: ~HudSoftwareBacking() override { - layer_tree_frame_sink->DidDeleteSharedBitmap(shared_bitmap_id); + if (shared_image) { + auto* sii = layer_tree_frame_sink->shared_image_interface(); + if (sii) { + sii->DestroySharedImage(mailbox_sync_token, std::move(shared_image)); + } + } else { + layer_tree_frame_sink->DidDeleteSharedBitmap(shared_bitmap_id); + } } void OnMemoryDump( @@ -321,23 +330,58 @@ } else { DCHECK_EQ(draw_mode, DRAW_MODE_SOFTWARE); - pool_resource = pool_->AcquireResource(internal_content_bounds_, - viz::SinglePlaneFormat::kRGBA_8888, - gfx::ColorSpace()); + auto* sii = layer_tree_frame_sink->shared_image_interface(); + if (sii) { + pool_resource = pool_->AcquireResource(internal_content_bounds_, + viz::SinglePlaneFormat::kBGRA_8888, + gfx::ColorSpace()); - if (!pool_resource.software_backing()) { - auto backing = std::make_unique<HudSoftwareBacking>(); - backing->layer_tree_frame_sink = layer_tree_frame_sink; - backing->shared_bitmap_id = viz::SharedBitmap::GenerateId(); - base::MappedReadOnlyRegion shm = - viz::bitmap_allocation::AllocateSharedBitmap(pool_resource.size(), - pool_resource.format()); - backing->shared_mapping = std::move(shm.mapping); + if (!pool_resource.software_backing()) { + auto backing = std::make_unique<HudSoftwareBacking>(); + backing->layer_tree_frame_sink = layer_tree_frame_sink; - layer_tree_frame_sink->DidAllocateSharedBitmap(std::move(shm.region), - backing->shared_bitmap_id); + const size_t buffer_size = gfx::BufferSizeForBufferFormat( + pool_resource.size(), gfx::BufferFormat::BGRA_8888); + auto shared_memory_region = + base::UnsafeSharedMemoryRegion::Create(buffer_size); + backing->shared_mapping = shared_memory_region.Map(); + CHECK(shared_memory_region.IsValid() && + backing->shared_mapping.IsValid()); - pool_resource.set_software_backing(std::move(backing)); + gfx::GpuMemoryBufferHandle handle; + handle.type = gfx::SHARED_MEMORY_BUFFER; + handle.offset = 0; + handle.stride = static_cast<int32_t>(gfx::RowSizeForBufferFormat( + pool_resource.size().width(), gfx::BufferFormat::BGRA_8888, 0)); + handle.region = std::move(shared_memory_region); + + backing->shared_image = sii->CreateSharedImage( + pool_resource.format(), pool_resource.size(), + pool_resource.color_space(), kTopLeft_GrSurfaceOrigin, + kPremul_SkAlphaType, gpu::SHARED_IMAGE_USAGE_CPU_WRITE, + "HeadsUpDisplayLayer", std::move(handle)); + CHECK(backing->shared_image); + + pool_resource.set_software_backing(std::move(backing)); + } + + } else { + pool_resource = pool_->AcquireResource(internal_content_bounds_, + viz::SinglePlaneFormat::kRGBA_8888, + gfx::ColorSpace()); + if (!pool_resource.software_backing()) { + auto backing = std::make_unique<HudSoftwareBacking>(); + backing->layer_tree_frame_sink = layer_tree_frame_sink; + backing->shared_bitmap_id = viz::SharedBitmap::GenerateId(); + base::MappedReadOnlyRegion shm = + viz::bitmap_allocation::AllocateSharedBitmap( + pool_resource.size(), pool_resource.format()); + backing->shared_mapping = std::move(shm.mapping); + + layer_tree_frame_sink->DidAllocateSharedBitmap( + std::move(shm.region), backing->shared_bitmap_id); + pool_resource.set_software_backing(std::move(backing)); + } } } @@ -421,6 +465,12 @@ SkiaPaintCanvas canvas(surface->getCanvas()); DrawHudContents(&canvas); + + if (backing->shared_image) { + backing->mailbox_sync_token = + layer_tree_frame_sink->shared_image_interface() + ->GenVerifiedSyncToken(); + } } // Exports the backing to the ResourceProvider, giving it a ResourceId that
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/IncognitoReauthPromoMessageService.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/IncognitoReauthPromoMessageService.java index 0fb55ad..5a6e57e 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/IncognitoReauthPromoMessageService.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/IncognitoReauthPromoMessageService.java
@@ -355,8 +355,7 @@ * A method which gets fired when the re-authentication was successful after the review action. */ private void onAfterReviewActionSuccessful() { - UserPrefs.get(Profile.getLastUsedRegularProfile()) - .setBoolean(Pref.INCOGNITO_REAUTHENTICATION_FOR_ANDROID, true); + UserPrefs.get(mProfile).setBoolean(Pref.INCOGNITO_REAUTHENTICATION_FOR_ANDROID, true); RecordHistogram.recordEnumeratedHistogram( "Android.IncognitoReauth.PromoAcceptedOrDismissed", IncognitoReauthPromoActionType.PROMO_ACCEPTED,
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/IncognitoTabSwitcherPane.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/IncognitoTabSwitcherPane.java index 0f6c34d..1aa1271 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/IncognitoTabSwitcherPane.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/IncognitoTabSwitcherPane.java
@@ -17,6 +17,7 @@ import org.chromium.chrome.browser.hub.FullButtonData; import org.chromium.chrome.browser.hub.HubColorScheme; import org.chromium.chrome.browser.hub.Pane; +import org.chromium.chrome.browser.hub.PaneHubController; import org.chromium.chrome.browser.hub.PaneId; import org.chromium.chrome.browser.hub.ResourceButtonData; import org.chromium.chrome.browser.incognito.reauth.IncognitoReauthController; @@ -40,6 +41,13 @@ @Override public void didBecomeEmpty() { mReferenceButtonDataSupplier.set(null); + if (isFocused()) { + @Nullable PaneHubController controller = getPaneHubController(); + assert controller != null + : "isFocused requires a non-null PaneHubController."; + controller.focusPane(PaneId.TAB_SWITCHER); + } + resetWithTabList(null, false); } };
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/IncognitoTabSwitcherPaneUnitTest.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/IncognitoTabSwitcherPaneUnitTest.java index b34a96f..ec657254 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/IncognitoTabSwitcherPaneUnitTest.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/IncognitoTabSwitcherPaneUnitTest.java
@@ -40,11 +40,13 @@ import org.mockito.junit.MockitoRule; import org.robolectric.shadows.ShadowLooper; +import org.chromium.base.Callback; import org.chromium.base.supplier.OneshotSupplierImpl; import org.chromium.base.test.BaseRobolectricTestRunner; import org.chromium.chrome.browser.hub.DisplayButtonData; import org.chromium.chrome.browser.hub.FullButtonData; import org.chromium.chrome.browser.hub.LoadHint; +import org.chromium.chrome.browser.hub.PaneHubController; import org.chromium.chrome.browser.hub.PaneId; import org.chromium.chrome.browser.incognito.reauth.IncognitoReauthController; import org.chromium.chrome.browser.incognito.reauth.IncognitoReauthManager.IncognitoReauthCallback; @@ -68,9 +70,11 @@ @Mock private TabModelFilter mTabModelFilter; @Mock private IncognitoTabModel mIncognitoTabModel; @Mock private MenuOrKeyboardActionController mMenuOrKeyboardActionController; + @Mock private PaneHubController mPaneHubController; @Captor private ArgumentCaptor<IncognitoTabModelObserver> mIncognitoTabModelObserverCaptor; @Captor private ArgumentCaptor<IncognitoReauthCallback> mIncognitoReauthCallbackCaptor; + @Captor private ArgumentCaptor<Callback<Integer>> mOnTabClickedCallbackCaptor; private final OneshotSupplierImpl<IncognitoReauthController> mIncognitoReauthControllerSupplier = new OneshotSupplierImpl<>(); @@ -88,7 +92,13 @@ return mTabSwitcherPaneCoordinator; }) .when(mTabSwitcherPaneCoordinatorFactory) - .create(any(), any(), any(), any(), anyBoolean()); + .create( + any(), + any(), + any(), + any(), + mOnTabClickedCallbackCaptor.capture(), + anyBoolean()); when(mTabModelFilter.getTabModel()).thenReturn(mIncognitoTabModel); @@ -302,10 +312,17 @@ } private void checkIncognitoTabModelObserverAndButtonData() { + mIncognitoTabSwitcherPane.createTabSwitcherPaneCoordinator(); + TabSwitcherPaneCoordinator coordinator = + mIncognitoTabSwitcherPane.getTabSwitcherPaneCoordinator(); + mIncognitoTabSwitcherPane.setPaneHubController(mPaneHubController); + IncognitoTabModelObserver observer = mIncognitoTabModelObserverCaptor.getValue(); observer.didBecomeEmpty(); assertNull(mIncognitoTabSwitcherPane.getReferenceButtonDataSupplier().get()); + verify(coordinator).resetWithTabList(null); + verify(mPaneHubController).focusPane(PaneId.TAB_SWITCHER); // TODO(crbug/1505772): These resources need to be updated. observer.wasFirstTabCreated(); @@ -321,5 +338,7 @@ observer.didBecomeEmpty(); assertNull(mIncognitoTabSwitcherPane.getReferenceButtonDataSupplier().get()); + verify(coordinator, times(2)).resetWithTabList(null); + verify(mPaneHubController, times(2)).focusPane(PaneId.TAB_SWITCHER); } }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/IphMessageService.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/IphMessageService.java index 2fd2c79..31e5067 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/IphMessageService.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/IphMessageService.java
@@ -55,10 +55,9 @@ } } - IphMessageService(TabSwitcherIphController controller) { + IphMessageService(Profile profile, TabSwitcherIphController controller) { super(MessageType.IPH); mIphController = controller; - Profile profile = Profile.getLastUsedRegularProfile().getOriginalProfile(); mTracker = TrackerFactory.getTrackerForProfile(profile); }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/PriceMessageService.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/PriceMessageService.java index 22a2b29..27c7d69 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/PriceMessageService.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/PriceMessageService.java
@@ -154,6 +154,7 @@ ? 2 : 1; + private final Profile mProfile; private final PriceWelcomeMessageProvider mPriceWelcomeMessageProvider; private final PriceWelcomeMessageReviewActionProvider mPriceWelcomeMessageReviewActionProvider; private final PriceDropNotificationManager mNotificationManager; @@ -161,10 +162,12 @@ private PriceTabData mPriceTabData; PriceMessageService( + Profile profile, PriceWelcomeMessageProvider priceWelcomeMessageProvider, PriceWelcomeMessageReviewActionProvider priceWelcomeMessageReviewActionProvider, PriceDropNotificationManager notificationManager) { super(MessageType.PRICE_MESSAGE); + mProfile = profile; mPriceTabData = null; mPriceWelcomeMessageProvider = priceWelcomeMessageProvider; mPriceWelcomeMessageReviewActionProvider = priceWelcomeMessageReviewActionProvider; @@ -176,11 +179,9 @@ */ boolean preparePriceMessage(@PriceMessageType int type, @Nullable PriceTabData priceTabData) { assert (type == PriceMessageType.PRICE_WELCOME - && PriceTrackingUtilities.isPriceWelcomeMessageCardEnabled( - Profile.getLastUsedRegularProfile())) + && PriceTrackingUtilities.isPriceWelcomeMessageCardEnabled(mProfile)) || (type == PriceMessageType.PRICE_ALERTS - && PriceTrackingUtilities.isPriceAlertsMessageCardEnabled( - Profile.getLastUsedRegularProfile())); + && PriceTrackingUtilities.isPriceAlertsMessageCardEnabled(mProfile)); if (type == PriceMessageType.PRICE_WELCOME) { PriceTrackingUtilities.increasePriceWelcomeMessageCardShowCount(); if (PriceTrackingUtilities.getPriceWelcomeMessageCardShowCount() @@ -193,8 +194,7 @@ // When PriceWelcomeMessageCard is available, it takes priority over // PriceAlertsMessageCard which will be removed first. This should be called only if // PriceAlertsMessageCard is currently enabled. - if (PriceTrackingUtilities.isPriceAlertsMessageCardEnabled( - Profile.getLastUsedRegularProfile())) { + if (PriceTrackingUtilities.isPriceAlertsMessageCardEnabled(mProfile)) { PriceTrackingUtilities.decreasePriceAlertsMessageCardShowCount(); } } else if (type == PriceMessageType.PRICE_ALERTS) {
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListEditorBookmarkAction.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListEditorBookmarkAction.java index 4809e2e..12235fed 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListEditorBookmarkAction.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListEditorBookmarkAction.java
@@ -80,8 +80,10 @@ @Override public void bookmarkTabsAndShowSnackbar( Activity activity, List<Tab> tabs, SnackbarManager snackbarManager) { - BookmarkModel bookmarkModel = - BookmarkModel.getForProfile(Profile.getLastUsedRegularProfile()); + if (tabs.isEmpty()) return; + + Profile profile = tabs.get(0).getProfile(); + BookmarkModel bookmarkModel = BookmarkModel.getForProfile(profile); bookmarkModel.finishLoadingBookmarkModel( () -> { BookmarkUtils.addBookmarksOnMultiSelect(
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSuggestionMessageService.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSuggestionMessageService.java index d3a70012..8b2c8ae 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSuggestionMessageService.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSuggestionMessageService.java
@@ -52,17 +52,14 @@ public class TabSuggestionMessageData implements MessageData { private final TabSuggestion mTabSuggestion; private final Callback<TabSuggestionFeedback> mTabSuggestionFeedback; - private Profile mProfile; private CustomMessageCardProvider mCustomMessageCardProvider; public TabSuggestionMessageData( TabSuggestion tabSuggestion, Callback<TabSuggestionFeedback> feedbackCallback, - Profile profile, CustomMessageCardProvider customMessageCardProvider) { mTabSuggestion = tabSuggestion; mTabSuggestionFeedback = feedbackCallback; - mProfile = profile; mCustomMessageCardProvider = customMessageCardProvider; } @@ -123,6 +120,7 @@ } private final Context mContext; + private final Profile mProfile; private final Supplier<TabModelFilter> mCurrentTabModelFilterSupplier; private final Supplier<TabListEditorCoordinator.TabListEditorController> mTabListEditorControllerSupplier; @@ -132,11 +130,13 @@ public TabSuggestionMessageService( Context context, + Profile profile, Supplier<TabModelFilter> currentTabModelFilterSupplier, Supplier<TabListEditorCoordinator.TabListEditorController> tabListEditorControllerSupplier) { super(MessageType.TAB_SUGGESTION); mContext = context; + mProfile = profile; mCurrentTabModelFilterSupplier = currentTabModelFilterSupplier; mTabListEditorControllerSupplier = tabListEditorControllerSupplier; mCustomMessageCardProvider = this; @@ -291,7 +291,6 @@ new TabSuggestionMessageData( tabSuggestion, tabSuggestionFeedback, - Profile.getLastUsedRegularProfile(), mCustomMessageCardProvider)); } }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMessageManager.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMessageManager.java index 07e8773d..26d3407 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMessageManager.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMessageManager.java
@@ -213,6 +213,7 @@ mTabSuggestionMessageService = new TabSuggestionMessageService( mContext, + profile, mCurrentTabModelFilterSupplier, mTabListEditorControllerSupplier::get); mTabSuggestionsOrchestrator.addObserver(mTabSuggestionMessageService); @@ -221,7 +222,8 @@ mTabGridIphDialogCoordinator = new TabGridIphDialogCoordinator(mContext, mContainer, mModalDialogManager); - IphMessageService iphMessageService = new IphMessageService(mTabGridIphDialogCoordinator); + IphMessageService iphMessageService = + new IphMessageService(profile, mTabGridIphDialogCoordinator); mMessageCardProviderCoordinator.subscribeMessageService(iphMessageService); if (IncognitoReauthManager.isIncognitoReauthFeatureAvailable() @@ -476,6 +478,7 @@ if (mPriceMessageService == null) { mPriceMessageService = new PriceMessageService( + mProfile, mTabListCoordinator, mPriceWelcomeMessageReviewActionProvider, notificationManager);
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneBase.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneBase.java index 08bccbeb..bbc60ed 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneBase.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneBase.java
@@ -31,6 +31,7 @@ import org.chromium.chrome.browser.hub.HubLayoutConstants; import org.chromium.chrome.browser.hub.LoadHint; import org.chromium.chrome.browser.hub.Pane; +import org.chromium.chrome.browser.hub.PaneHubController; import org.chromium.chrome.browser.tasks.pseudotab.PseudoTab; import org.chromium.chrome.browser.tasks.tab_management.TabListCoordinator.TabListMode; import org.chromium.chrome.tab_ui.R; @@ -88,6 +89,7 @@ private final boolean mIsIncognito; private boolean mNativeInitialized; + private @Nullable PaneHubController mPaneHubController; /** * @param context The activity context. @@ -122,11 +124,19 @@ } @Override + public void setPaneHubController(@Nullable PaneHubController paneHubController) { + mPaneHubController = paneHubController; + if (mPaneHubController != null) { + mMenuOrKeyboardActionController.registerMenuOrKeyboardActionHandler( + mMenuOrKeyboardActionHandler); + } else { + mMenuOrKeyboardActionController.unregisterMenuOrKeyboardActionHandler( + mMenuOrKeyboardActionHandler); + } + } + + @Override public void notifyLoadHint(@LoadHint int loadHint) { - // TODO(crbug/1502201): Figure out a more immediate signal for pane visibility. Due to - // WARM/COLD signals being posted this can lead to multiple HOT panes for a brief period. - // In this case multiple HOT panes might listen for the same menu event leading to a - // collision. boolean isVisible = loadHint == LoadHint.HOT; mIsVisibleSupplier.set(isVisible); @@ -134,8 +144,6 @@ if (isVisible) { createTabSwitcherPaneCoordinator(); - mMenuOrKeyboardActionController.registerMenuOrKeyboardActionHandler( - mMenuOrKeyboardActionHandler); showAllTabs(); setInitialScrollIndexOffset(); // TODO(crbug/1502201): This should only happen when the Pane becomes user visible which @@ -144,9 +152,6 @@ // need to know an animation is going to play and when it is finished (possibly using // the isAnimatingSupplier?). requestAccessibilityFocusOnCurrentTab(); - } else { - mMenuOrKeyboardActionController.unregisterMenuOrKeyboardActionHandler( - mMenuOrKeyboardActionHandler); } if (loadHint == LoadHint.WARM) { @@ -180,7 +185,7 @@ public @NonNull HubLayoutAnimatorProvider createShowHubLayoutAnimatorProvider( @NonNull HubContainerView hubContainerView) { assert !DeviceFormFactor.isNonMultiDisplayContextOnTablet(hubContainerView.getContext()); - // TODO(crbug/1505772): Replace with shrink animator and set animating supplier. + // TODO(crbug/1516949): Replace with shrink animator and set animating supplier. return FadeHubLayoutAnimationFactory.createFadeInAnimatorProvider( hubContainerView, HubLayoutConstants.FADE_DURATION_MS); } @@ -189,7 +194,7 @@ public @NonNull HubLayoutAnimatorProvider createHideHubLayoutAnimatorProvider( @NonNull HubContainerView hubContainerView) { assert !DeviceFormFactor.isNonMultiDisplayContextOnTablet(hubContainerView.getContext()); - // TODO(crbug/1505772): Replace with expand animator and set animating supplier. + // TODO(crbug/1516949): Replace with expand animator and set animating supplier. return FadeHubLayoutAnimationFactory.createFadeOutAnimatorProvider( hubContainerView, HubLayoutConstants.FADE_DURATION_MS); } @@ -289,6 +294,16 @@ return mIsVisibleSupplier.get(); } + /** Returns whether the pane is focused. */ + protected boolean isFocused() { + return mPaneHubController != null; + } + + /** Returns the PaneHubController if one exists or null otherwise. */ + protected @Nullable PaneHubController getPaneHubController() { + return mPaneHubController; + } + /** Returns the current {@link TabSwitcherPaneCoordinator} or null if one doesn't exist. */ @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) @Nullable @@ -308,6 +323,7 @@ /* resetHandler= */ this, mIsVisibleSupplier, mIsAnimatingSupplier, + this::onTabClick, mIsIncognito); mTabSwitcherPaneCoordinatorSupplier.set(coordinator); if (mNativeInitialized) { @@ -329,6 +345,15 @@ coordinator.destroy(); } + private void onTabClick(int tabId) { + if (mPaneHubController == null) return; + + // TODO(crbug/1516949): Consider using INVALID_TAB_ID if already selected to prevent a + // repeat selection. For now this is required to ensure the tab gets marked as shown when + // exiting the Hub. See if this can be updated/changed. + mPaneHubController.selectTabAndHideHub(tabId); + } + private void setInitialScrollIndexOffset() { TabSwitcherPaneCoordinator coordinator = mTabSwitcherPaneCoordinatorSupplier.get(); if (coordinator == null) return;
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneCoordinator.java index 8e394070..04677a3 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneCoordinator.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneCoordinator.java
@@ -87,6 +87,7 @@ * @param resetHandler The tab list reset handler for the pane. * @param isVisibleSupplier The supplier of the pane's visibility. * @param isAnimatingSupplier Whether the pane is animating into or out of view. + * @param onTabClickCallback Callback to invoke when a tab is clicked. * @param mode The {@link TabListMode} to use. */ public TabSwitcherPaneCoordinator( @@ -107,6 +108,7 @@ @NonNull TabSwitcherResetHandler resetHandler, @NonNull ObservableSupplier<Boolean> isVisibleSupplier, @NonNull ObservableSupplier<Boolean> isAnimatingSupplier, + @NonNull Callback<Integer> onTabClickCallback, @TabListMode int mode) { mProfileProviderSupplier = profileProviderSupplier; mSnackbarManager = snackbarManager; @@ -155,7 +157,8 @@ parentView, this::onTabSwitcherShown, isVisibleSupplier, - isAnimatingSupplier); + isAnimatingSupplier, + onTabClickCallback); mTabSwitcherCustomViewManager = new TabSwitcherCustomViewManager(mMediator); mMultiThumbnailCardProvider =
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneCoordinatorFactory.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneCoordinatorFactory.java index 8a35b77..c71ad7e 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneCoordinatorFactory.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneCoordinatorFactory.java
@@ -11,6 +11,7 @@ import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; +import org.chromium.base.Callback; import org.chromium.base.supplier.ObservableSupplier; import org.chromium.base.supplier.ObservableSupplierImpl; import org.chromium.base.supplier.OneshotSupplier; @@ -104,6 +105,7 @@ * @param resetHandler The reset handler to drive updates. * @param isVisibleSupplier Supplies visibility information to the tab switcher. * @param isAnimatingSupplier Supplies animation information to the tab switcher. + * @param onTabClickCallback Callback to be invoked with the tab ID of the selected tab. * @param isIncognito Whether this is for the incognito tab switcher. * @return a {@link TabSwitcherPaneCoordinator} to use. */ @@ -112,6 +114,7 @@ @NonNull TabSwitcherResetHandler resetHandler, @NonNull ObservableSupplier<Boolean> isVisibleSupplier, @NonNull ObservableSupplier<Boolean> isAnimatingSupplier, + @NonNull Callback<Integer> onTabClickCallback, boolean isIncognito) { return new TabSwitcherPaneCoordinator( mActivity, @@ -131,6 +134,7 @@ resetHandler, isVisibleSupplier, isAnimatingSupplier, + onTabClickCallback, mMode); }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneCoordinatorFactoryUnitTest.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneCoordinatorFactoryUnitTest.java index 54ad2bbe..ae73d86 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneCoordinatorFactoryUnitTest.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneCoordinatorFactoryUnitTest.java
@@ -29,6 +29,7 @@ import org.mockito.junit.MockitoRule; import org.chromium.base.BaseSwitches; +import org.chromium.base.Callback; import org.chromium.base.supplier.ObservableSupplierImpl; import org.chromium.base.supplier.OneshotSupplierImpl; import org.chromium.base.test.BaseRobolectricTestRunner; @@ -87,6 +88,7 @@ @Mock private SnackbarManager mSnackbarManager; @Mock private ModalDialogManager mModalDialogManager; @Mock private TabSwitcherResetHandler mResetHandler; + @Mock private Callback<Integer> mOnTabClickedCallback; @Captor private ArgumentCaptor<TabModelSelectorObserver> mTabModelSelectorObserverCaptor; @@ -135,6 +137,7 @@ mResetHandler, mIsVisibleSupplier, mIsAnimatingSupplier, + mOnTabClickedCallback, /* isIncognito= */ false)); }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneCoordinatorUnitTest.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneCoordinatorUnitTest.java index 848b1896..64a40ad 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneCoordinatorUnitTest.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneCoordinatorUnitTest.java
@@ -101,6 +101,7 @@ @Mock private SnackbarManager mSnackbarManager; @Mock private ModalDialogManager mModalDialogManager; @Mock private TabSwitcherResetHandler mResetHandler; + @Mock private Callback<Integer> mOnTabClickedCallback; @Mock private FaviconHelper.Natives mFaviconHelperJniMock; @Mock private Tracker mTracker; @@ -175,6 +176,7 @@ mResetHandler, mIsVisibleSupplier, mIsAnimatingSupplier, + mOnTabClickedCallback, TabListMode.GRID); mCoordinator.initWithNative();
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneMediator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneMediator.java index 9945962..ca2db57 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneMediator.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneMediator.java
@@ -100,6 +100,7 @@ private final ObservableSupplier<Boolean> mIsVisibleSupplier; private final ObservableSupplier<Boolean> mIsAnimatingSupplier; private final Runnable mOnTabSwitcherShown; + private final Callback<Integer> mOnTabClickCallback; private @Nullable ObservableSupplier<TabListEditorController> mTabListEditorControllerSupplier; private @Nullable TransitiveObservableSupplier<TabListEditorController, Boolean> @@ -117,6 +118,7 @@ * @param onTabSwitcherShown Runnable executed once the view becomes visible. * @param isVisibleSupplier Supplier for visibility of the pane. * @param isAnimatingSupplier Supplier for when the pane is animating in or out of visibility. + * @param onTabClickCallback Callback to invoke when a tab is clicked. */ public TabSwitcherPaneMediator( @NonNull TabSwitcherResetHandler resetHandler, @@ -126,8 +128,10 @@ @NonNull ViewGroup containerView, @NonNull Runnable onTabSwitcherShown, @NonNull ObservableSupplier<Boolean> isVisibleSupplier, - @NonNull ObservableSupplier<Boolean> isAnimatingSupplier) { + @NonNull ObservableSupplier<Boolean> isAnimatingSupplier, + @NonNull Callback<Integer> onTabClickCallback) { mResetHandler = resetHandler; + mOnTabClickCallback = onTabClickCallback; mTabModelFilterSupplier = tabModelFilterSupplier; mTabModelFilterSupplier.addObserver(mOnTabModelFilterChanged); @@ -241,7 +245,7 @@ Tab newlySelectedTab = TabModelUtils.getTabById(model, tabId); StartSurfaceUserData.setKeepTab(newlySelectedTab, true); } - // TODO(crbug/1505772): Forward the selection event to the Hub. + mOnTabClickCallback.onResult(tabId); } @Override
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneMediatorUnitTest.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneMediatorUnitTest.java index c02639c8..5e475f0c 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneMediatorUnitTest.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneMediatorUnitTest.java
@@ -38,6 +38,7 @@ import org.mockito.junit.MockitoRule; import org.robolectric.shadows.ShadowLooper; +import org.chromium.base.Callback; import org.chromium.base.supplier.LazyOneshotSupplier; import org.chromium.base.supplier.ObservableSupplier; import org.chromium.base.supplier.ObservableSupplierImpl; @@ -80,6 +81,7 @@ @Mock private ViewGroup mContainerView; @Mock private View mCustomView; @Mock private Runnable mCustomViewBackPressRunnable; + @Mock private Callback<Integer> mOnTabClickedCallback; @Captor private ArgumentCaptor<TabModelObserver> mTabModelObserverCaptor; @@ -148,7 +150,8 @@ mContainerView, mOnTabSwitcherShownRunnable, mIsVisibleSupplier, - mIsAnimatingSupplier); + mIsAnimatingSupplier, + mOnTabClickedCallback); assertTrue(mTabModelFilterSupplier.hasObservers()); assertTrue(mIsVisibleSupplier.hasObservers()); @@ -312,12 +315,11 @@ @Test @SmallTest public void testOnTabSelecting() { - // TODO(crbug/1505772): This test is incomplete since the event should be forwarded to the - // Hub. assertFalse(StartSurfaceUserData.getKeepTab(mUngroupedTab)); mMediator.onTabSelecting(mUngroupedTab.getId(), /* fromActionButton= */ true); assertTrue(StartSurfaceUserData.getKeepTab(mUngroupedTab)); + verify(mOnTabClickedCallback).onResult(UNGROUPED_TAB_ID); } @Test
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneUnitTest.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneUnitTest.java index 15d5ccb..bb0d1d6 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneUnitTest.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneUnitTest.java
@@ -40,6 +40,7 @@ import org.mockito.junit.MockitoRule; import org.robolectric.shadows.ShadowLooper; +import org.chromium.base.Callback; import org.chromium.base.supplier.ObservableSupplier; import org.chromium.base.supplier.ObservableSupplierImpl; import org.chromium.base.supplier.OneshotSupplierImpl; @@ -49,6 +50,7 @@ import org.chromium.chrome.browser.hub.HubContainerView; import org.chromium.chrome.browser.hub.HubLayoutAnimationType; import org.chromium.chrome.browser.hub.LoadHint; +import org.chromium.chrome.browser.hub.PaneHubController; import org.chromium.chrome.browser.hub.PaneId; import org.chromium.chrome.browser.price_tracking.PriceTrackingFeatures; import org.chromium.chrome.browser.price_tracking.PriceTrackingUtilities; @@ -77,9 +79,11 @@ @Mock private View.OnClickListener mNewTabButtonClickListener; @Mock private TabModelFilter mTabModelFilter; @Mock private MenuOrKeyboardActionController mMenuOrKeyboardActionController; + @Mock private PaneHubController mPaneHubController; @Captor ArgumentCaptor<MenuOrKeyboardActionHandler> mMenuOrKeyboardActionHandlerCaptor; @Captor ArgumentCaptor<OnSharedPreferenceChangeListener> mPriceAnnotationsPrefListenerCaptor; + @Captor ArgumentCaptor<Callback<Integer>> mOnTabClickedCallbackCaptor; private final OneshotSupplierImpl<ProfileProvider> mProfileProviderSupplier = new OneshotSupplierImpl<>(); @@ -106,7 +110,13 @@ return mTabSwitcherPaneCoordinator; }) .when(mTabSwitcherPaneCoordinatorFactory) - .create(any(), any(), any(), any(), anyBoolean()); + .create( + any(), + any(), + any(), + any(), + mOnTabClickedCallbackCaptor.capture(), + anyBoolean()); when(mTabSwitcherPaneCoordinatorFactory.getTabListMode()).thenReturn(TabListMode.GRID); when(mTabSwitcherPaneCoordinator.getHandleBackPressChangedSupplier()) .thenReturn(mHandleBackPressChangeSupplier); @@ -381,19 +391,18 @@ @SmallTest public void testShowTabListEditor() { verify(mMenuOrKeyboardActionController, never()).registerMenuOrKeyboardActionHandler(any()); - mTabSwitcherPane.notifyLoadHint(LoadHint.HOT); + mTabSwitcherPane.setPaneHubController(mPaneHubController); verify(mMenuOrKeyboardActionController) .registerMenuOrKeyboardActionHandler(mMenuOrKeyboardActionHandlerCaptor.capture()); - MenuOrKeyboardActionHandler handler = mMenuOrKeyboardActionHandlerCaptor.getValue(); // Check this doesn't crash if there is no coordinator. - mTabSwitcherPane.destroyTabSwitcherPaneCoordinator(); + MenuOrKeyboardActionHandler handler = mMenuOrKeyboardActionHandlerCaptor.getValue(); assertFalse( handler.handleMenuOrKeyboardAction( org.chromium.chrome.tab_ui.R.id.menu_select_tabs, false)); + mTabSwitcherPane.notifyLoadHint(LoadHint.HOT); mTabSwitcherPane.initWithNative(); - mTabSwitcherPane.createTabSwitcherPaneCoordinator(); TabSwitcherPaneCoordinator coordinator = mTabSwitcherPane.getTabSwitcherPaneCoordinator(); assertFalse( @@ -406,11 +415,8 @@ org.chromium.chrome.tab_ui.R.id.menu_select_tabs, false)); verify(coordinator).showTabListEditor(); - mTabSwitcherPane.notifyLoadHint(LoadHint.WARM); + mTabSwitcherPane.setPaneHubController(null); verify(mMenuOrKeyboardActionController).unregisterMenuOrKeyboardActionHandler(handler); - mTabSwitcherPane.notifyLoadHint(LoadHint.COLD); - verify(mMenuOrKeyboardActionController, times(2)) - .unregisterMenuOrKeyboardActionHandler(handler); } @Test @@ -488,4 +494,20 @@ mTabSwitcherPane.showAllTabs(); verify(coordinator).resetWithTabList(mTabModelFilter); } + + @Test + @SmallTest + public void testOnTabClickedCallback() { + mTabSwitcherPane.initWithNative(); + mTabSwitcherPane.createTabSwitcherPaneCoordinator(); + + int tabId = 6; + mOnTabClickedCallbackCaptor.getValue().onResult(tabId); + verify(mPaneHubController, never()).selectTabAndHideHub(tabId); + + mTabSwitcherPane.setPaneHubController(mPaneHubController); + + mOnTabClickedCallbackCaptor.getValue().onResult(tabId); + verify(mPaneHubController).selectTabAndHideHub(tabId); + } }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabContext.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabContext.java index 17ff0d6..998ceecf 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabContext.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabContext.java
@@ -8,10 +8,8 @@ import androidx.annotation.Nullable; -import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tabmodel.TabModelFilter; -import org.chromium.components.site_engagement.SiteEngagementService; import java.util.ArrayList; import java.util.Collections; @@ -103,11 +101,6 @@ tab.isIncognito()); } - public double getSiteEngagementScore() { - return SiteEngagementService.getForBrowserContext(Profile.getLastUsedRegularProfile()) - .getScore(visibleUrl); - } - @Override public boolean equals(Object other) { if (this == other) return true;
diff --git a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/IncognitoReauthPromoMessageServiceUnitTest.java b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/IncognitoReauthPromoMessageServiceUnitTest.java index ed7148d6..42dc4ca 100644 --- a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/IncognitoReauthPromoMessageServiceUnitTest.java +++ b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/IncognitoReauthPromoMessageServiceUnitTest.java
@@ -88,7 +88,6 @@ @Before public void setUp() { MockitoAnnotations.initMocks(this); - Profile.setLastUsedProfileForTesting(mProfileMock); mJniMocker.mock(UserPrefsJni.TEST_HOOKS, mUserPrefsJniMock); when(mUserPrefsJniMock.get(mProfileMock)).thenReturn(mPrefServiceMock);
diff --git a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/IphMessageServiceUnitTest.java b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/IphMessageServiceUnitTest.java index 75f6d6c..bb24f65 100644 --- a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/IphMessageServiceUnitTest.java +++ b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/IphMessageServiceUnitTest.java
@@ -43,9 +43,8 @@ @Before public void setUp() { MockitoAnnotations.initMocks(this); - Profile.setLastUsedProfileForTesting(mProfile); TrackerFactory.setTrackerForTests(mTracker); - mIphMessageService = new IphMessageService(mIphController); + mIphMessageService = new IphMessageService(mProfile, mIphController); } @Test
diff --git a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/PriceMessageServiceUnitTest.java b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/PriceMessageServiceUnitTest.java index 1a584321..eef5e73 100644 --- a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/PriceMessageServiceUnitTest.java +++ b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/PriceMessageServiceUnitTest.java
@@ -84,8 +84,6 @@ "true"); FeatureList.setTestValues(testValues); - Profile.setLastUsedProfileForTesting(mProfile); - PriceTrackingFeatures.setPriceTrackingEnabledForTesting(true); PriceTrackingFeatures.setIsSignedInAndSyncEnabledForTesting(true); PriceTrackingUtilities.SHARED_PREFERENCES_MANAGER.writeBoolean( @@ -101,7 +99,7 @@ mMessageService = new PriceMessageService( - mMessageProvider, mReviewActionProvider, mNotificationManager); + mProfile, mMessageProvider, mReviewActionProvider, mNotificationManager); mMessageService.addObserver(mMessageObserver); }
diff --git a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabSuggestionMessageServiceUnitTest.java b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabSuggestionMessageServiceUnitTest.java index 76a6535..269c708 100644 --- a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabSuggestionMessageServiceUnitTest.java +++ b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabSuggestionMessageServiceUnitTest.java
@@ -117,10 +117,11 @@ mMessageService = new TabSuggestionMessageService( - mContext, () -> mTabGroupModelFilter, () -> mTabListEditorController); + mContext, + mProfile, + () -> mTabGroupModelFilter, + () -> mTabListEditorController); mMessageService.addObserver(mMessageObserver); - - Profile.setLastUsedProfileForTesting(mProfile); } // Tests for Close suggestions.
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/multiwindow/MultiInstanceManagerApi31UnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/multiwindow/MultiInstanceManagerApi31UnitTest.java index 541f1004..e339eba 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/multiwindow/MultiInstanceManagerApi31UnitTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/multiwindow/MultiInstanceManagerApi31UnitTest.java
@@ -447,6 +447,7 @@ @Test @SmallTest @UiThreadTest + @EnableFeatures(ChromeFeatureList.MUlTI_INSTANCE_APPLICATION_STATUS_CLEANUP) public void testAllocInstanceId_removeTaskOnRecentScreen_withoutDestroy() { assertEquals(0, allocInstanceIndex(PASSED_ID_INVALID, mActivityTask56));
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 43bb5944..6e5e3cf2 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd
@@ -3388,6 +3388,11 @@ desc="Status text for a download item that is being checked for malware."> Checking for malware... </message> + + <!-- Web App Window Title string --> + <message name="IDS_WEB_APP_WITH_APP_TITLE" desc="Title of the web app window with app_title."> + <ph name="APP_NAME">$1<ex>Sample App</ex></ph> - <ph name="APP_TITLE">$2<ex>News</ex></ph> + </message> <!-- Desktop omnibox PWA install icon --> <if expr="not is_android"> @@ -7730,6 +7735,12 @@ <message name="IDS_NTP_CUSTOMIZE_COLOR_HUE_SLIDER_TITLE" desc="The label for the hue slider in the customization menu on the New Tab Page that allows a user to pick a color for their theme"> Color picker </message> + <message name="IDS_NTP_CUSTOMIZE_COLOR_HUE_SLIDER_DELETE_TITLE" desc="The tooltip for the delete button in the hue slider that unselects the currently selected hue."> + Unselect + </message> + <message name="IDS_NTP_CUSTOMIZE_COLOR_HUE_SLIDER_DELETE_A11Y_LABEL" desc="The accessibility label for the delete button in the hue slider that unselects the currently selected hue."> + Unselect color + </message> <message name="IDS_NTP_THEME_MANAGED_DIALOG_TITLE" desc="Title text for the dialog informing users that their theme is managed when they try selecting a theme on the New Tab Page."> Theme is set by your Organization </message> @@ -7886,9 +7897,6 @@ <message name="IDS_NTP_WALLPAPER_SEARCH_HISTORY_HEADER" desc="Header for the wallpaper search section for showing past themes." > Your recent AI themes </message> - <message name="IDS_NTP_WALLPAPER_SEARCH_HISTORY_TILE_TITLE" desc="Title for each tile button in the wallpaper search section for showing past themes."> - Recent AI theme <ph name="TILE_INDEX">$1<ex>2</ex></ph> - </message> <message name="IDS_NTP_WALLPAPER_SEARCH_OFFLINE_DESCRIPTION" desc="The description of the message displayed by wallpaper search when the browser is offline."> Check your internet and try again. </message> @@ -7928,17 +7936,32 @@ <message name="IDS_NTP_WALLPAPER_SEARCH_TRY_AGAIN_CTA" desc="Call to action displayed when wallpaper search fails that asks user to try again."> Try again </message> + <message name="IDS_NTP_WALLPAPER_SEARCH_HISTORY_RESULT_LABEL_NO_DESCRIPTOR" desc="Accessibility label for a wallpaper search history result, with only the index."> + Recent AI theme <ph name="INDEX">$1<ex>2</ex></ph> + </message> + <message name="IDS_NTP_WALLPAPER_SEARCH_HISTORY_RESULT_LABEL" desc="Accessibility label for a wallpaper search history result, with only descriptor A."> + Recent AI theme <ph name="INDEX">$1<ex>2</ex></ph> of <ph name="SUBJECT">$2</ph> + </message> + <message name="IDS_NTP_WALLPAPER_SEARCH_HISTORY_RESULT_LABEL_WITH_DESCRIPTOR_B" desc="Accessibility label for a wallpaper search history result, with descriptors A and B."> + Recent AI theme <ph name="INDEX">$1<ex>2</ex></ph> of <ph name="SUBJECT">$2</ph>, in <ph name="STYLE">$3</ph> style + </message> + <message name="IDS_NTP_WALLPAPER_SEARCH_HISTORY_RESULT_LABEL_WITH_DESCRIPTOR_C" desc="Accessibility label for a wallpaper search history result, with descriptors A and C."> + Recent AI theme <ph name="INDEX">$1<ex>2</ex></ph> of <ph name="SUBJECT">$2</ph>, with <ph name="MOOD">$3</ph> mood. + </message> + <message name="IDS_NTP_WALLPAPER_SEARCH_HISTORY_RESULT_LABEL_WITH_DESCRIPTORS_B_AND_C" desc="Accessibility label for a wallpaper search history result, with descriptors A, B, and C."> + Recent AI theme <ph name="INDEX">$1<ex>2</ex></ph> of <ph name="SUBJECT">$2</ph>, in <ph name="STYLE">$3</ph> style, with <ph name="MOOD">$4</ph> mood. + </message> <message name="IDS_NTP_WALLPAPER_SEARCH_RESULT_LABEL" desc="Accessibility label for a wallpaper search result, with only descriptor A."> - Image <ph name="INDEX">$1<ex>2</ex></ph> of <ph name="A">$2</ph> + Generated image <ph name="INDEX">$1<ex>2</ex></ph> of <ph name="SUBJECT">$2</ph> </message> <message name="IDS_NTP_WALLPAPER_SEARCH_RESULT_LABEL_WITH_DESCRIPTOR_B" desc="Accessibility label for a wallpaper search result, with descriptors A and B."> - Image <ph name="INDEX">$1<ex>2</ex></ph> of <ph name="A">$2</ph>, in <ph name="B">$3</ph> style + Generated image <ph name="INDEX">$1<ex>2</ex></ph> of <ph name="SUBJECT">$2</ph>, in <ph name="STYLE">$3</ph> style </message> <message name="IDS_NTP_WALLPAPER_SEARCH_RESULT_LABEL_WITH_DESCRIPTOR_C" desc="Accessibility label for a wallpaper search result, with descriptors A and C."> - Image <ph name="INDEX">$1<ex>2</ex></ph> of <ph name="A">$2</ph>, with <ph name="C">$3</ph> mood. + Generated image <ph name="INDEX">$1<ex>2</ex></ph> of <ph name="SUBJECT">$2</ph>, with <ph name="MOOD">$3</ph> mood. </message> <message name="IDS_NTP_WALLPAPER_SEARCH_RESULT_LABEL_WITH_DESCRIPTORS_B_AND_C" desc="Accessibility label for a wallpaper search result, with descriptors A, B, and C."> - Image <ph name="INDEX">$1<ex>2</ex></ph> of <ph name="A">$2</ph>, in <ph name="B">$3</ph> style, with <ph name="C">$4</ph> mood. + Generated image <ph name="INDEX">$1<ex>2</ex></ph> of <ph name="SUBJECT">$2</ph>, in <ph name="STYLE">$3</ph> style, with <ph name="MOOD">$4</ph> mood. </message> <message name="IDS_NTP_WALLPAPER_SEARCH_SUBJECT_LABEL" desc="Label for the Create theme with AI dropdown for selecting subject of the image."> Subject
diff --git a/chrome/app/generated_resources_grd/IDS_NTP_CUSTOMIZE_COLOR_HUE_SLIDER_DELETE_A11Y_LABEL.png.sha1 b/chrome/app/generated_resources_grd/IDS_NTP_CUSTOMIZE_COLOR_HUE_SLIDER_DELETE_A11Y_LABEL.png.sha1 new file mode 100644 index 0000000..af1edd4 --- /dev/null +++ b/chrome/app/generated_resources_grd/IDS_NTP_CUSTOMIZE_COLOR_HUE_SLIDER_DELETE_A11Y_LABEL.png.sha1
@@ -0,0 +1 @@ +728d7b9f4f2d9cbc3604f097b29e7a3d2642d65b \ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_NTP_CUSTOMIZE_COLOR_HUE_SLIDER_DELETE_TITLE.png.sha1 b/chrome/app/generated_resources_grd/IDS_NTP_CUSTOMIZE_COLOR_HUE_SLIDER_DELETE_TITLE.png.sha1 new file mode 100644 index 0000000..7cdba5db --- /dev/null +++ b/chrome/app/generated_resources_grd/IDS_NTP_CUSTOMIZE_COLOR_HUE_SLIDER_DELETE_TITLE.png.sha1
@@ -0,0 +1 @@ +dd934c7a0a18af3d4d47e662c6d0b802c7bf6c60 \ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_NTP_WALLPAPER_SEARCH_HISTORY_TILE_TITLE.png.sha1 b/chrome/app/generated_resources_grd/IDS_NTP_WALLPAPER_SEARCH_HISTORY_RESULT_LABEL.png.sha1 similarity index 100% rename from chrome/app/generated_resources_grd/IDS_NTP_WALLPAPER_SEARCH_HISTORY_TILE_TITLE.png.sha1 rename to chrome/app/generated_resources_grd/IDS_NTP_WALLPAPER_SEARCH_HISTORY_RESULT_LABEL.png.sha1
diff --git a/chrome/app/generated_resources_grd/IDS_NTP_WALLPAPER_SEARCH_HISTORY_TILE_TITLE.png.sha1 b/chrome/app/generated_resources_grd/IDS_NTP_WALLPAPER_SEARCH_HISTORY_RESULT_LABEL_NO_DESCRIPTOR.png.sha1 similarity index 100% copy from chrome/app/generated_resources_grd/IDS_NTP_WALLPAPER_SEARCH_HISTORY_TILE_TITLE.png.sha1 copy to chrome/app/generated_resources_grd/IDS_NTP_WALLPAPER_SEARCH_HISTORY_RESULT_LABEL_NO_DESCRIPTOR.png.sha1
diff --git a/chrome/app/generated_resources_grd/IDS_NTP_WALLPAPER_SEARCH_HISTORY_TILE_TITLE.png.sha1 b/chrome/app/generated_resources_grd/IDS_NTP_WALLPAPER_SEARCH_HISTORY_RESULT_LABEL_WITH_DESCRIPTORS_B_AND_C.png.sha1 similarity index 100% copy from chrome/app/generated_resources_grd/IDS_NTP_WALLPAPER_SEARCH_HISTORY_TILE_TITLE.png.sha1 copy to chrome/app/generated_resources_grd/IDS_NTP_WALLPAPER_SEARCH_HISTORY_RESULT_LABEL_WITH_DESCRIPTORS_B_AND_C.png.sha1
diff --git a/chrome/app/generated_resources_grd/IDS_NTP_WALLPAPER_SEARCH_HISTORY_TILE_TITLE.png.sha1 b/chrome/app/generated_resources_grd/IDS_NTP_WALLPAPER_SEARCH_HISTORY_RESULT_LABEL_WITH_DESCRIPTOR_B.png.sha1 similarity index 100% copy from chrome/app/generated_resources_grd/IDS_NTP_WALLPAPER_SEARCH_HISTORY_TILE_TITLE.png.sha1 copy to chrome/app/generated_resources_grd/IDS_NTP_WALLPAPER_SEARCH_HISTORY_RESULT_LABEL_WITH_DESCRIPTOR_B.png.sha1
diff --git a/chrome/app/generated_resources_grd/IDS_NTP_WALLPAPER_SEARCH_HISTORY_TILE_TITLE.png.sha1 b/chrome/app/generated_resources_grd/IDS_NTP_WALLPAPER_SEARCH_HISTORY_RESULT_LABEL_WITH_DESCRIPTOR_C.png.sha1 similarity index 100% copy from chrome/app/generated_resources_grd/IDS_NTP_WALLPAPER_SEARCH_HISTORY_TILE_TITLE.png.sha1 copy to chrome/app/generated_resources_grd/IDS_NTP_WALLPAPER_SEARCH_HISTORY_RESULT_LABEL_WITH_DESCRIPTOR_C.png.sha1
diff --git a/chrome/app/generated_resources_grd/IDS_NTP_WALLPAPER_SEARCH_RESULT_LABEL.png.sha1 b/chrome/app/generated_resources_grd/IDS_NTP_WALLPAPER_SEARCH_RESULT_LABEL.png.sha1 index 85d05eb2..5dd8fa6 100644 --- a/chrome/app/generated_resources_grd/IDS_NTP_WALLPAPER_SEARCH_RESULT_LABEL.png.sha1 +++ b/chrome/app/generated_resources_grd/IDS_NTP_WALLPAPER_SEARCH_RESULT_LABEL.png.sha1
@@ -1 +1 @@ -3c1aa0835be426969bb0502004773c1a40bf169b \ No newline at end of file +5f6cd954e8ae25200a891e2f72b79a12086004ab \ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_NTP_WALLPAPER_SEARCH_RESULT_LABEL_WITH_DESCRIPTORS_B_AND_C.png.sha1 b/chrome/app/generated_resources_grd/IDS_NTP_WALLPAPER_SEARCH_RESULT_LABEL_WITH_DESCRIPTORS_B_AND_C.png.sha1 index 85d05eb2..5dd8fa6 100644 --- a/chrome/app/generated_resources_grd/IDS_NTP_WALLPAPER_SEARCH_RESULT_LABEL_WITH_DESCRIPTORS_B_AND_C.png.sha1 +++ b/chrome/app/generated_resources_grd/IDS_NTP_WALLPAPER_SEARCH_RESULT_LABEL_WITH_DESCRIPTORS_B_AND_C.png.sha1
@@ -1 +1 @@ -3c1aa0835be426969bb0502004773c1a40bf169b \ No newline at end of file +5f6cd954e8ae25200a891e2f72b79a12086004ab \ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_NTP_WALLPAPER_SEARCH_RESULT_LABEL_WITH_DESCRIPTOR_B.png.sha1 b/chrome/app/generated_resources_grd/IDS_NTP_WALLPAPER_SEARCH_RESULT_LABEL_WITH_DESCRIPTOR_B.png.sha1 index 85d05eb2..5dd8fa6 100644 --- a/chrome/app/generated_resources_grd/IDS_NTP_WALLPAPER_SEARCH_RESULT_LABEL_WITH_DESCRIPTOR_B.png.sha1 +++ b/chrome/app/generated_resources_grd/IDS_NTP_WALLPAPER_SEARCH_RESULT_LABEL_WITH_DESCRIPTOR_B.png.sha1
@@ -1 +1 @@ -3c1aa0835be426969bb0502004773c1a40bf169b \ No newline at end of file +5f6cd954e8ae25200a891e2f72b79a12086004ab \ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_NTP_WALLPAPER_SEARCH_RESULT_LABEL_WITH_DESCRIPTOR_C.png.sha1 b/chrome/app/generated_resources_grd/IDS_NTP_WALLPAPER_SEARCH_RESULT_LABEL_WITH_DESCRIPTOR_C.png.sha1 index 85d05eb2..5dd8fa6 100644 --- a/chrome/app/generated_resources_grd/IDS_NTP_WALLPAPER_SEARCH_RESULT_LABEL_WITH_DESCRIPTOR_C.png.sha1 +++ b/chrome/app/generated_resources_grd/IDS_NTP_WALLPAPER_SEARCH_RESULT_LABEL_WITH_DESCRIPTOR_C.png.sha1
@@ -1 +1 @@ -3c1aa0835be426969bb0502004773c1a40bf169b \ No newline at end of file +5f6cd954e8ae25200a891e2f72b79a12086004ab \ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_WEB_APP_WITH_APP_TITLE.png.sha1 b/chrome/app/generated_resources_grd/IDS_WEB_APP_WITH_APP_TITLE.png.sha1 new file mode 100644 index 0000000..204347f --- /dev/null +++ b/chrome/app/generated_resources_grd/IDS_WEB_APP_WITH_APP_TITLE.png.sha1
@@ -0,0 +1 @@ +6b9f169c1bca991eaa7722ab2c6ee729543ef0d8 \ No newline at end of file
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index dd20367..280b14b 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -8127,6 +8127,12 @@ FEATURE_VALUE_TYPE( content_settings::features::kImprovedSemanticsActivityIndicators)}, + {"left-hand-side-activity-indicators", + flag_descriptions::kLeftHandSideActivityIndicatorsName, + flag_descriptions::kLeftHandSideActivityIndicatorsDescription, kOsDesktop, + FEATURE_VALUE_TYPE( + content_settings::features::kLeftHandSideActivityIndicators)}, + {"attribution-reporting-debug-mode", flag_descriptions::kAttributionReportingDebugModeName, flag_descriptions::kAttributionReportingDebugModeDescription, kOsAll,
diff --git a/chrome/browser/ash/app_list/search/essential_search/essential_search_manager.cc b/chrome/browser/ash/app_list/search/essential_search/essential_search_manager.cc index 8578c25d..06f7e93d 100644 --- a/chrome/browser/ash/app_list/search/essential_search/essential_search_manager.cc +++ b/chrome/browser/ash/app_list/search/essential_search/essential_search_manager.cc
@@ -22,7 +22,9 @@ EssentialSearchManager::EssentialSearchManager(Profile* primary_profile) : primary_profile_(primary_profile) { DCHECK(primary_profile_); - scoped_observation_.Observe(ash::SessionController::Get()); + auto* session_controller = ash::SessionController::Get(); + CHECK(session_controller); + scoped_observation_.Observe(session_controller); } EssentialSearchManager::~EssentialSearchManager() = default;
diff --git a/chrome/browser/ash/arc/input_overlay/ui/action_edit_view.cc b/chrome/browser/ash/arc/input_overlay/ui/action_edit_view.cc index 5ca0488..7fe2beb 100644 --- a/chrome/browser/ash/arc/input_overlay/ui/action_edit_view.cc +++ b/chrome/browser/ash/arc/input_overlay/ui/action_edit_view.cc
@@ -60,8 +60,8 @@ views::CreateEmptyBorder(gfx::Insets::VH(14, kHorizontalInsets))); container->SetBackground(views::CreateThemedRoundedRectBackground( cros_tokens::kCrosSysSystemOnBase, - /*top_radius=*/kCornerRadius, - /*bottom_radius=*/for_editing_list ? kCornerRadius : 0.0f, + /*top_radius=*/for_editing_list ? kCornerRadius : 0.0f, + /*bottom_radius=*/kCornerRadius, /*for_border_thickness=*/0)); const int padding_width = for_editing_list ? kNameTagAndLabelsPaddingForEditingList @@ -94,11 +94,12 @@ // Set highlight path. views::HighlightPathGenerator::Install( - this, std::make_unique<views::RoundRectHighlightPathGenerator>( - gfx::Insets(), for_editing_list - ? gfx::RoundedCornersF(kCornerRadius) - : gfx::RoundedCornersF( - kCornerRadius, kCornerRadius, 0, 0))); + this, + std::make_unique<views::RoundRectHighlightPathGenerator>( + gfx::Insets(), for_editing_list + ? gfx::RoundedCornersF(kCornerRadius) + : gfx::RoundedCornersF(0.0f, 0.0f, kCornerRadius, + kCornerRadius))); } ActionEditView::~ActionEditView() = default;
diff --git a/chrome/browser/ash/arc/input_overlay/ui/button_options_menu.cc b/chrome/browser/ash/arc/input_overlay/ui/button_options_menu.cc index 455e0b3..3d39f59 100644 --- a/chrome/browser/ash/arc/input_overlay/ui/button_options_menu.cc +++ b/chrome/browser/ash/arc/input_overlay/ui/button_options_menu.cc
@@ -185,8 +185,8 @@ views::BoxLayout::Orientation::kVertical)); AddHeader(); AddEditTitle(); - AddActionEdit(); AddActionSelection(); + AddActionEdit(); AddDeleteButton(); } @@ -245,16 +245,6 @@ gfx::Insets::TLBR(0, kHeaderLeftMarginSpacing, 16, 0)); } -void ButtonOptionsMenu::AddActionEdit() { - // ------------------------------ - // ||"Selected key" |key labels|| - // ||"key" | - // ------------------------------ - action_edit_ = AddChildView( - std::make_unique<ButtonOptionsActionEdit>(controller_, action_)); - action_name_label_->SetText(action_edit_->GetActionName()); -} - void ButtonOptionsMenu::AddActionSelection() { // ---------------------------------- // | |"Choose your button type:" | | @@ -262,10 +252,10 @@ // ---------------------------------- auto* container = AddChildView(std::make_unique<views::View>()); container->SetBackground(views::CreateThemedRoundedRectBackground( - cros_tokens::kCrosSysSystemOnBase, /*top_radius=*/0, - /*bottom_radius=*/16, /*for_border_thickness=*/0)); + cros_tokens::kCrosSysSystemOnBase, /*top_radius=*/16.0f, + /*bottom_radius=*/0.0f, /*for_border_thickness=*/0.0f)); container->SetUseDefaultFillLayout(true); - container->SetProperty(views::kMarginsKey, gfx::Insets::TLBR(2, 0, 0, 0)); + container->SetProperty(views::kMarginsKey, gfx::Insets::TLBR(0, 0, 2, 0)); container->SetLayoutManager(std::make_unique<views::BoxLayout>( views::BoxLayout::Orientation::kVertical, /*inside_border_insets=*/gfx::Insets::TLBR(12, 16, 16, 16), @@ -284,6 +274,16 @@ ActionTypeButtonGroup::CreateButtonGroup(controller_, action_)); } +void ButtonOptionsMenu::AddActionEdit() { + // ------------------------------ + // ||"Selected key" |key labels|| + // ||"key" | + // ------------------------------ + action_edit_ = AddChildView( + std::make_unique<ButtonOptionsActionEdit>(controller_, action_)); + action_name_label_->SetText(action_edit_->GetActionName()); +} + void ButtonOptionsMenu::AddDeleteButton() { // ------------------------------ // || Delete button ||
diff --git a/chrome/browser/ash/arc/input_overlay/ui/button_options_menu.h b/chrome/browser/ash/arc/input_overlay/ui/button_options_menu.h index d693c85..d9524d0 100644 --- a/chrome/browser/ash/arc/input_overlay/ui/button_options_menu.h +++ b/chrome/browser/ash/arc/input_overlay/ui/button_options_menu.h
@@ -37,13 +37,13 @@ // |----------------------------------| // ||"Buttons let..."| | // |----------------------------------| -// ||"Selected key" |key labels|| -// ||"key" | -// |----------------------------------| // | |"Choose your button type:" | | // | |feature_tile| |feature_title| | // | | | | | | // |----------------------------------| +// ||"Selected key" |key labels|| +// ||"key" | +// |----------------------------------| // -----------------------------------| // || Delete button || // +----------------------------------+ @@ -69,8 +69,8 @@ // Add UI components. void AddHeader(); void AddEditTitle(); - void AddActionEdit(); void AddActionSelection(); + void AddActionEdit(); void AddDeleteButton(); // Functions related to buttons.
diff --git a/chrome/browser/ash/arc/tracing/arc_tracing_graphics_model.cc b/chrome/browser/ash/arc/tracing/arc_tracing_graphics_model.cc index a0bf635..56cf8ec 100644 --- a/chrome/browser/ash/arc/tracing/arc_tracing_graphics_model.cc +++ b/chrome/browser/ash/arc/tracing/arc_tracing_graphics_model.cc
@@ -39,8 +39,6 @@ using BufferEvents = ArcTracingGraphicsModel::BufferEvents; using EventType = ArcTracingGraphicsModel::EventType; -constexpr char kCustomTracePrefix[] = "customTrace"; - constexpr char kUnknownActivity[] = "unknown"; constexpr char kKeyActivity[] = "activity"; @@ -200,43 +198,19 @@ route->pop_back(); } -void ScanForCustomEvents( - const ArcTracingEvent* event, - ArcTracingGraphicsModel::BufferEvents* out_custom_events) { - if (base::StartsWith(event->GetName(), kCustomTracePrefix, - base::CompareCase::SENSITIVE)) { - DCHECK(!event->GetArgs() || event->GetArgs()->empty()); - out_custom_events->emplace_back( - ArcTracingGraphicsModel::EventType::kCustomEvent, event->GetTimestamp(), - event->GetName().substr(std::size(kCustomTracePrefix) - 1)); - } - for (const auto& child : event->children()) - ScanForCustomEvents(child.get(), out_custom_events); -} - -// Extracts custom events from the model. Custom events start from customTrace -ArcTracingGraphicsModel::BufferEvents GetCustomEvents( - const ArcTracingModel& common_model) { - ArcTracingGraphicsModel::BufferEvents custom_events; - for (const ArcTracingEvent* root : common_model.GetRoots()) - ScanForCustomEvents(root, &custom_events); - return custom_events; -} - // Adds jank events into |ArcTracingGraphicsModel::EventsContainer|. // |pulse_event_type| defines the type of the event that should appear // periodically. Once it is missed in analyzed buffer events, new jank event is // added. |jank_event_type| defines the type of jank. -void AddJanks(ArcTracingGraphicsModel::EventsContainer* result, +void AddJanks(std::vector<BufferEvent>* events, EventType pulse_event_type, EventType jank_event_type) { // Detect rate first. BufferEvents pulse_events; - for (const auto& it : result->buffer_events()) { - for (const auto& it_event : it) { - if (it_event.type == pulse_event_type) - pulse_events.emplace_back(it_event); + for (const auto& ev : *events) { + if (ev.type == pulse_event_type) { + pulse_events.emplace_back(ev); } } SortBufferEventsByTimestamp(&pulse_events); @@ -248,7 +222,7 @@ BufferEvent(jank_event_type, timestamp.ToDeltaSinceWindowsEpoch().InMicroseconds())); }, - jank_event_type, &result->global_events())); + jank_event_type, events)); for (const auto& it : pulse_events) { jank_detector.OnSample(base::Time::FromDeltaSinceWindowsEpoch( @@ -266,6 +240,8 @@ jank_detector.OnSample(base::Time::FromDeltaSinceWindowsEpoch( base::Microseconds(it.timestamp))); } + + SortBufferEventsByTimestamp(events); } // Helper that performs query in |common_model| for top level Chrome GPU events @@ -280,8 +256,6 @@ } SortBufferEventsByTimestamp(&result->buffer_events()[0]); - - // TODO(matvore): Record Janks in the ChromeOS swap done pulse. } // Helper that serializes events |events| to the |base::Value::List|. @@ -341,12 +315,13 @@ if (!IsInRange(type, EventType::kBufferQueueDequeueStart, EventType::kBufferFillJank) && !IsInRange(type, EventType::kExoSurfaceAttach, - EventType::kExoSurfaceCommit) && + EventType::kExoLastEvent) && !IsInRange(type, EventType::kChromeBarrierOrder, EventType::kChromeBarrierFlush) && !IsInRange(type, EventType::kSurfaceFlingerVsyncHandler, EventType::kVsyncTimestamp) && - !IsInRange(type, EventType::kChromeOSDraw, EventType::kChromeOSJank) && + !IsInRange(type, EventType::kChromeOSDraw, + EventType::kChromeOSLastEvent) && !IsInRange(type, EventType::kCustomEvent, EventType::kCustomEvent) && !IsInRange(type, EventType::kInputEventCreated, EventType::kInputEventDeliverEnd)) { @@ -463,24 +438,16 @@ for (int64_t ticks : present_frames.commits()) { buffer_events[0].emplace_back(EventType::kExoSurfaceCommit, ticks); } + AddJanks(&buffer_events[0], EventType::kExoSurfaceCommit, + EventType::kExoSurfaceCommitJank); + for (int64_t ticks : present_frames.presents()) { chrome_top_level_.global_events().emplace_back( EventType::kChromeOSPresentationDone, ticks); } - - // TODO(khmel): Add more information to resolve owner of custom events. At - // this moment add custom events to each view. - const ArcTracingGraphicsModel::BufferEvents custom_events = - GetCustomEvents(common_model); - for (auto& it : view_buffers_) { - AddJanks(&it.second, EventType::kBufferQueueDequeueStart, - EventType::kBufferFillJank); - AddJanks(&it.second, EventType::kExoSurfaceCommit, EventType::kExoJank); - it.second.global_events().insert(it.second.global_events().end(), - custom_events.begin(), - custom_events.end()); - SortBufferEventsByTimestamp(&it.second.global_events()); - } + AddJanks(&chrome_top_level_.global_events(), + EventType::kChromeOSPresentationDone, + EventType::kChromeOSPerceivedJank); GetChromeTopLevelEvents(common_model, &chrome_top_level_); if (chrome_top_level_.buffer_events().empty()) { @@ -488,6 +455,8 @@ if (!skip_structure_validation_) return false; } + AddJanks(&chrome_top_level_.buffer_events()[0], EventType::kChromeOSSwapDone, + EventType::kChromeOSSwapJank); system_model_.CopyFrom(common_model.system_model());
diff --git a/chrome/browser/ash/arc/tracing/arc_tracing_graphics_model.h b/chrome/browser/ash/arc/tracing/arc_tracing_graphics_model.h index b3a1f2b..66286d6 100644 --- a/chrome/browser/ash/arc/tracing/arc_tracing_graphics_model.h +++ b/chrome/browser/ash/arc/tracing/arc_tracing_graphics_model.h
@@ -56,13 +56,15 @@ kBufferFillJank, // 106, // Wayland exo events - kExoSurfaceAttach = 200, // Obsolete - kExoProduceResource = 201, // Obsolete - kExoBound = 202, // Obsolete - kExoPendingQuery = 203, // Obsolete - kExoReleased = 204, // Obsolete - kExoJank = 205, - kExoSurfaceCommit = 206, + kExoSurfaceAttach = 200, // Obsolete + kExoProduceResource = 201, // Obsolete + kExoBound = 202, // Obsolete + kExoPendingQuery = 203, // Obsolete + kExoReleased = 204, // Obsolete + kExoJank = 205, + kExoSurfaceCommit = 206, + kExoSurfaceCommitJank = 207, + kExoLastEvent = kExoSurfaceCommitJank, // Chrome events kChromeBarrierOrder = 300, // Obsolete @@ -84,9 +86,12 @@ kChromeOSPresentationDone = 503, kChromeOSSwapDone = 504, kChromeOSJank = 505, // Obsolete + kChromeOSPerceivedJank = 506, + kChromeOSSwapJank = 507, + kChromeOSLastEvent = kChromeOSSwapJank, // Custom event. - kCustomEvent = 600, + kCustomEvent = 600, // Obsolete // Input events kInputEventCreated = 700, // Obsolete
diff --git a/chrome/browser/ash/chrome_browser_main_parts_ash.cc b/chrome/browser/ash/chrome_browser_main_parts_ash.cc index cf5db34..b9f5e93 100644 --- a/chrome/browser/ash/chrome_browser_main_parts_ash.cc +++ b/chrome/browser/ash/chrome_browser_main_parts_ash.cc
@@ -50,6 +50,7 @@ #include "chrome/browser/ash/accessibility/accessibility_event_rewriter_delegate_impl.h" #include "chrome/browser/ash/accessibility/accessibility_manager.h" #include "chrome/browser/ash/accessibility/magnification_manager.h" +#include "chrome/browser/ash/app_list/search/essential_search/essential_search_manager.h" #include "chrome/browser/ash/app_mode/app_launch_utils.h" #include "chrome/browser/ash/app_mode/arc/arc_kiosk_app_manager.h" #include "chrome/browser/ash/app_mode/kiosk_chrome_app_manager.h" @@ -1258,6 +1259,9 @@ misconfigured_user_cleaner_->ScheduleCleanup(); + essential_search_manager_ = + ::app_list::EssentialSearchManager::Create(profile); + g_browser_process->platform_part()->session_manager()->Initialize( *base::CommandLine::ForCurrentProcess(), profile, is_integration_test()); @@ -1565,6 +1569,7 @@ login_screen_extensions_storage_cleaner_.reset(); debugd_notification_handler_.reset(); shortcut_mapping_pref_service_.reset(); + essential_search_manager_.reset(); if (features::IsTrafficCountersEnabled()) { traffic_counters_handler_.reset(); }
diff --git a/chrome/browser/ash/chrome_browser_main_parts_ash.h b/chrome/browser/ash/chrome_browser_main_parts_ash.h index 0c7dcb0..1b0be40 100644 --- a/chrome/browser/ash/chrome_browser_main_parts_ash.h +++ b/chrome/browser/ash/chrome_browser_main_parts_ash.h
@@ -23,6 +23,10 @@ class ChromeKeyboardControllerClient; class ImageDownloaderImpl; +namespace app_list { +class EssentialSearchManager; +} + namespace arc { class ArcServiceLauncher; class ContainerAppKiller; @@ -309,6 +313,8 @@ std::unique_ptr<MisconfiguredUserCleaner> misconfigured_user_cleaner_; + std::unique_ptr<::app_list::EssentialSearchManager> essential_search_manager_; + base::WeakPtrFactory<ChromeBrowserMainPartsAsh> weak_ptr_factory_{this}; };
diff --git a/chrome/browser/ash/crosapi/crosapi_util.cc b/chrome/browser/ash/crosapi/crosapi_util.cc index 66e73c8..111668f 100644 --- a/chrome/browser/ash/crosapi/crosapi_util.cc +++ b/chrome/browser/ash/crosapi/crosapi_util.cc
@@ -205,6 +205,10 @@ // Bug fix to launch tabbed web app windows in new windows when requested. // We can remove this capability once Ash and Lacros are both past M122. constexpr char kAshShelfNewWindowFix[] = "crbug/1490336"; +// Support feedback dialog ai flow. +// TODO(crbug/1501057): Remove this capability once Ash and Lacros are both past +// M123. +constexpr char kAshFeedbackFlowAi[] = "crbug/1501057"; // Returns the vector containing policy data of the device account. In case of // an error, returns nullopt. @@ -630,6 +634,7 @@ kAshExtensionKeeplistCmdlineSwitchCapability, kAshAppInstallServicePackageIdFix, kAshShelfNewWindowFix, + kAshFeedbackFlowAi, }; params->ash_capabilities = {std::move(ash_capabilities)};
diff --git a/chrome/browser/ash/crosapi/feedback_ash.cc b/chrome/browser/ash/crosapi/feedback_ash.cc index f5c74c0..e1fc0495 100644 --- a/chrome/browser/ash/crosapi/feedback_ash.cc +++ b/chrome/browser/ash/crosapi/feedback_ash.cc
@@ -36,6 +36,8 @@ return chrome::kFeedbackSourceProfileErrorDialog; case mojom::LacrosFeedbackSource::kFeedbackSourceQuickOffice: return chrome::kFeedbackSourceQuickOffice; + case mojom::LacrosFeedbackSource::kFeedbackSourceAI: + return chrome::kFeedbackSourceAI; case mojom::LacrosFeedbackSource::kUnknown: return chrome::kFeedbackSourceUnknownLacrosSource; } @@ -67,14 +69,26 @@ } base::Value::Dict autofill_metadata; if (feedback_info->autofill_metadata) { - DCHECK(feedback_info->autofill_metadata->is_dict()); + if (!feedback_info->autofill_metadata->is_dict()) { + LOG(ERROR) << "Feedback info autofill metadata is not a dict."; + return; + } autofill_metadata = std::move(*feedback_info->autofill_metadata).TakeDict(); } + base::Value::Dict ai_metadata; + if (feedback_info->ai_metadata) { + if (!feedback_info->ai_metadata->is_dict()) { + LOG(ERROR) << "Feedback info ai metadata is not a dict."; + return; + } + ai_metadata = std::move(*feedback_info->ai_metadata).TakeDict(); + } chrome::ShowFeedbackPage( feedback_info->page_url, profile, FromMojo(feedback_info->source), feedback_info->description_template, feedback_info->description_placeholder_text, feedback_info->category_tag, - feedback_info->extra_diagnostics, std::move(autofill_metadata)); + feedback_info->extra_diagnostics, std::move(autofill_metadata), + std::move(ai_metadata)); } } // namespace crosapi
diff --git a/chrome/browser/ash/extensions/file_manager/private_api_tasks.cc b/chrome/browser/ash/extensions/file_manager/private_api_tasks.cc index 66480cc..c721212 100644 --- a/chrome/browser/ash/extensions/file_manager/private_api_tasks.cc +++ b/chrome/browser/ash/extensions/file_manager/private_api_tasks.cc
@@ -32,7 +32,6 @@ #include "extensions/browser/entry_info.h" #include "storage/browser/file_system/file_system_context.h" #include "storage/browser/file_system/file_system_url.h" -#include "ui/gfx/native_widget_types.h" namespace extensions { namespace { @@ -134,14 +133,8 @@ urls.push_back(url); } - // Get Files App window, if it exists. - Browser* browser = - FindSystemWebAppBrowser(profile, ash::SystemWebAppType::FILE_MANAGER); - gfx::NativeWindow modal_parent = - browser ? browser->window()->GetNativeWindow() : nullptr; - const bool result = file_manager::file_tasks::ExecuteFileTask( - profile, task, urls, modal_parent, + profile, task, urls, base::BindOnce( &FileManagerPrivateInternalExecuteTaskFunction::OnTaskExecuted, this));
diff --git a/chrome/browser/ash/file_manager/file_tasks.cc b/chrome/browser/ash/file_manager/file_tasks.cc index 6d6fd943..125097c 100644 --- a/chrome/browser/ash/file_manager/file_tasks.cc +++ b/chrome/browser/ash/file_manager/file_tasks.cc
@@ -782,7 +782,6 @@ bool ExecuteFileTask(Profile* profile, const TaskDescriptor& task, const std::vector<FileSystemURL>& file_urls, - gfx::NativeWindow modal_parent, FileTaskFinishedCallback done) { // Save some of the arguments of "the most recent ExecuteFileTask" in JSON // (base::Value) format. @@ -818,7 +817,7 @@ RecordOfficeOpenExtensionDriveMetric(file_url); } const bool started = ExecuteWebDriveOfficeTask( - profile, task, file_urls, modal_parent, + profile, task, file_urls, std::make_unique<ash::cloud_upload::CloudOpenMetrics>( ash::cloud_upload::CloudProvider::kGoogleDrive, file_urls.size())); if (done) { @@ -839,7 +838,7 @@ RecordOfficeOpenExtensionOneDriveMetric(file_url); } const bool started = ExecuteOpenInOfficeTask( - profile, task, file_urls, modal_parent, + profile, task, file_urls, std::make_unique<ash::cloud_upload::CloudOpenMetrics>( ash::cloud_upload::CloudProvider::kOneDrive, file_urls.size())); if (done) { @@ -859,8 +858,7 @@ } // TODO(b/284800493): Add a test that VirtualTasks get run. if (IsVirtualTask(task)) { - const bool started = - ExecuteVirtualTask(profile, task, file_urls, modal_parent); + const bool started = ExecuteVirtualTask(profile, task, file_urls); if (done) { if (started) { std::move(done).Run(
diff --git a/chrome/browser/ash/file_manager/file_tasks.h b/chrome/browser/ash/file_manager/file_tasks.h index cdcf964..ee709e0 100644 --- a/chrome/browser/ash/file_manager/file_tasks.h +++ b/chrome/browser/ash/file_manager/file_tasks.h
@@ -105,7 +105,6 @@ #include "base/files/file_path.h" #include "base/functional/callback_forward.h" #include "chrome/common/extensions/api/file_manager_private.h" -#include "ui/gfx/native_widget_types.h" #include "url/gurl.h" class PrefService; @@ -298,15 +297,12 @@ // profile - The profile used for making this function call. // task - See the comment at TaskDescriptor struct. // file_urls - URLs of the target files. -// modal_parent - Certain tasks like the Office setup flow can create WebUIs, -// which will be made modal to this parent, if not null. // done - The callback which will be called on completion. // The callback won't be called if the function returns // false. bool ExecuteFileTask(Profile* profile, const TaskDescriptor& task, const std::vector<storage::FileSystemURL>& file_urls, - gfx::NativeWindow modal_parent, FileTaskFinishedCallback done); // See ash::FilesInternalsDebugJSONProvider::FunctionPointerType in
diff --git a/chrome/browser/ash/file_manager/file_tasks_browsertest.cc b/chrome/browser/ash/file_manager/file_tasks_browsertest.cc index 31f233be..ee80df6 100644 --- a/chrome/browser/ash/file_manager/file_tasks_browsertest.cc +++ b/chrome/browser/ash/file_manager/file_tasks_browsertest.cc
@@ -306,7 +306,7 @@ base::test::TestFuture<std::string> message; DomMessageObserverAsh observer(&message); lacros_waiter_->ObserveDomMessages(observer.Bind()); - ExecuteFileTask(profile(), task, files, nullptr, base::DoNothing()); + ExecuteFileTask(profile(), task, files, base::DoNothing()); return message.Get(); } @@ -344,7 +344,7 @@ const TaskDescriptor& task, const std::vector<storage::FileSystemURL>& files) override { content::DOMMessageQueue message_queue; - ExecuteFileTask(profile(), task, files, nullptr, base::DoNothing()); + ExecuteFileTask(profile(), task, files, base::DoNothing()); std::string message; CHECK(message_queue.WaitForMessage(&message)); return message; @@ -732,7 +732,7 @@ std::vector<storage::FileSystemURL> files; files.push_back(storage::FileSystemURL::CreateForTest(url1)); files.push_back(storage::FileSystemURL::CreateForTest(url2)); - ExecuteFileTask(profile, task_descriptor, files, nullptr, base::DoNothing()); + ExecuteFileTask(profile, task_descriptor, files, base::DoNothing()); run_loop.Run(); } @@ -798,7 +798,7 @@ // GetUserFallbackChoice() returns `True` because the Fallback dialog can be // shown. ASSERT_TRUE(GetUserFallbackChoice( - profile, CreateWebDriveOfficeTask(), {test_url}, nullptr, + profile, CreateWebDriveOfficeTask(), {test_url}, ash::office_fallback::FallbackReason::kOffline, std::make_unique<ash::cloud_upload::CloudOpenMetrics>( ash::cloud_upload::CloudProvider::kOneDrive, /*file_count=*/1))); @@ -820,7 +820,7 @@ // installed. storage::FileSystemURL test_url; ASSERT_FALSE(GetUserFallbackChoice( - browser()->profile(), CreateWebDriveOfficeTask(), {test_url}, nullptr, + browser()->profile(), CreateWebDriveOfficeTask(), {test_url}, ash::office_fallback::FallbackReason::kOffline, std::make_unique<ash::cloud_upload::CloudOpenMetrics>( ash::cloud_upload::CloudProvider::kOneDrive, /*file_count=*/1))); @@ -925,8 +925,8 @@ /*should_launch_browser=*/true, account_id); } - // Launch Files app and return its NativeWindow. - gfx::NativeWindow LaunchFilesAppAndWait() { + // Launch Files app and wait for it to open. + void LaunchFilesAppAndWait() { GURL files_swa_url = util::GetFileManagerMainPageUrlWithParams( ui::SelectFileDialog::SELECT_NONE, /*title=*/std::u16string(), /*current_directory_url=*/{}, @@ -940,8 +940,7 @@ params.url = files_swa_url; ash::LaunchSystemWebAppAsync(browser()->profile(), ash::SystemWebAppType::FILE_MANAGER, params); - Browser* files_app = ui_test_utils::WaitForBrowserToOpen(); - return files_app->window()->GetNativeWindow(); + ui_test_utils::WaitForBrowserToOpen(); } protected: @@ -1354,7 +1353,7 @@ // Launches the office fallback dialog as the system is offline. base::test::TestFuture<TaskResult, std::string> executed_future; - ExecuteFileTask(profile(), web_drive_office_task, file_urls, nullptr, + ExecuteFileTask(profile(), web_drive_office_task, file_urls, executed_future.GetCallback()); ASSERT_EQ(executed_future.Get<0>(), TaskResult::kOpened); @@ -1376,7 +1375,7 @@ // because system is online. OnDialogChoiceReceived(profile(), web_drive_office_task, file_urls, ash::office_fallback::FallbackReason::kOffline, - nullptr, std::move(cloud_open_metrics_), + std::move(cloud_open_metrics_), ash::office_fallback::kDialogChoiceTryAgain); // Wait for file to open in web drive office. @@ -1420,7 +1419,7 @@ auto task = base::WrapRefCounted(new ash::cloud_upload::CloudOpenTask( profile(), file_urls, ash::cloud_upload::CloudProvider::kGoogleDrive, - nullptr, std::move(cloud_open_metrics_))); + std::move(cloud_open_metrics_))); task->OpenOrMoveFiles(); // Wait for file to open in web drive office. @@ -1460,10 +1459,10 @@ expected_dialog_URL); navigation_observer_dialog.StartWatchingNewWebContents(); - gfx::NativeWindow modal_parent = LaunchFilesAppAndWait(); + LaunchFilesAppAndWait(); // Triggers setup flow. - ExecuteFileTask(profile(), web_drive_office_task, file_urls, modal_parent, + ExecuteFileTask(profile(), web_drive_office_task, file_urls, base::DoNothing()); // Wait for setup flow dialog to open. @@ -1497,10 +1496,10 @@ expected_dialog_URL); navigation_observer_dialog.StartWatchingNewWebContents(); - gfx::NativeWindow modal_parent = LaunchFilesAppAndWait(); + LaunchFilesAppAndWait(); // Triggers setup flow. - ExecuteFileTask(profile(), web_drive_office_task, file_urls, modal_parent, + ExecuteFileTask(profile(), web_drive_office_task, file_urls, base::DoNothing()); // Wait for setup flow dialog to open. @@ -1738,7 +1737,7 @@ // Launches the office fallback dialog as the system is offline. base::test::TestFuture<TaskResult, std::string> executed_future; - ExecuteFileTask(profile(), open_in_office_task, file_urls, nullptr, + ExecuteFileTask(profile(), open_in_office_task, file_urls, executed_future.GetCallback()); ASSERT_EQ(executed_future.Get<0>(), TaskResult::kOpened); @@ -1754,7 +1753,7 @@ // because system is online, and the file doesn't need to be moved. OnDialogChoiceReceived(profile(), open_in_office_task, file_urls, ash::office_fallback::FallbackReason::kOffline, - nullptr, std::move(cloud_open_metrics_), + std::move(cloud_open_metrics_), ash::office_fallback::kDialogChoiceTryAgain); auto launches = web_app_publisher_->GetLaunches(); @@ -1803,7 +1802,7 @@ // Launches the office fallback dialog as the system is offline. base::test::TestFuture<TaskResult, std::string> executed_future; - ExecuteFileTask(profile(), open_in_office_task, file_urls, nullptr, + ExecuteFileTask(profile(), open_in_office_task, file_urls, executed_future.GetCallback()); ASSERT_EQ(executed_future.Get<0>(), TaskResult::kOpened); @@ -1819,7 +1818,7 @@ // open. OnDialogChoiceReceived(profile(), open_in_office_task, file_urls, ash::office_fallback::FallbackReason::kOffline, - nullptr, std::move(cloud_open_metrics_), + std::move(cloud_open_metrics_), ash::office_fallback::kDialogChoiceCancel); ASSERT_EQ(0u, web_app_publisher_->GetLaunches().size()); @@ -1859,7 +1858,7 @@ // Launches the first office fallback dialog as the system is offline. Let it // hang waiting for a choice from the user. base::test::TestFuture<TaskResult, std::string> executed_future; - ExecuteFileTask(profile(), open_in_office_task, file_urls, nullptr, + ExecuteFileTask(profile(), open_in_office_task, file_urls, executed_future.GetCallback()); ASSERT_EQ(executed_future.Get<0>(), TaskResult::kOpened); @@ -1869,7 +1868,7 @@ // Fails to launch a second office fallback dialog. base::test::TestFuture<TaskResult, std::string> failed_future; - ExecuteFileTask(profile(), open_in_office_task, file_urls, nullptr, + ExecuteFileTask(profile(), open_in_office_task, file_urls, failed_future.GetCallback()); ASSERT_EQ(failed_future.Get<0>(), TaskResult::kFailed); @@ -1901,7 +1900,7 @@ // Open file directly from ODFS. auto task = base::WrapRefCounted(new ash::cloud_upload::CloudOpenTask( profile(), file_urls, ash::cloud_upload::CloudProvider::kOneDrive, - nullptr, std::move(cloud_open_metrics_))); + std::move(cloud_open_metrics_))); task->OpenOrMoveFiles(); auto launches = web_app_publisher_->GetLaunches(); @@ -1936,12 +1935,12 @@ expected_dialog_URL); navigation_observer_dialog.StartWatchingNewWebContents(); - gfx::NativeWindow modal_parent = LaunchFilesAppAndWait(); + LaunchFilesAppAndWait(); // Triggers Move Confirmation dialog. auto task = base::WrapRefCounted(new ash::cloud_upload::CloudOpenTask( profile(), file_urls, ash::cloud_upload::CloudProvider::kOneDrive, - modal_parent, std::move(cloud_open_metrics_))); + std::move(cloud_open_metrics_))); task->OpenOrMoveFiles(); // Wait for Move Confirmation dialog to open. @@ -1976,7 +1975,7 @@ // Open file directly from ODFS. auto task = base::WrapRefCounted(new ash::cloud_upload::CloudOpenTask( profile(), file_urls, ash::cloud_upload::CloudProvider::kOneDrive, - nullptr, std::move(cloud_open_metrics_))); + std::move(cloud_open_metrics_))); task->OpenOrMoveFiles(); // Expect that there was a notification. EXPECT_FALSE(notification_message_.empty()); @@ -2023,7 +2022,7 @@ // Open file directly from ODFS. auto task = base::WrapRefCounted(new ash::cloud_upload::CloudOpenTask( profile(), file_urls, ash::cloud_upload::CloudProvider::kOneDrive, - nullptr, std::move(cloud_open_metrics_))); + std::move(cloud_open_metrics_))); task->OpenOrMoveFiles(); // Expect that there was a notification. EXPECT_FALSE(notification_message_.empty()); @@ -2070,7 +2069,7 @@ // Open the file indirectly from Android OneDrive (via ODFS). auto task = base::WrapRefCounted(new ash::cloud_upload::CloudOpenTask( profile(), {android_onedrive_url}, - ash::cloud_upload::CloudProvider::kOneDrive, nullptr, + ash::cloud_upload::CloudProvider::kOneDrive, std::move(cloud_open_metrics_))); task->OpenOrMoveFiles(); @@ -2124,7 +2123,7 @@ // will fail as the email accounts don't match. auto task = base::WrapRefCounted(new ash::cloud_upload::CloudOpenTask( profile(), {android_onedrive_url}, - ash::cloud_upload::CloudProvider::kOneDrive, nullptr, + ash::cloud_upload::CloudProvider::kOneDrive, std::move(cloud_open_metrics_))); task->OpenOrMoveFiles(); @@ -2167,7 +2166,7 @@ // will fail as there is not an equivalent ODFS file path. auto task = base::WrapRefCounted(new ash::cloud_upload::CloudOpenTask( profile(), {android_onedrive_url}, - ash::cloud_upload::CloudProvider::kOneDrive, nullptr, + ash::cloud_upload::CloudProvider::kOneDrive, std::move(cloud_open_metrics_))); task->OpenOrMoveFiles(); @@ -2215,7 +2214,7 @@ // will fail as there is not an equivalent ODFS file path. auto task = base::WrapRefCounted(new ash::cloud_upload::CloudOpenTask( profile(), {android_onedrive_url}, - ash::cloud_upload::CloudProvider::kOneDrive, nullptr, + ash::cloud_upload::CloudProvider::kOneDrive, std::move(cloud_open_metrics_))); task->OpenOrMoveFiles(); @@ -2241,7 +2240,7 @@ IN_PROC_BROWSER_TEST_F(OneDriveTest, FileInOneDriveOpensSetUpDialog) { // Do this before SetUpTest creates a FakeWebAppPublisher which would // intercept Files app launching. - gfx::NativeWindow modal_parent = LaunchFilesAppAndWait(); + LaunchFilesAppAndWait(); // Creates a fake ODFS with a test file. SetUpTest(); @@ -2260,8 +2259,7 @@ navigation_observer_dialog.StartWatchingNewWebContents(); // Triggers setup flow. - ExecuteFileTask(profile(), open_in_office_task, file_urls, modal_parent, - base::DoNothing()); + ExecuteFileTask(profile(), open_in_office_task, file_urls, base::DoNothing()); // Wait for setup flow dialog to open. navigation_observer_dialog.Wait(); @@ -2290,11 +2288,10 @@ expected_dialog_URL); navigation_observer_dialog.StartWatchingNewWebContents(); - gfx::NativeWindow modal_parent = LaunchFilesAppAndWait(); + LaunchFilesAppAndWait(); // Triggers setup flow. - ExecuteFileTask(profile(), open_in_office_task, file_urls, modal_parent, - base::DoNothing()); + ExecuteFileTask(profile(), open_in_office_task, file_urls, base::DoNothing()); // Wait for setup flow dialog to open. navigation_observer_dialog.Wait();
diff --git a/chrome/browser/ash/file_manager/office_file_tasks.cc b/chrome/browser/ash/file_manager/office_file_tasks.cc index acfa1647..9ea10b4d 100644 --- a/chrome/browser/ash/file_manager/office_file_tasks.cc +++ b/chrome/browser/ash/file_manager/office_file_tasks.cc
@@ -185,11 +185,10 @@ Profile* profile, const TaskDescriptor& task, const std::vector<storage::FileSystemURL>& file_urls, - gfx::NativeWindow modal_parent, std::unique_ptr<ash::cloud_upload::CloudOpenMetrics> cloud_open_metrics) { if (!drive::util::IsDriveEnabledForProfile(profile)) { return GetUserFallbackChoice( - profile, task, file_urls, modal_parent, + profile, task, file_urls, ash::office_fallback::FallbackReason::kDriveDisabled, std::move(cloud_open_metrics)); } @@ -200,7 +199,7 @@ opt_fallback_reason = DriveConnectionStatusToFallbackReason(drive_connection_status); if (opt_fallback_reason) { - return GetUserFallbackChoice(profile, task, file_urls, modal_parent, + return GetUserFallbackChoice(profile, task, file_urls, opt_fallback_reason.value(), std::move(cloud_open_metrics)); } @@ -210,31 +209,30 @@ if (!integration_service || !integration_service->IsMounted() || !integration_service->GetDriveFsInterface()) { return GetUserFallbackChoice( - profile, task, file_urls, modal_parent, + profile, task, file_urls, ash::office_fallback::FallbackReason::kDriveFsInterfaceError, std::move(cloud_open_metrics)); } return ash::cloud_upload::CloudOpenTask::Execute( profile, file_urls, ash::cloud_upload::CloudProvider::kGoogleDrive, - modal_parent, std::move(cloud_open_metrics)); + std::move(cloud_open_metrics)); } bool ExecuteOpenInOfficeTask( Profile* profile, const TaskDescriptor& task, const std::vector<storage::FileSystemURL>& file_urls, - gfx::NativeWindow modal_parent, std::unique_ptr<ash::cloud_upload::CloudOpenMetrics> cloud_open_metrics) { if (content::GetNetworkConnectionTracker()->IsOffline()) { - return GetUserFallbackChoice(profile, task, file_urls, modal_parent, + return GetUserFallbackChoice(profile, task, file_urls, ash::office_fallback::FallbackReason::kOffline, std::move(cloud_open_metrics)); } return ash::cloud_upload::CloudOpenTask::Execute( profile, file_urls, ash::cloud_upload::CloudProvider::kOneDrive, - modal_parent, std::move(cloud_open_metrics)); + std::move(cloud_open_metrics)); } void LaunchQuickOffice(Profile* profile, @@ -244,7 +242,7 @@ kActionIdQuickOffice); ExecuteFileTask( - profile, quick_office_task, file_urls, /* modal_parent */ nullptr, + profile, quick_office_task, file_urls, base::BindOnce( [](extensions::api::file_manager_private::TaskResult result, std::string error_message) { @@ -264,7 +262,6 @@ const TaskDescriptor& task, const std::vector<storage::FileSystemURL>& file_urls, ash::office_fallback::FallbackReason fallback_reason, - gfx::NativeWindow modal_parent, std::unique_ptr<ash::cloud_upload::CloudOpenMetrics> cloud_open_metrics, std::optional<const std::string> choice) { if (!choice.has_value()) { @@ -302,10 +299,10 @@ // Only the last open result is recorded: when the user either selects // QO or cancels. if (IsWebDriveOfficeTask(task)) { - ExecuteWebDriveOfficeTask(profile, task, file_urls, modal_parent, + ExecuteWebDriveOfficeTask(profile, task, file_urls, std::move(cloud_open_metrics)); } else if (IsOpenInOfficeTask(task)) { - ExecuteOpenInOfficeTask(profile, task, file_urls, modal_parent, + ExecuteOpenInOfficeTask(profile, task, file_urls, std::move(cloud_open_metrics)); } } else if (choice.value() == ash::office_fallback::kDialogChoiceCancel) { @@ -327,7 +324,6 @@ Profile* profile, const TaskDescriptor& task, const std::vector<storage::FileSystemURL>& file_urls, - gfx::NativeWindow modal_parent, ash::office_fallback::FallbackReason fallback_reason, std::unique_ptr<ash::cloud_upload::CloudOpenMetrics> cloud_open_metrics) { // TODO(b/242685536) Add support for multi-file @@ -335,9 +331,9 @@ // `OnDialogChoiceReceived()` can open multiple files. std::vector<storage::FileSystemURL> first_url{file_urls.front()}; - ash::office_fallback::DialogChoiceCallback callback = base::BindOnce( - &OnDialogChoiceReceived, profile, task, first_url, fallback_reason, - modal_parent, std::move(cloud_open_metrics)); + ash::office_fallback::DialogChoiceCallback callback = + base::BindOnce(&OnDialogChoiceReceived, profile, task, first_url, + fallback_reason, std::move(cloud_open_metrics)); // If QuickOffice is not installed, don't launch dialog. if (!IsQuickOfficeInstalled(profile)) {
diff --git a/chrome/browser/ash/file_manager/office_file_tasks.h b/chrome/browser/ash/file_manager/office_file_tasks.h index 237e851..b5f1db1 100644 --- a/chrome/browser/ash/file_manager/office_file_tasks.h +++ b/chrome/browser/ash/file_manager/office_file_tasks.h
@@ -12,7 +12,6 @@ #include "base/files/file_path.h" #include "base/time/time.h" #include "chrome/browser/ui/webui/ash/office_fallback/office_fallback_dialog.h" -#include "ui/gfx/native_widget_types.h" class Profile; @@ -109,7 +108,6 @@ Profile* profile, const TaskDescriptor& task, const std::vector<storage::FileSystemURL>& file_urls, - gfx::NativeWindow modal_parent, std::unique_ptr<ash::cloud_upload::CloudOpenMetrics> cloud_open_metrics); // Open files with Office365. @@ -117,7 +115,6 @@ Profile* profile, const TaskDescriptor& task, const std::vector<storage::FileSystemURL>& file_urls, - gfx::NativeWindow modal_parent, std::unique_ptr<ash::cloud_upload::CloudOpenMetrics> cloud_open_metrics); // Executes QuickOffice file handler for each element of |file_urls|. @@ -133,7 +130,6 @@ const TaskDescriptor& task, const std::vector<storage::FileSystemURL>& file_urls, ash::office_fallback::FallbackReason fallback_reason, - gfx::NativeWindow modal_parent, std::unique_ptr<ash::cloud_upload::CloudOpenMetrics> cloud_open_metrics, std::optional<const std::string> choice); @@ -143,7 +139,6 @@ Profile* profile, const TaskDescriptor& task, const std::vector<storage::FileSystemURL>& file_urls, - gfx::NativeWindow modal_parent, ash::office_fallback::FallbackReason failure_reason, std::unique_ptr<ash::cloud_upload::CloudOpenMetrics> cloud_open_metrics);
diff --git a/chrome/browser/ash/file_manager/open_util.cc b/chrome/browser/ash/file_manager/open_util.cc index 4ef20d28..5af88a9 100644 --- a/chrome/browser/ash/file_manager/open_util.cc +++ b/chrome/browser/ash/file_manager/open_util.cc
@@ -52,13 +52,11 @@ storage::FileSystemContext* file_system_context = GetFileManagerFileSystemContext(profile); - // There is no Files app window for spawned WebUI to be modal to. - gfx::NativeWindow modal_parent = gfx::NativeWindow(); file_tasks::ExecuteFileTask( profile, task, std::vector<FileSystemURL>( 1, file_system_context->CrackURLInFirstPartyContext(url)), - modal_parent, base::BindOnce(&IgnoreFileTaskExecuteResult)); + base::BindOnce(&IgnoreFileTaskExecuteResult)); } // Opens the file manager for the specified |url|. Used to implement
diff --git a/chrome/browser/ash/file_manager/virtual_file_tasks.cc b/chrome/browser/ash/file_manager/virtual_file_tasks.cc index ef36d04..09b1c87 100644 --- a/chrome/browser/ash/file_manager/virtual_file_tasks.cc +++ b/chrome/browser/ash/file_manager/virtual_file_tasks.cc
@@ -108,13 +108,12 @@ bool ExecuteVirtualTask(Profile* profile, const TaskDescriptor& task, - const std::vector<FileSystemURL>& file_urls, - gfx::NativeWindow modal_parent) { + const std::vector<FileSystemURL>& file_urls) { auto* virtual_task = FindVirtualTask(task); if (!virtual_task || !virtual_task->IsEnabled(profile)) { return false; } - return virtual_task->Execute(profile, task, file_urls, modal_parent); + return virtual_task->Execute(profile, task, file_urls); } bool IsVirtualTask(const TaskDescriptor& task) {
diff --git a/chrome/browser/ash/file_manager/virtual_file_tasks.h b/chrome/browser/ash/file_manager/virtual_file_tasks.h index f56bc9d..18efe01 100644 --- a/chrome/browser/ash/file_manager/virtual_file_tasks.h +++ b/chrome/browser/ash/file_manager/virtual_file_tasks.h
@@ -34,8 +34,7 @@ // started running, if there are async steps. virtual bool Execute(Profile* profile, const TaskDescriptor& task, - const std::vector<FileSystemURL>& file_urls, - gfx::NativeWindow modal_parent) const = 0; + const std::vector<FileSystemURL>& file_urls) const = 0; // Whether this task should be included in |FindVirtualTasks()|. This can be // used to disable tasks based on a flag or other runtime conditions. virtual bool IsEnabled(Profile* profile) const = 0; @@ -76,8 +75,7 @@ // Run |task| by calling |Execute()| on the associated VirtualTask. bool ExecuteVirtualTask(Profile* profile, const TaskDescriptor& task, - const std::vector<FileSystemURL>& file_urls, - gfx::NativeWindow modal_parent); + const std::vector<FileSystemURL>& file_urls); // Whether |task| is a virtual task and can be executed using // |ExecuteVirtualTask()|. Returns true for disabled tasks, too.
diff --git a/chrome/browser/ash/file_manager/virtual_file_tasks_unittest.cc b/chrome/browser/ash/file_manager/virtual_file_tasks_unittest.cc index a58738f..8490a848 100644 --- a/chrome/browser/ash/file_manager/virtual_file_tasks_unittest.cc +++ b/chrome/browser/ash/file_manager/virtual_file_tasks_unittest.cc
@@ -91,8 +91,7 @@ TEST_F(VirtualFileTasksTest, ExecuteVirtualTask_WrongApp) { TaskDescriptor wrong_app = {"random_app", TASK_TYPE_WEB_APP, task1->id()}; bool result = - ExecuteVirtualTask(/*profile=*/nullptr, wrong_app, /*file_urls=*/{}, - /*modal_parent=*/nullptr); + ExecuteVirtualTask(/*profile=*/nullptr, wrong_app, /*file_urls=*/{}); ASSERT_FALSE(result); ASSERT_EQ(task1_executed_, 0); } @@ -100,9 +99,8 @@ TEST_F(VirtualFileTasksTest, ExecuteVirtualTask_WrongActionId) { TaskDescriptor wrong_action_id = {kFileManagerSwaAppId, TASK_TYPE_WEB_APP, "https://app/wrongaction"}; - bool result = - ExecuteVirtualTask(/*profile=*/nullptr, wrong_action_id, /*file_urls=*/{}, - /*modal_parent=*/nullptr); + bool result = ExecuteVirtualTask(/*profile=*/nullptr, wrong_action_id, + /*file_urls=*/{}); ASSERT_FALSE(result); ASSERT_EQ(task1_executed_, 0); } @@ -111,8 +109,7 @@ TaskDescriptor ok_task = {kFileManagerSwaAppId, TASK_TYPE_WEB_APP, task1->id()}; bool result = - ExecuteVirtualTask(/*profile=*/nullptr, ok_task, /*file_urls=*/{}, - /*modal_parent=*/nullptr); + ExecuteVirtualTask(/*profile=*/nullptr, ok_task, /*file_urls=*/{}); ASSERT_TRUE(result); ASSERT_EQ(task1_executed_, 1); } @@ -121,8 +118,7 @@ TaskDescriptor disabled_task = {kFileManagerSwaAppId, TASK_TYPE_WEB_APP, task2->id()}; bool result = - ExecuteVirtualTask(/*profile=*/nullptr, disabled_task, /*file_urls=*/{}, - /*modal_parent=*/nullptr); + ExecuteVirtualTask(/*profile=*/nullptr, disabled_task, /*file_urls=*/{}); ASSERT_FALSE(result); ASSERT_EQ(task2_executed_, 0); } @@ -131,8 +127,7 @@ TaskDescriptor execute_false = {kFileManagerSwaAppId, TASK_TYPE_WEB_APP, task3->id()}; bool result = - ExecuteVirtualTask(/*profile=*/nullptr, execute_false, /*file_urls=*/{}, - /*modal_parent=*/nullptr); + ExecuteVirtualTask(/*profile=*/nullptr, execute_false, /*file_urls=*/{}); ASSERT_FALSE(result); ASSERT_EQ(task3_executed_, 1); }
diff --git a/chrome/browser/ash/file_manager/virtual_tasks/fake_virtual_task.cc b/chrome/browser/ash/file_manager/virtual_tasks/fake_virtual_task.cc index 4b3d89c..d269f00 100644 --- a/chrome/browser/ash/file_manager/virtual_tasks/fake_virtual_task.cc +++ b/chrome/browser/ash/file_manager/virtual_tasks/fake_virtual_task.cc
@@ -17,10 +17,10 @@ FakeVirtualTask::~FakeVirtualTask() = default; -bool FakeVirtualTask::Execute(Profile* profile, - const TaskDescriptor& task, - const std::vector<FileSystemURL>& file_urls, - gfx::NativeWindow modal_parent) const { +bool FakeVirtualTask::Execute( + Profile* profile, + const TaskDescriptor& task, + const std::vector<FileSystemURL>& file_urls) const { return execute_cb_ ? execute_cb_.Run() : true; }
diff --git a/chrome/browser/ash/file_manager/virtual_tasks/fake_virtual_task.h b/chrome/browser/ash/file_manager/virtual_tasks/fake_virtual_task.h index 9791dee..672c62fa 100644 --- a/chrome/browser/ash/file_manager/virtual_tasks/fake_virtual_task.h +++ b/chrome/browser/ash/file_manager/virtual_tasks/fake_virtual_task.h
@@ -26,8 +26,7 @@ bool Execute(Profile* profile, const TaskDescriptor& task, - const std::vector<FileSystemURL>& file_urls, - gfx::NativeWindow modal_parent) const override; + const std::vector<FileSystemURL>& file_urls) const override; bool IsEnabled(Profile* profile) const override; bool Matches(const std::vector<extensions::EntryInfo>& entries, const std::vector<GURL>& file_urls,
diff --git a/chrome/browser/ash/file_manager/virtual_tasks/install_isolated_web_app_virtual_task.cc b/chrome/browser/ash/file_manager/virtual_tasks/install_isolated_web_app_virtual_task.cc index d3be1711..d770e37 100644 --- a/chrome/browser/ash/file_manager/virtual_tasks/install_isolated_web_app_virtual_task.cc +++ b/chrome/browser/ash/file_manager/virtual_tasks/install_isolated_web_app_virtual_task.cc
@@ -25,7 +25,6 @@ #include "storage/browser/file_system/file_system_url.h" #include "ui/base/l10n/l10n_util.h" #include "ui/chromeos/strings/grit/ui_chromeos_strings.h" -#include "ui/gfx/native_widget_types.h" #include "url/gurl.h" namespace file_manager::file_tasks { @@ -57,8 +56,7 @@ bool InstallIsolatedWebAppVirtualTask::Execute( Profile* profile, const TaskDescriptor& task, - const std::vector<storage::FileSystemURL>& file_urls, - gfx::NativeWindow modal_parent) const { + const std::vector<storage::FileSystemURL>& file_urls) const { if (file_urls.empty()) { return false; }
diff --git a/chrome/browser/ash/file_manager/virtual_tasks/install_isolated_web_app_virtual_task.h b/chrome/browser/ash/file_manager/virtual_tasks/install_isolated_web_app_virtual_task.h index 90a6c59..76914846 100644 --- a/chrome/browser/ash/file_manager/virtual_tasks/install_isolated_web_app_virtual_task.h +++ b/chrome/browser/ash/file_manager/virtual_tasks/install_isolated_web_app_virtual_task.h
@@ -9,7 +9,6 @@ #include <vector> #include "chrome/browser/ash/file_manager/virtual_file_tasks.h" -#include "ui/gfx/native_widget_types.h" class GURL; class Profile; @@ -36,10 +35,10 @@ GURL icon_url() const override; - bool Execute(Profile* profile, - const TaskDescriptor& task, - const std::vector<storage::FileSystemURL>& file_urls, - gfx::NativeWindow modal_parent) const override; + bool Execute( + Profile* profile, + const TaskDescriptor& task, + const std::vector<storage::FileSystemURL>& file_urls) const override; }; } // namespace file_manager::file_tasks
diff --git a/chrome/browser/ash/file_manager/virtual_tasks/install_isolated_web_app_virtual_task_unittest.cc b/chrome/browser/ash/file_manager/virtual_tasks/install_isolated_web_app_virtual_task_unittest.cc index f9dba16..df733718 100644 --- a/chrome/browser/ash/file_manager/virtual_tasks/install_isolated_web_app_virtual_task_unittest.cc +++ b/chrome/browser/ash/file_manager/virtual_tasks/install_isolated_web_app_virtual_task_unittest.cc
@@ -88,7 +88,7 @@ return ExecuteVirtualTask( &profile_, {kFileManagerSwaAppId, TASK_TYPE_WEB_APP, task_.id()}, - file_system_urls, /*modal_parent=*/nullptr); + file_system_urls); } private:
diff --git a/chrome/browser/ash/guest_os/public/guest_os_service_factory.cc b/chrome/browser/ash/guest_os/public/guest_os_service_factory.cc index 46c3464..1cd019f 100644 --- a/chrome/browser/ash/guest_os/public/guest_os_service_factory.cc +++ b/chrome/browser/ash/guest_os/public/guest_os_service_factory.cc
@@ -40,12 +40,13 @@ GuestOsServiceFactory::~GuestOsServiceFactory() = default; -KeyedService* GuestOsServiceFactory::BuildServiceInstanceFor( +std::unique_ptr<KeyedService> +GuestOsServiceFactory::BuildServiceInstanceForBrowserContext( content::BrowserContext* context) const { Profile* profile = Profile::FromBrowserContext(context); if (!profile) return nullptr; - return new GuestOsService(profile); + return std::make_unique<GuestOsService>(profile); } } // namespace guest_os
diff --git a/chrome/browser/ash/guest_os/public/guest_os_service_factory.h b/chrome/browser/ash/guest_os/public/guest_os_service_factory.h index 723e5a8..b20b3d3 100644 --- a/chrome/browser/ash/guest_os/public/guest_os_service_factory.h +++ b/chrome/browser/ash/guest_os/public/guest_os_service_factory.h
@@ -29,7 +29,7 @@ ~GuestOsServiceFactory() override; // BrowserContextKeyedServiceFactory: - KeyedService* BuildServiceInstanceFor( + std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext( content::BrowserContext* context) const override; };
diff --git a/chrome/browser/ash/wallpaper_handlers/sea_pen_utils.cc b/chrome/browser/ash/wallpaper_handlers/sea_pen_utils.cc index 4eaef4d8..1588bc5 100644 --- a/chrome/browser/ash/wallpaper_handlers/sea_pen_utils.cc +++ b/chrome/browser/ash/wallpaper_handlers/sea_pen_utils.cc
@@ -10,6 +10,8 @@ namespace wallpaper_handlers { +// Generated by sea_pen_client_generator.py, do not edit. +// TODO(b/318565684): Move generated code to a separate file. namespace { std::string TemplateIdToString( @@ -23,6 +25,18 @@ return "landscape"; case ash::personalization_app::mojom::SeaPenTemplateId::kScifi: return "scifi"; + case ash::personalization_app::mojom::SeaPenTemplateId::kArt: + return "art"; + case ash::personalization_app::mojom::SeaPenTemplateId::kCharacters: + return "characters"; + case ash::personalization_app::mojom::SeaPenTemplateId::kTerrain: + return "terrain"; + case ash::personalization_app::mojom::SeaPenTemplateId::kCurious: + return "curious"; + case ash::personalization_app::mojom::SeaPenTemplateId::kDreamscapes: + return "dreamscapes"; + case ash::personalization_app::mojom::SeaPenTemplateId::kTranslucent: + return "translucent"; } } @@ -46,6 +60,41 @@ return "<scifi_feature>"; case ash::personalization_app::mojom::SeaPenTemplateChip::kScifiColor: return "<scifi_color>"; + case ash::personalization_app::mojom::SeaPenTemplateChip::kArtFeature: + return "<art_feature>"; + case ash::personalization_app::mojom::SeaPenTemplateChip::kArtMovement: + return "<art_movement>"; + case ash::personalization_app::mojom::SeaPenTemplateChip::kCharactersColor: + return "<characters_color>"; + case ash::personalization_app::mojom::SeaPenTemplateChip:: + kCharactersSubjects: + return "<characters_subjects>"; + case ash::personalization_app::mojom::SeaPenTemplateChip:: + kCharactersBackground: + return "<characters_background>"; + case ash::personalization_app::mojom::SeaPenTemplateChip::kTerrainFeature: + return "<terrain_feature>"; + case ash::personalization_app::mojom::SeaPenTemplateChip::kTerrainColor: + return "<terrain_color>"; + case ash::personalization_app::mojom::SeaPenTemplateChip::kCuriousSubject: + return "<curious_subject>"; + case ash::personalization_app::mojom::SeaPenTemplateChip::kCuriousFeature: + return "<curious_feature>"; + case ash::personalization_app::mojom::SeaPenTemplateChip::kCuriousColor: + return "<curious_color>"; + case ash::personalization_app::mojom::SeaPenTemplateChip:: + kDreamscapesObject: + return "<dreamscapes_object>"; + case ash::personalization_app::mojom::SeaPenTemplateChip:: + kDreamscapesMaterial: + return "<dreamscapes_material>"; + case ash::personalization_app::mojom::SeaPenTemplateChip:: + kDreamscapesColors: + return "<dreamscapes_colors>"; + case ash::personalization_app::mojom::SeaPenTemplateChip::kTranslucentItem: + return "<translucent_item>"; + case ash::personalization_app::mojom::SeaPenTemplateChip::kTranslucentColor: + return "<translucent_color>"; } } @@ -305,6 +354,870 @@ case ash::personalization_app::mojom::SeaPenTemplateOption:: kScifiColorNeutral: return "neutral"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kArtFeatureCanyon: + return "canyon"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kArtFeatureMountain: + return "mountain"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kArtFeatureBeach: + return "beach"; + case ash::personalization_app::mojom::SeaPenTemplateOption::kArtFeatureCave: + return "cave"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kArtFeatureCliff: + return "cliff"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kArtFeatureForest: + return "forest"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kArtFeatureGlacier: + return "glacier"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kArtFeatureIsland: + return "island"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kArtFeatureJungle: + return "jungle"; + case ash::personalization_app::mojom::SeaPenTemplateOption::kArtFeatureLake: + return "lake"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kArtFeatureMeadow: + return "meadow"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kArtFeatureOcean: + return "ocean"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kArtFeatureRiver: + return "river"; + case ash::personalization_app::mojom::SeaPenTemplateOption::kArtFeatureDune: + return "dune"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kArtFeatureSwamp: + return "swamp"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kArtFeatureValley: + return "valley"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kArtFeatureWaterfall: + return "waterfall"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kArtFeatureField: + return "field"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kArtFeatureCityscape: + return "cityscape"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kArtFeatureVillage: + return "village"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kArtMovementAvantGarde: + return "avant_garde"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kArtMovementRealism: + return "realism"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kArtMovementExpressionism: + return "expressionism"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kArtMovementImpressionism: + return "impressionism"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kArtMovementPostImpressionism: + return "post_impressionism"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kArtMovementArtNouveau: + return "art_nouveau"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kArtMovementBaroque: + return "baroque"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kArtMovementBauhaus: + return "bauhaus"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kArtMovementClassicism: + return "classicism"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kArtMovementWatercolor: + return "watercolor"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kArtMovementAbstract: + return "abstract"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kArtMovementPointillism: + return "pointillism"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kArtMovementGraphicDesign: + return "graphic_design"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kArtMovementModernArt: + return "modern_art"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersColorYellow: + return "yellow"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersColorPink: + return "pink"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersColorRed: + return "red"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersColorBlue: + return "blue"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersColorIndigo: + return "indigo"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersColorGreen: + return "green"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersColorEmerald: + return "emerald"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersColorTeal: + return "teal"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersColorCyan: + return "cyan"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersColorPurple: + return "purple"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersColorBrown: + return "brown"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersColorGold: + return "gold"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersColorBurntOrange: + return "burnt_orange"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersColorRust: + return "rust"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersColorOlive: + return "olive"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersColorGray: + return "gray"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersColorViolet: + return "violet"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersColorWhite: + return "white"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersColorBeige: + return "beige"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersColorIvory: + return "ivory"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersColorCream: + return "cream"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersColorMagenta: + return "magenta"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersColorLimeGreen: + return "lime_green"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersColorFuschia: + return "fuschia"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersColorElectricBlue: + return "electric_blue"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersColorHotPink: + return "hot_pink"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersColorNeonGreen: + return "neon_green"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersColorSkyBlue: + return "sky_blue"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersColorElectricPurple: + return "electric_purple"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersColorFireEngineRed: + return "fire_engine_red"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersColorNeonPink: + return "neon_pink"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersColorChartreuse: + return "chartreuse"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersColorCobalt: + return "cobalt"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersColorLemonYellow: + return "lemon_yellow"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersColorCoralPink: + return "coral_pink"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersColorVibrantViolet: + return "vibrant_violet"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersColorPeacockBlue: + return "peacock_blue"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersSubjectsLemons: + return "lemons"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersSubjectsFlowers: + return "flowers"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersSubjectsApples: + return "apples"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersSubjectsCherries: + return "cherries"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersSubjectsOranges: + return "oranges"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersSubjectsPineapples: + return "pineapples"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersSubjectsStrawberries: + return "strawberries"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersSubjectsWatermelons: + return "watermelons"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersSubjectsPotatoes: + return "potatoes"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersSubjectsSushi: + return "sushi"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersSubjectsBaconAndEggs: + return "bacon_and_eggs"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersSubjectsPizza: + return "pizza"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersSubjectsHotDogs: + return "hot_dogs"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersSubjectsHamburgers: + return "hamburgers"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersSubjectsRamen: + return "ramen"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersSubjectsTacos: + return "tacos"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersSubjectsBunnies: + return "bunnies"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersSubjectsCats: + return "cats"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersSubjectsDogs: + return "dogs"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersSubjectsKoalas: + return "koalas"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersSubjectsPandas: + return "pandas"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersSubjectsPenguins: + return "penguins"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersSubjectsPigs: + return "pigs"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersSubjectsSloths: + return "sloths"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersSubjectsPonies: + return "ponies"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersSubjectsElephants: + return "elephants"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersSubjectsFoxes: + return "foxes"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersSubjectsOwls: + return "owls"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersSubjectsCrabs: + return "crabs"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersSubjectsBees: + return "bees"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersSubjectsButterflies: + return "butterflies"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersSubjectsBicycles: + return "bicycles"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersSubjectsBoats: + return "boats"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersSubjectsBooks: + return "books"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersSubjectsCutlery: + return "cutlery"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersSubjectsUmbrellas: + return "umbrellas"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersSubjectsInstruments: + return "instruments"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersBackgroundPurple: + return "purple"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersBackgroundBlue: + return "blue"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersBackgroundIndigo: + return "indigo"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersBackgroundGreen: + return "green"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersBackgroundEmerald: + return "emerald"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersBackgroundTeal: + return "teal"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersBackgroundCyan: + return "cyan"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersBackgroundBrown: + return "brown"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersBackgroundGold: + return "gold"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersBackgroundRed: + return "red"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersBackgroundBurntOrange: + return "burnt_orange"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersBackgroundRust: + return "rust"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersBackgroundOlive: + return "olive"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersBackgroundPink: + return "pink"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersBackgroundGray: + return "gray"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersBackgroundYellow: + return "yellow"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersBackgroundViolet: + return "violet"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersBackgroundWhite: + return "white"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersBackgroundBeige: + return "beige"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersBackgroundIvory: + return "ivory"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersBackgroundCream: + return "cream"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersBackgroundMagenta: + return "magenta"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersBackgroundLimeGreen: + return "lime_green"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersBackgroundFuschia: + return "fuschia"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersBackgroundElectricBlue: + return "electric_blue"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersBackgroundHotPink: + return "hot_pink"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersBackgroundNeonGreen: + return "neon_green"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersBackgroundSkyBlue: + return "sky_blue"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersBackgroundElectricPurple: + return "electric_purple"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersBackgroundFireEngineRed: + return "fire_engine_red"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersBackgroundNeonPink: + return "neon_pink"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersBackgroundChartreuse: + return "chartreuse"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersBackgroundCobalt: + return "cobalt"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersBackgroundLemonYellow: + return "lemon_yellow"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersBackgroundCoralPink: + return "coral_pink"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersBackgroundVibrantViolet: + return "vibrant_violet"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersBackgroundPeacockBlue: + return "peacock_blue"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTerrainFeatureSaltLake: + return "salt_lake"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTerrainFeatureRiver: + return "river"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTerrainFeatureNorthernLights: + return "northern_lights"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTerrainFeatureWhiteDunes: + return "white_dunes"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTerrainFeatureClayHills: + return "clay_hills"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTerrainFeatureSandyLagoons: + return "sandy_lagoons"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTerrainFeatureMountains: + return "mountains"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTerrainFeatureBioluminescentBeach: + return "bioluminescent_beach"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTerrainFeatureFireflyForest: + return "firefly_forest"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTerrainFeatureSandDunes: + return "sand_dunes"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTerrainColorPink: + return "pink"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTerrainColorTeal: + return "teal"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTerrainColorWhite: + return "white"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTerrainColorPurple: + return "purple"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTerrainColorBlue: + return "blue"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTerrainColorYellow: + return "yellow"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTerrainColorMaroonPink: + return "maroon_pink"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTerrainColorBluePurple: + return "blue_purple"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTerrainColorPinkYellow: + return "pink_yellow"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTerrainColorBluePink: + return "blue_pink"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCuriousSubjectCherryBlossoms: + return "cherry_blossoms"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCuriousSubjectJasmineFlowers: + return "jasmine_flowers"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCuriousSubjectDaisies: + return "daisies"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCuriousSubjectTulips: + return "tulips"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCuriousSubjectCarnations: + return "carnations"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCuriousSubjectDaffodils: + return "daffodils"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCuriousSubjectForgetMeNots: + return "forget_me_nots"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCuriousSubjectSunflowers: + return "sunflowers"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCuriousSubjectBougainvilleas: + return "bougainvilleas"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCuriousSubjectAirPlants: + return "air_plants"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCuriousSubjectSucculents: + return "succulents"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCuriousFeatureAlpineLake: + return "alpine_lake"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCuriousFeatureGalaxy: + return "galaxy"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCuriousFeatureSandDunes: + return "sand_dunes"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCuriousFeatureSwamp: + return "swamp"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCuriousFeatureBeach: + return "beach"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCuriousFeatureMountains: + return "mountains"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCuriousFeatureRiver: + return "river"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCuriousFeatureWaterfall: + return "waterfall"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCuriousColorBlue: + return "blue"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCuriousColorRed: + return "red"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCuriousColorYellow: + return "yellow"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCuriousColorGreen: + return "green"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCuriousColorPurple: + return "purple"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCuriousColorOrange: + return "orange"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCuriousColorPink: + return "pink"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCuriousColorBrown: + return "brown"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCuriousColorBlack: + return "black"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCuriousColorTurquoise: + return "turquoise"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCuriousColorMagenta: + return "magenta"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCuriousColorLavender: + return "lavender"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCuriousColorMaroon: + return "maroon"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCuriousColorNavy: + return "navy"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCuriousColorOlive: + return "olive"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCuriousColorCoral: + return "coral"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCuriousColorCream: + return "cream"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCuriousColorIndigo: + return "indigo"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kCuriousColorFuchsia: + return "fuchsia"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kDreamscapesObjectBicycle: + return "bicycle"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kDreamscapesObjectCastle: + return "castle"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kDreamscapesObjectBuilding: + return "building"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kDreamscapesObjectBoat: + return "boat"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kDreamscapesObjectLamp: + return "lamp"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kDreamscapesObjectTable: + return "table"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kDreamscapesObjectBridge: + return "bridge"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kDreamscapesObjectLighthouse: + return "lighthouse"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kDreamscapesObjectPagoda: + return "pagoda"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kDreamscapesObjectPalace: + return "palace"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kDreamscapesObjectTower: + return "tower"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kDreamscapesObjectUfo: + return "UFO"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kDreamscapesMaterialFlowers: + return "flowers"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kDreamscapesMaterialSilk: + return "silk"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kDreamscapesMaterialFelt: + return "felt"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kDreamscapesMaterialBurlap: + return "burlap"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kDreamscapesMaterialChiffon: + return "chiffon"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kDreamscapesMaterialCotton: + return "cotton"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kDreamscapesMaterialFur: + return "fur"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kDreamscapesMaterialLace: + return "lace"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kDreamscapesMaterialLinen: + return "linen"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kDreamscapesMaterialOrganza: + return "organza"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kDreamscapesMaterialTulle: + return "tulle"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kDreamscapesMaterialWool: + return "wool"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kDreamscapesMaterialYarn: + return "yarn"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kDreamscapesMaterialFleece: + return "fleece"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kDreamscapesMaterialClay: + return "clay"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kDreamscapesMaterialStone: + return "stone"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kDreamscapesMaterialWood: + return "wood"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kDreamscapesMaterialAmethyst: + return "amethyst"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kDreamscapesMaterialLapisLuzuli: + return "lapis_luzuli"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kDreamscapesMaterialObsidian: + return "obsidian"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kDreamscapesMaterialOpal: + return "opal"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kDreamscapesMaterialSapphire: + return "sapphire"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kDreamscapesColorsPinkPurple: + return "pink_purple"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kDreamscapesColorsCoralTan: + return "coral_tan"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kDreamscapesColorsCreamOrange: + return "cream_orange"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kDreamscapesColorsBlueIndigo: + return "blue_indigo"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kDreamscapesColorsGreenTeal: + return "green_teal"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kDreamscapesColorsBurgundyMaroon: + return "burgundy_maroon"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kDreamscapesColorsYellowTeal: + return "yellow_teal"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTranslucentItemApple: + return "apple"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTranslucentItemAzalea: + return "azalea"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTranslucentItemBegonia: + return "begonia"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTranslucentItemBluebell: + return "bluebell"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTranslucentItemCherryBlossom: + return "cherry_blossom"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTranslucentItemChrysanthemum: + return "chrysanthemum"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTranslucentItemClemati: + return "clemati"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTranslucentItemDaffodil: + return "daffodil"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTranslucentItemDaisy: + return "daisy"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTranslucentItemDandelion: + return "dandelion"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTranslucentItemRose: + return "rose"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTranslucentItemDogwood: + return "dogwood"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTranslucentItemHibiscus: + return "hibiscus"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTranslucentItemHydrangea: + return "hydrangea"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTranslucentItemLeaf: + return "leaf"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTranslucentItemLily: + return "lily"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTranslucentItemPansy: + return "pansy"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTranslucentItemPear: + return "pear"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTranslucentItemPeony: + return "peony"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTranslucentItemPhilodendron: + return "philodendron"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTranslucentItemPoppy: + return "poppy"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTranslucentItemSunflower: + return "sunflower"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTranslucentItemPea: + return "pea"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTranslucentItemTulip: + return "tulip"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTranslucentItemButterfly: + return "butterfly"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTranslucentItemDragonfly: + return "dragonfly"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTranslucentColorPink: + return "pink"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTranslucentColorBlue: + return "blue"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTranslucentColorIndigo: + return "indigo"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTranslucentColorGreen: + return "green"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTranslucentColorEmerald: + return "emerald"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTranslucentColorTeal: + return "teal"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTranslucentColorCyan: + return "cyan"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTranslucentColorPurple: + return "purple"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTranslucentColorGold: + return "gold"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTranslucentColorRed: + return "red"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTranslucentColorRust: + return "rust"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTranslucentColorOlive: + return "olive"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTranslucentColorGray: + return "gray"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTranslucentColorYellow: + return "yellow"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTranslucentColorViolet: + return "violet"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTranslucentColorIvory: + return "ivory"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTranslucentColorMagenta: + return "magenta"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTranslucentColorPeach: + return "peach"; + case ash::personalization_app::mojom::SeaPenTemplateOption:: + kTranslucentColorBlack: + return "black"; } } @@ -314,88 +1227,271 @@ auto options = query->options; switch (id) { case ash::personalization_app::mojom::SeaPenTemplateId::kFlower: { - auto flower_type = options - .find(ash::personalization_app::mojom:: - SeaPenTemplateChip::kFlowerType) - ->second; - auto flower_color = options - .find(ash::personalization_app::mojom:: - SeaPenTemplateChip::kFlowerColor) - ->second; - return (flower_type >= ash::personalization_app::mojom:: - SeaPenTemplateOption::kFlowerTypeRose && - flower_type <= ash::personalization_app::mojom:: - SeaPenTemplateOption::kFlowerTypeHydrangeas && - flower_color >= ash::personalization_app::mojom:: - SeaPenTemplateOption::kFlowerColorPink && - flower_color <= ash::personalization_app::mojom:: - SeaPenTemplateOption::kFlowerColorRed); + auto enum1 = options + .find(ash::personalization_app::mojom:: + SeaPenTemplateChip::kFlowerColor) + ->second; + if (enum1 < ash::personalization_app::mojom::SeaPenTemplateOption:: + kFlowerColorPink || + enum1 > ash::personalization_app::mojom::SeaPenTemplateOption:: + kFlowerColorRed) { + return false; + } + auto enum2 = options + .find(ash::personalization_app::mojom:: + SeaPenTemplateChip::kFlowerType) + ->second; + if (enum2 < ash::personalization_app::mojom::SeaPenTemplateOption:: + kFlowerTypeRose || + enum2 > ash::personalization_app::mojom::SeaPenTemplateOption:: + kFlowerTypeHydrangeas) { + return false; + } + return true; } case ash::personalization_app::mojom::SeaPenTemplateId::kMineral: { - auto mineral_name = options - .find(ash::personalization_app::mojom:: - SeaPenTemplateChip::kMineralName) - ->second; - auto mineral_color = options - .find(ash::personalization_app::mojom:: - SeaPenTemplateChip::kMineralColor) - ->second; - return (mineral_name >= ash::personalization_app::mojom:: - SeaPenTemplateOption::kMineralNameAgate && - mineral_name <= - ash::personalization_app::mojom::SeaPenTemplateOption:: - kMineralNameTourmaline && - mineral_color >= ash::personalization_app::mojom:: - SeaPenTemplateOption::kMineralColorWarm && - mineral_color <= ash::personalization_app::mojom:: - SeaPenTemplateOption::kMineralColorGray); + auto enum1 = options + .find(ash::personalization_app::mojom:: + SeaPenTemplateChip::kMineralName) + ->second; + if (enum1 < ash::personalization_app::mojom::SeaPenTemplateOption:: + kMineralNameAgate || + enum1 > ash::personalization_app::mojom::SeaPenTemplateOption:: + kMineralNameTourmaline) { + return false; + } + auto enum2 = options + .find(ash::personalization_app::mojom:: + SeaPenTemplateChip::kMineralColor) + ->second; + if (enum2 < ash::personalization_app::mojom::SeaPenTemplateOption:: + kMineralColorWarm || + enum2 > ash::personalization_app::mojom::SeaPenTemplateOption:: + kMineralColorGray) { + return false; + } + return true; } case ash::personalization_app::mojom::SeaPenTemplateId::kLandscape: { - auto landscape_biome = options - .find(ash::personalization_app::mojom:: - SeaPenTemplateChip::kLandscapeBiome) - ->second; - auto landscape_lighting = - options - .find(ash::personalization_app::mojom::SeaPenTemplateChip:: - kLandscapeLighting) - ->second; - return ( - landscape_biome >= ash::personalization_app::mojom:: - SeaPenTemplateOption::kLandscapeBiomeTaiga && - landscape_biome <= ash::personalization_app::mojom:: - SeaPenTemplateOption::kLandscapeBiomeForest && - landscape_lighting >= - ash::personalization_app::mojom::SeaPenTemplateOption:: - kLandscapeLightingDiffuse && - landscape_lighting <= - ash::personalization_app::mojom::SeaPenTemplateOption:: - kLandscapeLightingMidday); + auto enum1 = options + .find(ash::personalization_app::mojom:: + SeaPenTemplateChip::kLandscapeBiome) + ->second; + if (enum1 < ash::personalization_app::mojom::SeaPenTemplateOption:: + kLandscapeBiomeTaiga || + enum1 > ash::personalization_app::mojom::SeaPenTemplateOption:: + kLandscapeBiomeForest) { + return false; + } + auto enum2 = options + .find(ash::personalization_app::mojom:: + SeaPenTemplateChip::kLandscapeLighting) + ->second; + if (enum2 < ash::personalization_app::mojom::SeaPenTemplateOption:: + kLandscapeLightingDiffuse || + enum2 > ash::personalization_app::mojom::SeaPenTemplateOption:: + kLandscapeLightingMidday) { + return false; + } + return true; } case ash::personalization_app::mojom::SeaPenTemplateId::kScifi: { - auto scifi_feature = options - .find(ash::personalization_app::mojom:: - SeaPenTemplateChip::kScifiFeature) - ->second; - auto scifi_color = options - .find(ash::personalization_app::mojom:: - SeaPenTemplateChip::kScifiColor) - ->second; - return (scifi_feature >= ash::personalization_app::mojom:: - SeaPenTemplateOption::kScifiFeatureStreet && - scifi_feature <= - ash::personalization_app::mojom::SeaPenTemplateOption:: - kScifiFeatureUnderwater && - scifi_color >= ash::personalization_app::mojom:: - SeaPenTemplateOption::kScifiColorEarthy && - scifi_color <= ash::personalization_app::mojom:: - SeaPenTemplateOption::kScifiColorNeutral); + auto enum1 = options + .find(ash::personalization_app::mojom:: + SeaPenTemplateChip::kScifiFeature) + ->second; + if (enum1 < ash::personalization_app::mojom::SeaPenTemplateOption:: + kScifiFeatureStreet || + enum1 > ash::personalization_app::mojom::SeaPenTemplateOption:: + kScifiFeatureUnderwater) { + return false; + } + auto enum2 = options + .find(ash::personalization_app::mojom:: + SeaPenTemplateChip::kScifiColor) + ->second; + if (enum2 < ash::personalization_app::mojom::SeaPenTemplateOption:: + kScifiColorEarthy || + enum2 > ash::personalization_app::mojom::SeaPenTemplateOption:: + kScifiColorNeutral) { + return false; + } + return true; + } + case ash::personalization_app::mojom::SeaPenTemplateId::kArt: { + auto enum1 = options + .find(ash::personalization_app::mojom:: + SeaPenTemplateChip::kArtFeature) + ->second; + if (enum1 < ash::personalization_app::mojom::SeaPenTemplateOption:: + kArtFeatureCanyon || + enum1 > ash::personalization_app::mojom::SeaPenTemplateOption:: + kArtFeatureVillage) { + return false; + } + auto enum2 = options + .find(ash::personalization_app::mojom:: + SeaPenTemplateChip::kArtMovement) + ->second; + if (enum2 < ash::personalization_app::mojom::SeaPenTemplateOption:: + kArtMovementAvantGarde || + enum2 > ash::personalization_app::mojom::SeaPenTemplateOption:: + kArtMovementModernArt) { + return false; + } + return true; + } + case ash::personalization_app::mojom::SeaPenTemplateId::kCharacters: { + auto enum1 = options + .find(ash::personalization_app::mojom:: + SeaPenTemplateChip::kCharactersColor) + ->second; + if (enum1 < ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersColorYellow || + enum1 > ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersColorPeacockBlue) { + return false; + } + auto enum2 = options + .find(ash::personalization_app::mojom:: + SeaPenTemplateChip::kCharactersSubjects) + ->second; + if (enum2 < ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersSubjectsLemons || + enum2 > ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersSubjectsInstruments) { + return false; + } + auto enum3 = options + .find(ash::personalization_app::mojom:: + SeaPenTemplateChip::kCharactersBackground) + ->second; + if (enum3 < ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersBackgroundPurple || + enum3 > ash::personalization_app::mojom::SeaPenTemplateOption:: + kCharactersBackgroundPeacockBlue) { + return false; + } + return true; + } + case ash::personalization_app::mojom::SeaPenTemplateId::kTerrain: { + auto enum1 = options + .find(ash::personalization_app::mojom:: + SeaPenTemplateChip::kTerrainFeature) + ->second; + if (enum1 < ash::personalization_app::mojom::SeaPenTemplateOption:: + kTerrainFeatureSaltLake || + enum1 > ash::personalization_app::mojom::SeaPenTemplateOption:: + kTerrainFeatureSandDunes) { + return false; + } + auto enum2 = options + .find(ash::personalization_app::mojom:: + SeaPenTemplateChip::kTerrainColor) + ->second; + if (enum2 < ash::personalization_app::mojom::SeaPenTemplateOption:: + kTerrainColorPink || + enum2 > ash::personalization_app::mojom::SeaPenTemplateOption:: + kTerrainColorBluePink) { + return false; + } + return true; + } + case ash::personalization_app::mojom::SeaPenTemplateId::kCurious: { + auto enum1 = options + .find(ash::personalization_app::mojom:: + SeaPenTemplateChip::kCuriousColor) + ->second; + if (enum1 < ash::personalization_app::mojom::SeaPenTemplateOption:: + kCuriousColorBlue || + enum1 > ash::personalization_app::mojom::SeaPenTemplateOption:: + kCuriousColorFuchsia) { + return false; + } + auto enum2 = options + .find(ash::personalization_app::mojom:: + SeaPenTemplateChip::kCuriousFeature) + ->second; + if (enum2 < ash::personalization_app::mojom::SeaPenTemplateOption:: + kCuriousFeatureAlpineLake || + enum2 > ash::personalization_app::mojom::SeaPenTemplateOption:: + kCuriousFeatureWaterfall) { + return false; + } + auto enum3 = options + .find(ash::personalization_app::mojom:: + SeaPenTemplateChip::kCuriousSubject) + ->second; + if (enum3 < ash::personalization_app::mojom::SeaPenTemplateOption:: + kCuriousSubjectCherryBlossoms || + enum3 > ash::personalization_app::mojom::SeaPenTemplateOption:: + kCuriousSubjectSucculents) { + return false; + } + return true; + } + case ash::personalization_app::mojom::SeaPenTemplateId::kDreamscapes: { + auto enum1 = options + .find(ash::personalization_app::mojom:: + SeaPenTemplateChip::kDreamscapesObject) + ->second; + if (enum1 < ash::personalization_app::mojom::SeaPenTemplateOption:: + kDreamscapesObjectBicycle || + enum1 > ash::personalization_app::mojom::SeaPenTemplateOption:: + kDreamscapesObjectUfo) { + return false; + } + auto enum2 = options + .find(ash::personalization_app::mojom:: + SeaPenTemplateChip::kDreamscapesMaterial) + ->second; + if (enum2 < ash::personalization_app::mojom::SeaPenTemplateOption:: + kDreamscapesMaterialFlowers || + enum2 > ash::personalization_app::mojom::SeaPenTemplateOption:: + kDreamscapesMaterialSapphire) { + return false; + } + auto enum3 = options + .find(ash::personalization_app::mojom:: + SeaPenTemplateChip::kDreamscapesColors) + ->second; + if (enum3 < ash::personalization_app::mojom::SeaPenTemplateOption:: + kDreamscapesColorsPinkPurple || + enum3 > ash::personalization_app::mojom::SeaPenTemplateOption:: + kDreamscapesColorsYellowTeal) { + return false; + } + return true; + } + case ash::personalization_app::mojom::SeaPenTemplateId::kTranslucent: { + auto enum1 = options + .find(ash::personalization_app::mojom:: + SeaPenTemplateChip::kTranslucentItem) + ->second; + if (enum1 < ash::personalization_app::mojom::SeaPenTemplateOption:: + kTranslucentItemApple || + enum1 > ash::personalization_app::mojom::SeaPenTemplateOption:: + kTranslucentItemDragonfly) { + return false; + } + auto enum2 = options + .find(ash::personalization_app::mojom:: + SeaPenTemplateChip::kTranslucentColor) + ->second; + if (enum2 < ash::personalization_app::mojom::SeaPenTemplateOption:: + kTranslucentColorPink || + enum2 > ash::personalization_app::mojom::SeaPenTemplateOption:: + kTranslucentColorBlack) { + return false; + } + return true; } } return false; } } // namespace +// End of generated code. bool IsValidOutput(manta::proto::OutputData output, const std::string_view source) {
diff --git a/chrome/browser/compose/chrome_compose_client_unittest.cc b/chrome/browser/compose/chrome_compose_client_unittest.cc index 3483a89..891d31e 100644 --- a/chrome/browser/compose/chrome_compose_client_unittest.cc +++ b/chrome/browser/compose/chrome_compose_client_unittest.cc
@@ -375,6 +375,7 @@ EXPECT_EQ(compose::mojom::ComposeStatus::kOk, result->status); EXPECT_EQ("Cucumbers", result->result); + EXPECT_FALSE(result->on_device_evaluation_used); // Check that a user action for the Compose request was emitted. EXPECT_EQ(1, user_action_tester().GetActionCount( @@ -405,10 +406,11 @@ OptimizationGuideModelExecutionResultStreamingCallback callback) { // Start with a partial response. - callback.Run( + auto opt_guide_response = OptimizationGuideResponse(ComposeResponse(true, "Cucu"), - /*is_complete=*/false), - nullptr); + /*is_complete=*/false); + opt_guide_response.provided_by_on_device = true; + callback.Run(std::move(opt_guide_response), nullptr); saved_callback = callback; }))); ShowDialogAndBindMojo(); @@ -440,11 +442,14 @@ EXPECT_TRUE(initial_state->compose_state->has_pending_request); // Then send the full response. - saved_callback.Run( - OptimizationGuideResponse(ComposeResponse(true, "Cucumbers")), nullptr); + auto full_response = + OptimizationGuideResponse(ComposeResponse(true, "Cucumbers")); + full_response.provided_by_on_device = true; + saved_callback.Run(full_response, nullptr); auto complete_result = test_future.Take(); EXPECT_EQ(compose::mojom::ComposeStatus::kOk, complete_result->status); EXPECT_EQ("Cucumbers", complete_result->result); + EXPECT_TRUE(complete_result->on_device_evaluation_used); // Check that a single response result OK metric was emitted. histogram_tester.ExpectUniqueSample(compose::kComposeResponseStatus,
diff --git a/chrome/browser/compose/compose_dialog_browsertest.cc b/chrome/browser/compose/compose_dialog_browsertest.cc index 53ed9ca0..1e0f4e2 100644 --- a/chrome/browser/compose/compose_dialog_browsertest.cc +++ b/chrome/browser/compose/compose_dialog_browsertest.cc
@@ -52,7 +52,6 @@ ASSERT_TRUE(ui_test_utils::NavigateToURL( browser(), embedded_test_server()->GetURL("/compose/test2.html"))); ASSERT_NE(nullptr, ChromeComposeClient::FromWebContents(web_contents)); - ComposeEnabling::SetEnabledForTesting(true); // get point of element gfx::PointF textarea_center = @@ -85,7 +84,6 @@ ASSERT_TRUE(ui_test_utils::NavigateToURL( browser(), embedded_test_server()->GetURL("/compose/test2.html"))); ASSERT_NE(nullptr, ChromeComposeClient::FromWebContents(web_contents)); - ComposeEnabling::SetEnabledForTesting(true); // get point of element gfx::PointF textarea_center = @@ -112,7 +110,6 @@ browser(), embedded_test_server()->GetURL("/compose/test2.html"))); ASSERT_NE(nullptr, ChromeComposeClient::FromWebContents(web_contents)); auto* client = ChromeComposeClient::FromWebContents(web_contents); - client->GetComposeEnabling().SetEnabledForTesting(true); // get point of element gfx::PointF textarea_center =
diff --git a/chrome/browser/compose/compose_session.cc b/chrome/browser/compose/compose_session.cc index 0f5fac94..d4819118 100644 --- a/chrome/browser/compose/compose_session.cc +++ b/chrome/browser/compose/compose_session.cc
@@ -392,6 +392,7 @@ auto ui_response = compose::mojom::ComposeResponse::New(); ui_response->status = compose::mojom::ComposeStatus::kOk; ui_response->result = response->output(); + ui_response->on_device_evaluation_used = result->provided_by_on_device; current_state_->response = ui_response->Clone(); // Log successful response status.
diff --git a/chrome/browser/download/chrome_download_manager_delegate_unittest.cc b/chrome/browser/download/chrome_download_manager_delegate_unittest.cc index 87e508d..a466e78 100644 --- a/chrome/browser/download/chrome_download_manager_delegate_unittest.cc +++ b/chrome/browser/download/chrome_download_manager_delegate_unittest.cc
@@ -52,6 +52,7 @@ #include "components/policy/core/common/policy_pref_names.h" #include "components/prefs/pref_service.h" #include "components/safe_browsing/buildflags.h" +#include "components/safe_browsing/content/common/file_type_policies_test_util.h" #include "components/safe_search_api/safe_search_util.h" #include "components/sync_preferences/testing_pref_service_syncable.h" #include "content/public/browser/download_item_utils.h" @@ -751,6 +752,34 @@ } } +TEST_F(ChromeDownloadManagerDelegateTest, DragAndDropDangerous) { +#if BUILDFLAG(ENABLE_PLUGINS) + content::PluginService::GetInstance()->Init(); +#endif + + GURL url("http://example.com/foo"); + base::FilePath path(GetPathInDownloadDir("foo.evil_file_type")); + safe_browsing::FileTypePoliciesTestOverlay scoped_dangerous = + safe_browsing::ScopedMarkAllFilesDangerousForTesting(); + + std::unique_ptr<download::MockDownloadItem> download_item = + CreateActiveDownloadItem(0); + EXPECT_CALL(*download_item, GetURL()).WillRepeatedly(ReturnRef(url)); + EXPECT_CALL(*download_item, GetDownloadSource()) + .WillRepeatedly(Return(download::DownloadSource::DRAG_AND_DROP)); + EXPECT_CALL(*download_item, GetForcedFilePath()) + .WillRepeatedly(ReturnRef(path)); + EXPECT_CALL(*delegate(), MockCheckDownloadUrl(_, _)) + .WillRepeatedly( + Return(download::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT)); + + DetermineDownloadTargetResult result; + DetermineDownloadTarget(download_item.get(), &result); + + EXPECT_EQ(DownloadFileType::DANGEROUS, + DownloadItemModel(download_item.get()).GetDangerLevel()); +} + TEST_F(ChromeDownloadManagerDelegateTest, BlockedByPolicy) { const GURL kUrl("http://example.com/foo"); const std::string kTargetDisposition("attachment; filename=\"foo.txt\"");
diff --git a/chrome/browser/download/download_target_determiner.cc b/chrome/browser/download/download_target_determiner.cc index 0dba97c..76f7ad0 100644 --- a/chrome/browser/download/download_target_determiner.cc +++ b/chrome/browser/download/download_target_determiner.cc
@@ -1255,10 +1255,16 @@ // If the user has has been prompted or will be, assume that the user has // approved the download. A programmatic download is considered safe unless it // contains malware. + bool user_approved_path = + !download_->GetForcedFilePath().empty() && + // Drag and drop download paths are not approved by the user. See + // https://crbug.com/1513639 + download_->GetDownloadSource() != download::DownloadSource::DRAG_AND_DROP; if (HasPromptedForPath() || confirmation_reason_ != DownloadConfirmationReason::NONE || - !download_->GetForcedFilePath().empty()) + user_approved_path) { return DownloadFileType::NOT_DANGEROUS; + } // User-initiated extension downloads from pref-whitelisted sources are not // considered dangerous.
diff --git a/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_apitest.cc b/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_apitest.cc index 712639d..49bd8ce2 100644 --- a/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_apitest.cc +++ b/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_apitest.cc
@@ -2,18 +2,18 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/extensions/extension_apitest.h" - #include "base/files/file_path.h" #include "base/files/file_util.h" #include "base/files/scoped_temp_dir.h" #include "base/threading/thread_restrictions.h" #include "build/build_config.h" +#include "chrome/browser/extensions/extension_apitest.h" #include "chrome/common/chrome_features.h" #include "components/version_info/version_info.h" #include "content/public/common/content_features.h" #include "content/public/test/browser_test.h" #include "content/public/test/prerender_test_util.h" +#include "extensions/browser/api/declarative_net_request/constants.h" #include "extensions/browser/api/declarative_net_request/utils.h" #include "extensions/common/extension_features.h" #include "extensions/test/extension_test_message_listener.h" @@ -100,6 +100,15 @@ ASSERT_TRUE(RunExtensionTest("dynamic_rules")) << message_; } +IN_PROC_BROWSER_TEST_P(DeclarativeNetRequestLazyApiTest, RegexRuleMessage) { + // Ensure the error message for large RegEx rules is updated with the + // correct value for the memory limit. + std::string expected_amount = base::StringPrintf( + "%dKB", extensions::declarative_net_request::kRegexMaxMemKb); + EXPECT_THAT(extensions::declarative_net_request::kErrorRegexTooLarge, + testing::HasSubstr(expected_amount)); +} + class DeclarativeNetRequestSafeRulesLazyApiTest : public DeclarativeNetRequestLazyApiTest { public:
diff --git a/chrome/browser/feedback/show_feedback_page.cc b/chrome/browser/feedback/show_feedback_page.cc index 011e3fd9..58c35f9 100644 --- a/chrome/browser/feedback/show_feedback_page.cc +++ b/chrome/browser/feedback/show_feedback_page.cc
@@ -276,7 +276,8 @@ const std::string& description_placeholder_text, const std::string& category_tag, const std::string& extra_diagnostics, - base::Value::Dict autofill_metadata); + base::Value::Dict autofill_metadata, + base::Value::Dict ai_metadata); } // namespace internal #endif @@ -350,7 +351,8 @@ // Send request to ash via crosapi mojo to show Feedback ui from ash. internal::ShowFeedbackPageLacros( page_url, source, description_template, description_placeholder_text, - category_tag, extra_diagnostics, std::move(autofill_metadata)); + category_tag, extra_diagnostics, std::move(autofill_metadata), + std::move(ai_metadata)); #else // Show feedback dialog using feedback extension API. RequestFeedbackFlow(page_url, profile, source, description_template,
diff --git a/chrome/browser/feedback/show_feedback_page_lacros.cc b/chrome/browser/feedback/show_feedback_page_lacros.cc index 19835187..b609e07 100644 --- a/chrome/browser/feedback/show_feedback_page_lacros.cc +++ b/chrome/browser/feedback/show_feedback_page_lacros.cc
@@ -5,6 +5,7 @@ #include "chrome/browser/ui/chrome_pages.h" #include "chromeos/crosapi/mojom/feedback.mojom.h" #include "chromeos/lacros/lacros_service.h" +#include "chromeos/startup/browser_params_proxy.h" namespace chrome { namespace internal { @@ -40,6 +41,8 @@ kFeedbackSourceProfileErrorDialog; case kFeedbackSourceQuickOffice: return crosapi::mojom::LacrosFeedbackSource::kFeedbackSourceQuickOffice; + case kFeedbackSourceAI: + return crosapi::mojom::LacrosFeedbackSource::kFeedbackSourceAI; default: LOG(ERROR) << "ShowFeedbackPage is called by unknown Lacros source: " << static_cast<int>(source); @@ -55,7 +58,8 @@ const std::string& description_placeholder_text, const std::string& category_tag, const std::string& extra_diagnostics, - base::Value::Dict autofill_metadata) { + base::Value::Dict autofill_metadata, + base::Value::Dict ai_metadata) { auto mojo_feedback = crosapi::mojom::FeedbackInfo::New(); mojo_feedback->page_url = page_url; mojo_feedback->source = ToMojoLacrosFeedbackSource(source); @@ -64,6 +68,7 @@ mojo_feedback->category_tag = category_tag; mojo_feedback->extra_diagnostics = extra_diagnostics; mojo_feedback->autofill_metadata = base::Value(std::move(autofill_metadata)); + mojo_feedback->ai_metadata = base::Value(std::move(ai_metadata)); return mojo_feedback; } @@ -77,12 +82,22 @@ const std::string& description_placeholder_text, const std::string& category_tag, const std::string& extra_diagnostics, - base::Value::Dict autofill_metadata) { + base::Value::Dict autofill_metadata, + base::Value::Dict ai_metadata) { + if (source == kFeedbackSourceAI) { + auto capabilities = chromeos::BrowserParamsProxy::Get()->AshCapabilities(); + if (!capabilities || !base::Contains(*capabilities, "crbug/1501057")) { + LOG(WARNING) << "Unsupported feedback source AI for ash."; + return; + } + } + chromeos::LacrosService::Get() ->GetRemote<crosapi::mojom::Feedback>() ->ShowFeedbackPage(ToMojoFeedbackInfo( page_url, source, description_template, description_placeholder_text, - category_tag, extra_diagnostics, std::move(autofill_metadata))); + category_tag, extra_diagnostics, std::move(autofill_metadata), + std::move(ai_metadata))); } } // namespace internal
diff --git a/chrome/browser/feedback/show_feedback_page_lacros_browsertest.cc b/chrome/browser/feedback/show_feedback_page_lacros_browsertest.cc index ef42adc..8942c19 100644 --- a/chrome/browser/feedback/show_feedback_page_lacros_browsertest.cc +++ b/chrome/browser/feedback/show_feedback_page_lacros_browsertest.cc
@@ -6,6 +6,7 @@ #include "base/version.h" #include "chrome/browser/ui/chrome_pages.h" #include "chrome/test/base/in_process_browser_test.h" +#include "chromeos/startup/browser_params_proxy.h" #include "components/version_info/version_info.h" #include "content/public/test/browser_test.h" @@ -124,3 +125,23 @@ ShowFeedbackPageWithFeedbackSource(chrome::kFeedbackSourceQuickOffice); histogram_tester.ExpectTotalCount("Feedback.RequestSource", 1); } + +IN_PROC_BROWSER_TEST_F(ShowFeedbackPageBrowserTest, ShowFeedbackPageFromAI) { + base::HistogramTester histogram_tester; + std::string unused; + auto capabilities = chromeos::BrowserParamsProxy::Get()->AshCapabilities(); + if (!capabilities || !base::Contains(*capabilities, "crbug/1501057")) { + GTEST_SKIP() << "Unsupported feedback source AI for ash."; + } + + // AI flow uses the Chrome feedback dialog instead so no new ash window will + // be created. + chrome::ShowFeedbackPage(browser(), chrome::kFeedbackSourceAI, + /*description_template=*/unused, + /*description_placeholder_text=*/unused, + /*category_tag=*/unused, + /*extra_diagnostics=*/unused, + /*autofill_metadata=*/base::Value::Dict(), + /*ai_metadata=*/base::Value::Dict()); + histogram_tester.ExpectTotalCount("Feedback.RequestSource", 1); +}
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index 13c867c..b0519170 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -5174,6 +5174,11 @@ "expiry_milestone": 130 }, { + "name": "left-hand-side-activity-indicators", + "owners": [ "elklm@chromium.org", "//components/permissions/PERMISSIONS_OWNERS" ], + "expiry_milestone": 135 + }, + { "name": "legacy-tech-report-enable-cookie-issue-reports", "owners": ["sandormajor@google.com", "zmin@chromium.org", "parastoog@chromium.org"], "expiry_milestone": 125
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index b546553..bb59f289 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -2789,6 +2789,11 @@ const char kImprovedSemanticsActivityIndicatorsDescription[] = "Enables experimental improved semantics indicators in the location bar."; +const char kLeftHandSideActivityIndicatorsName[] = + "Left-hand side activity indicators"; +const char kLeftHandSideActivityIndicatorsDescription[] = + "Moves activity indicators to the left-hand side of location bar."; + const char kPermissionPredictionsName[] = "Permission Predictions"; const char kPermissionPredictionsDescription[] = "Use the Permission Predictions Service to surface permission requests "
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index 652da05e..0ba824b 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -1605,6 +1605,9 @@ extern const char kImprovedSemanticsActivityIndicatorsName[]; extern const char kImprovedSemanticsActivityIndicatorsDescription[]; +extern const char kLeftHandSideActivityIndicatorsName[]; +extern const char kLeftHandSideActivityIndicatorsDescription[]; + extern const char kPermissionPredictionsName[]; extern const char kPermissionPredictionsDescription[];
diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc index 6a1a3e5..6aba36b9 100644 --- a/chrome/browser/flags/android/chrome_feature_list.cc +++ b/chrome/browser/flags/android/chrome_feature_list.cc
@@ -626,7 +626,7 @@ BASE_FEATURE(kMultiInstanceApplicationStatusCleanup, "MultiInstanceApplicationStatusCleanup", - base::FEATURE_ENABLED_BY_DEFAULT); + base::FEATURE_DISABLED_BY_DEFAULT); BASE_FEATURE(kNewTabSearchEngineUrlAndroid, "NewTabSearchEngineUrlAndroid",
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 2f5b4a808..ba822628 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
@@ -513,7 +513,7 @@ new CachedFlag(HIDE_TAB_ON_TAB_SWITCHER, true); public static final CachedFlag sMagicStackAndroid = new CachedFlag(MAGIC_STACK_ANDROID, false); public static final CachedFlag sMultiInstanceApplicationStatusCleanup = - new CachedFlag(MUlTI_INSTANCE_APPLICATION_STATUS_CLEANUP, true); + new CachedFlag(MUlTI_INSTANCE_APPLICATION_STATUS_CLEANUP, false); public static final CachedFlag sNewTabSearchEngineUrlAndroid = new CachedFlag(NEW_TAB_SEARCH_ENGINE_URL_ANDROID, false); public static final CachedFlag sPriceChangeModule = new CachedFlag(PRICE_CHANGE_MODULE, false);
diff --git a/chrome/browser/guest_view/mime_handler_view/chrome_mime_handler_view_browsertest.cc b/chrome/browser/guest_view/mime_handler_view/chrome_mime_handler_view_browsertest.cc index 2e64a4b..6664b142 100644 --- a/chrome/browser/guest_view/mime_handler_view/chrome_mime_handler_view_browsertest.cc +++ b/chrome/browser/guest_view/mime_handler_view/chrome_mime_handler_view_browsertest.cc
@@ -69,6 +69,11 @@ using guest_view::TestGuestViewManager; using guest_view::TestGuestViewManagerFactory; +namespace { +// The value of the data is "content to read\n". +const char kDataUrlCsv[] = "data:text/csv;base64,Y29udGVudCB0byByZWFkCg=="; +} // namespace + class ChromeMimeHandlerViewTest : public extensions::ExtensionApiTest { public: ChromeMimeHandlerViewTest() = default; @@ -400,7 +405,6 @@ } IN_PROC_BROWSER_TEST_F(ChromeMimeHandlerViewTest, DataUrl) { - const char* kDataUrlCsv = "data:text/csv;base64,Y29udGVudCB0byByZWFkCg=="; RunTestWithUrl(GURL(kDataUrlCsv)); } @@ -654,12 +658,11 @@ IN_PROC_BROWSER_TEST_F(ChromeMimeHandlerViewTest, GuestDevToolsReloadsEmbedder) { - GURL data_url("data:application/pdf,foo"); - ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), data_url)); + GURL data_url(kDataUrlCsv); + RunTestWithUrl(data_url); auto* embedder_web_contents = browser()->tab_strip_model()->GetWebContentsAt(0); auto* guest_view = GetGuestViewManager()->WaitForSingleGuestViewCreated(); - ASSERT_TRUE(guest_view); EXPECT_NE(embedder_web_contents->GetPrimaryMainFrame(), guest_view->GetGuestMainFrame()); TestMimeHandlerViewGuest::WaitForGuestLoadStartThenStop(guest_view); @@ -686,10 +689,10 @@ IN_PROC_BROWSER_TEST_F(ChromeMimeHandlerViewTest, MimeHandlerViewInDisplayNoneFrameForGoogleApps) { GURL data_url( - "data:text/html, <iframe src='data:application/pdf,foo' " - "style='display:none'></iframe>,foo2"); - ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), data_url)); - ASSERT_TRUE(GetGuestViewManager()->WaitForSingleGuestViewCreated()); + base::StringPrintf("data:text/html, <iframe src='%s' " + "style='display:none'></iframe>,foo2", + kDataUrlCsv)); + RunTestWithUrl(data_url); } #if BUILDFLAG(ENABLE_PRINT_PREVIEW)
diff --git a/chrome/browser/hub/BUILD.gn b/chrome/browser/hub/BUILD.gn index a1ee455..61b217d 100644 --- a/chrome/browser/hub/BUILD.gn +++ b/chrome/browser/hub/BUILD.gn
@@ -28,6 +28,7 @@ "android/java/src/org/chromium/chrome/browser/hub/HubManager.java", "android/java/src/org/chromium/chrome/browser/hub/LoadHint.java", "android/java/src/org/chromium/chrome/browser/hub/Pane.java", + "android/java/src/org/chromium/chrome/browser/hub/PaneHubController.java", "android/java/src/org/chromium/chrome/browser/hub/PaneId.java", "android/java/src/org/chromium/chrome/browser/hub/PaneListBuilder.java", "android/java/src/org/chromium/chrome/browser/hub/PaneLookup.java",
diff --git a/chrome/browser/hub/android/java/src/org/chromium/chrome/browser/hub/Pane.java b/chrome/browser/hub/android/java/src/org/chromium/chrome/browser/hub/Pane.java index 73e4062..78fe0b0 100644 --- a/chrome/browser/hub/android/java/src/org/chromium/chrome/browser/hub/Pane.java +++ b/chrome/browser/hub/android/java/src/org/chromium/chrome/browser/hub/Pane.java
@@ -7,6 +7,7 @@ import android.view.View; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import org.chromium.base.supplier.ObservableSupplier; import org.chromium.components.browser_ui.widget.gesture.BackPressHandler; @@ -29,6 +30,14 @@ void destroy(); /** + * Sets an interface for controlling certain aspects of the Hub while focused. + * + * @param paneHubController An interface that can be used to control the hub, may be null when + * not focused. If null is set do not keep a reference to the old controller. + */ + void setPaneHubController(@Nullable PaneHubController paneHubController); + + /** * Notifies of a change to the Hub's or the pane's lifecycle. See {@link LoadHint} for possible * values and what the pane could or should do in response to a notification. *
diff --git a/chrome/browser/hub/android/java/src/org/chromium/chrome/browser/hub/PaneHubController.java b/chrome/browser/hub/android/java/src/org/chromium/chrome/browser/hub/PaneHubController.java new file mode 100644 index 0000000..de8d6ab1 --- /dev/null +++ b/chrome/browser/hub/android/java/src/org/chromium/chrome/browser/hub/PaneHubController.java
@@ -0,0 +1,29 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.hub; + +import org.chromium.chrome.browser.tab.Tab; + +/** + * Interface for controlling the Hub from a {@link Pane}. This is only available to the focused + * pane. + */ +public interface PaneHubController { + /** + * Sets a tab as active and hides the Hub. A tab must be selected if the browser is + * transitioning to an active tab. Use {@link Tab.INVALID_TAB_ID} if a tab has already been + * selected and doing so would repeat work. + * + * @param tabId The ID of the tab to select or {@link Tab.INVALID_TAB_ID}. + */ + public void selectTabAndHideHub(int tabId); + + /** + * Focuses a pane taking focus away from the current pane. + * + * @param paneId The ID of the pane to focus. + */ + public void focusPane(@PaneId int paneId); +}
diff --git a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubCoordinator.java b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubCoordinator.java index 60b240a5..a8b0ba0 100644 --- a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubCoordinator.java +++ b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubCoordinator.java
@@ -10,6 +10,7 @@ import android.widget.FrameLayout; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import org.chromium.base.Callback; import org.chromium.base.supplier.ObservableSupplier; @@ -21,17 +22,17 @@ import org.chromium.components.browser_ui.widget.gesture.BackPressHandler.BackPressResult; /** Root coordinator of the Hub. */ -public class HubCoordinator implements BackPressHandler { +public class HubCoordinator implements PaneHubController, BackPressHandler { private static final Integer START_SURFACE_LAYOUT_TYPE = Integer.valueOf(LayoutType.START_SURFACE); private final @NonNull FrameLayout mContainerView; private final @NonNull View mMainHubParent; + private final @NonNull PaneManager mPaneManager; private final @NonNull HubToolbarCoordinator mHubToolbarCoordinator; private final @NonNull HubPaneHostCoordinator mHubPaneHostCoordinator; private final @NonNull HubLayoutController mHubLayoutController; private final @NonNull ObservableSupplierImpl<Boolean> mHandleBackPressSupplier; - private final @NonNull ObservableSupplier<Pane> mFocusedPaneSupplier; /** * Generic callback that invokes {@link #updateHandleBackPressSupplier()}. This can be cast to @@ -40,7 +41,7 @@ private final @NonNull Callback<Object> mBackPressStateChangeCallback; /** - * Warning: {@link mFocusedPaneSupplier#get()} may return null if no pane is focused or {@link + * Warning: {@link #getFocusedPane()} may return null if no pane is focused or {@link * Pane#getHandleBackPressChangedSupplier()} contains null. */ private final @NonNull TransitiveObservableSupplier<Pane, Boolean> @@ -64,10 +65,11 @@ @NonNull ObservableSupplier<Tab> currentTabSupplier) { Context context = containerView.getContext(); mBackPressStateChangeCallback = (ignored) -> updateHandleBackPressSupplier(); - mFocusedPaneSupplier = paneManager.getFocusedPaneSupplier(); + mPaneManager = paneManager; mFocusedPaneHandleBackPressSupplier = new TransitiveObservableSupplier<>( - mFocusedPaneSupplier, p -> p.getHandleBackPressChangedSupplier()); + paneManager.getFocusedPaneSupplier(), + p -> p.getHandleBackPressChangedSupplier()); mFocusedPaneHandleBackPressSupplier.addObserver( castCallback(mBackPressStateChangeCallback)); @@ -122,7 +124,7 @@ @Override public @BackPressResult int handleBackPress() { if (Boolean.TRUE.equals(mFocusedPaneHandleBackPressSupplier.get()) - && mFocusedPaneSupplier.get().handleBackPress() == BackPressResult.SUCCESS) { + && getFocusedPane().handleBackPress() == BackPressResult.SUCCESS) { return BackPressResult.SUCCESS; } @@ -151,6 +153,20 @@ return mHandleBackPressSupplier; } + @Override + public void selectTabAndHideHub(int tabId) { + mHubLayoutController.selectTabAndHideHubLayout(tabId); + } + + @Override + public void focusPane(@PaneId int paneId) { + mPaneManager.focusPane(paneId); + } + + private @Nullable Pane getFocusedPane() { + return mPaneManager.getFocusedPaneSupplier().get(); + } + private boolean startSurfaceHandlesBackpress() { Tab currentTab = mCurrentTabSupplier.get(); boolean isIncognito = currentTab != null ? currentTab.isIncognito() : false;
diff --git a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubCoordinatorUnitTest.java b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubCoordinatorUnitTest.java index 1accc851..ebdf896 100644 --- a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubCoordinatorUnitTest.java +++ b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubCoordinatorUnitTest.java
@@ -11,6 +11,8 @@ import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -99,7 +101,7 @@ .registerPane( PaneId.INCOGNITO_TAB_SWITCHER, LazyOneshotSupplier.fromValue(mIncognitoTabSwitcherPane)); - mPaneManager = new PaneManagerImpl(builder, mHubVisibilitySupplier); + mPaneManager = spy(new PaneManagerImpl(builder, mHubVisibilitySupplier)); assertTrue(mPaneManager.focusPane(PaneId.TAB_SWITCHER)); assertEquals(mTabSwitcherPane, mPaneManager.getFocusedPaneSupplier().get()); @@ -280,4 +282,20 @@ assertEquals(BackPressResult.SUCCESS, mHubCoordinator.handleBackPress()); verify(mHubLayoutController).selectTabAndHideHubLayout(eq(TAB_ID)); } + + @Test + @SmallTest + public void testFocusPane() { + reset(mPaneManager); + mHubCoordinator.focusPane(PaneId.TAB_SWITCHER); + verify(mPaneManager).focusPane(PaneId.TAB_SWITCHER); + } + + @Test + @SmallTest + public void testSelectTabAndHideHub() { + int tabId = 5; + mHubCoordinator.selectTabAndHideHub(tabId); + verify(mHubLayoutController).selectTabAndHideHubLayout(tabId); + } }
diff --git a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubManagerImpl.java b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubManagerImpl.java index 5a4e946..b7a02e6 100644 --- a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubManagerImpl.java +++ b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubManagerImpl.java
@@ -7,7 +7,9 @@ import android.content.Context; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import org.chromium.base.ValueChangedCallback; import org.chromium.base.supplier.ObservableSupplier; import org.chromium.base.supplier.ObservableSupplierImpl; import org.chromium.chrome.browser.back_press.BackPressManager; @@ -22,9 +24,11 @@ * created and torn down as needed when {@link HubLayout} visibility changes. */ public class HubManagerImpl implements HubManager, HubController { - private final @NonNull Context mContext; + private final ValueChangedCallback<Pane> mOnFocusedPaneChanged = + new ValueChangedCallback<>(this::onFocusedPaneChanged); private final @NonNull ObservableSupplierImpl<Boolean> mHubVisibilitySupplier = new ObservableSupplierImpl<>(); + private final @NonNull Context mContext; private final @NonNull PaneManagerImpl mPaneManager; private final @NonNull HubContainerView mHubContainerView; private final @NonNull BackPressManager mBackPressManager; @@ -48,10 +52,13 @@ // TODO(crbug/1487315): Consider making this a xml file so the entire core UI is inflated. mHubContainerView = new HubContainerView(mContext); + + mPaneManager.getFocusedPaneSupplier().addObserver(mOnFocusedPaneChanged); } @Override public void destroy() { + mPaneManager.getFocusedPaneSupplier().removeObserver(mOnFocusedPaneChanged); mPaneManager.destroy(); destroyHubCoordinator(); } @@ -117,10 +124,15 @@ new HubCoordinator( mHubContainerView, mPaneManager, mHubLayoutController, mTabSupplier); mBackPressManager.addHandler(mHubCoordinator, BackPressHandler.Type.HUB); + Pane pane = mPaneManager.getFocusedPaneSupplier().get(); + if (pane != null) pane.setPaneHubController(mHubCoordinator); } private void destroyHubCoordinator() { if (mHubCoordinator != null) { + Pane pane = mPaneManager.getFocusedPaneSupplier().get(); + if (pane != null) pane.setPaneHubController(null); + mBackPressManager.removeHandler(mHubCoordinator); mHubCoordinator.destroy(); mHubCoordinator = null; @@ -130,4 +142,9 @@ HubCoordinator getHubCoordinatorForTesting() { return mHubCoordinator; } + + private void onFocusedPaneChanged(@Nullable Pane newPane, @Nullable Pane oldPane) { + if (oldPane != null) oldPane.setPaneHubController(null); + if (newPane != null) newPane.setPaneHubController(mHubCoordinator); + } }
diff --git a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubManagerImplUnitTest.java b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubManagerImplUnitTest.java index 0ae03ad..57cde3d3 100644 --- a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubManagerImplUnitTest.java +++ b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubManagerImplUnitTest.java
@@ -10,6 +10,7 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -51,15 +52,31 @@ @Mock private BackPressManager mBackPressManager; @Mock private Tab mTab; @Mock private Pane mTabSwitcherPane; + @Mock private Pane mIncognitoTabSwitcherPane; @Mock private HubLayoutController mHubLayoutController; @Mock private ObservableSupplier<Integer> mPreviousLayoutTypeSupplier; + private final ObservableSupplierImpl<Tab> mTabSupplier = new ObservableSupplierImpl<>(); + private final ObservableSupplierImpl<DisplayButtonData> mReferenceButtonDataSupplier = + new ObservableSupplierImpl<>(); + private final ObservableSupplierImpl<FullButtonData> mActionButtonDataSupplier = + new ObservableSupplierImpl<>(); + private Activity mActivity; private FrameLayout mRootView; - private ObservableSupplierImpl<Tab> mTabSupplier = new ObservableSupplierImpl<>(); @Before public void setUp() { + when(mTabSwitcherPane.getPaneId()).thenReturn(PaneId.TAB_SWITCHER); + when(mTabSwitcherPane.getReferenceButtonDataSupplier()) + .thenReturn(mReferenceButtonDataSupplier); + when(mTabSwitcherPane.getActionButtonDataSupplier()).thenReturn(mActionButtonDataSupplier); + when(mIncognitoTabSwitcherPane.getPaneId()).thenReturn(PaneId.INCOGNITO_TAB_SWITCHER); + when(mIncognitoTabSwitcherPane.getReferenceButtonDataSupplier()) + .thenReturn(mReferenceButtonDataSupplier); + when(mIncognitoTabSwitcherPane.getActionButtonDataSupplier()) + .thenReturn(mActionButtonDataSupplier); + when(mHubLayoutController.getPreviousLayoutTypeSupplier()) .thenReturn(mPreviousLayoutTypeSupplier); when(mTab.getId()).thenReturn(TAB_ID); @@ -81,7 +98,10 @@ new PaneListBuilder(new DefaultPaneOrderController()) .registerPane( PaneId.TAB_SWITCHER, - LazyOneshotSupplier.fromValue(mTabSwitcherPane)); + LazyOneshotSupplier.fromValue(mTabSwitcherPane)) + .registerPane( + PaneId.INCOGNITO_TAB_SWITCHER, + LazyOneshotSupplier.fromValue(mIncognitoTabSwitcherPane)); HubManager hubManager = HubManagerFactory.createHubManager( mActivity, builder, mBackPressManager, mTabSupplier); @@ -96,9 +116,18 @@ @Test @SmallTest public void testHubController() { - PaneListBuilder builder = new PaneListBuilder(new DefaultPaneOrderController()); + PaneListBuilder builder = + new PaneListBuilder(new DefaultPaneOrderController()) + .registerPane( + PaneId.TAB_SWITCHER, + LazyOneshotSupplier.fromValue(mTabSwitcherPane)) + .registerPane( + PaneId.INCOGNITO_TAB_SWITCHER, + LazyOneshotSupplier.fromValue(mIncognitoTabSwitcherPane)); HubManagerImpl hubManager = new HubManagerImpl(mActivity, builder, mBackPressManager, mTabSupplier); + hubManager.getPaneManager().focusPane(PaneId.TAB_SWITCHER); + verify(mTabSwitcherPane).setPaneHubController(null); HubController hubController = hubManager.getHubController(); hubController.setHubLayoutController(mHubLayoutController); assertNull(hubManager.getHubCoordinatorForTesting()); @@ -107,6 +136,7 @@ HubCoordinator coordinator = hubManager.getHubCoordinatorForTesting(); assertNotNull(coordinator); verify(mBackPressManager).addHandler(eq(coordinator), eq(BackPressHandler.Type.HUB)); + verify(mTabSwitcherPane).setPaneHubController(coordinator); View containerView = hubController.getContainerView(); assertNotNull(containerView); @@ -115,9 +145,14 @@ mRootView.addView(containerView); assertEquals(mRootView, containerView.getParent()); + hubManager.getPaneManager().focusPane(PaneId.INCOGNITO_TAB_SWITCHER); + verify(mTabSwitcherPane, times(2)).setPaneHubController(null); + verify(mIncognitoTabSwitcherPane).setPaneHubController(coordinator); + hubController.onHubLayoutDoneHiding(); assertNull(hubManager.getHubCoordinatorForTesting()); verify(mBackPressManager).removeHandler(eq(coordinator)); + verify(mIncognitoTabSwitcherPane).setPaneHubController(null); // Container is still attached and will be removed separately. assertEquals(mRootView, containerView.getParent());
diff --git a/chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.cc b/chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.cc index 730e74d..89d70d0 100644 --- a/chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.cc +++ b/chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.cc
@@ -1168,12 +1168,6 @@ } } -void ChromeBrowserMainExtraPartsMetrics::PostMainMessageLoopRun() { -#if BUILDFLAG(IS_CHROMEOS_ASH) - profile_manager_observation_.Reset(); -#endif -} - void ChromeBrowserMainExtraPartsMetrics::RegisterPrefs( PrefRegistrySimple* registry) { registry->RegisterIntegerPref(kEnableBenchmarkingPrefId, @@ -1210,16 +1204,23 @@ void ChromeBrowserMainExtraPartsMetrics:: HandleEnableBenchmarkingCountdownAsync() { - // On ChromeOS we must wait until post-login to be able to accurately assess - // whether the enable-benchmarking flag has been enabled. This logic assumes - // that it always runs pre-login. + Profile* profile = nullptr; #if BUILDFLAG(IS_CHROMEOS_ASH) - profile_manager_observation_.Observe(g_browser_process->profile_manager()); -#else - about_flags::GetStorage(/*profile=*/nullptr, + // This logic is subtle. There are two ways for ash-chrome PostBrowserStart to + // be called on ChromeOS. The first is when the device first shows the login + // screen. In this case the profile is the login profile. The second is after + // the user logs in. If any flags have been changed from the login profile's + // flags, then all of ash is restarted. We only care about invoking this logic + // in the second case. Thus we check if IsUserLoggedIn() to guard the logic. + if (!user_manager::UserManager::IsInitialized() || + !user_manager::UserManager::Get()->IsUserLoggedIn()) { + return; + } + profile = g_browser_process->profile_manager()->GetPrimaryUserProfile(); +#endif + about_flags::GetStorage(profile, base::BindOnce(&HandleEnableBenchmarkingCountdown, g_browser_process->local_state())); -#endif } void ChromeBrowserMainExtraPartsMetrics::OnDisplayAdded( @@ -1250,23 +1251,6 @@ } } -#if BUILDFLAG(IS_CHROMEOS_ASH) -void ChromeBrowserMainExtraPartsMetrics::OnProfileAdded(Profile* profile) { - // This may be called with the login profile which is a side effect when - // ash-chrome restarts during login. We only want to trigger the - // HandleEnableBenchmarkingCountdown logic for the primary profile. - - if (!user_manager::UserManager::Get()->IsPrimaryUser( - ash::BrowserContextHelper::Get()->GetUserByBrowserContext(profile))) { - return; - } - - about_flags::GetStorage(profile, - base::BindOnce(&HandleEnableBenchmarkingCountdown, - g_browser_process->local_state())); -} -#endif - namespace chrome { void AddMetricsExtraParts(ChromeBrowserMainParts* main_parts) {
diff --git a/chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.h b/chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.h index 6f995f6..a76b426e 100644 --- a/chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.h +++ b/chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.h
@@ -13,16 +13,11 @@ #include "base/scoped_observation.h" #include "build/build_config.h" #include "chrome/browser/chrome_browser_main_extra_parts.h" -#include "chrome/browser/profiles/profile_manager_observer.h" #include "components/flags_ui/flags_state.h" #include "components/flags_ui/flags_storage.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/display/display_observer.h" -#if BUILDFLAG(IS_CHROMEOS_ASH) -#include "chrome/browser/profiles/profile_manager.h" -#endif - class ChromeBrowserMainParts; class PrefRegistrySimple; class PrefService; @@ -47,8 +42,7 @@ } class ChromeBrowserMainExtraPartsMetrics : public ChromeBrowserMainExtraParts, - public display::DisplayObserver, - public ProfileManagerObserver { + public display::DisplayObserver { public: ChromeBrowserMainExtraPartsMetrics(); @@ -66,7 +60,6 @@ void PreBrowserStart() override; void PostBrowserStart() override; void PreMainMessageLoopRun() override; - void PostMainMessageLoopRun() override; // Registers local state prefs used by this class. static void RegisterPrefs(PrefRegistrySimple* registry); @@ -105,11 +98,6 @@ // If the number of displays has changed, emit a UMA metric. void EmitDisplaysChangedMetric(); -#if BUILDFLAG(IS_CHROMEOS_ASH) - // On ChromeOS, we must wait for post login to have a valid browser Profile*. - void OnProfileAdded(Profile* profile) override; -#endif - // A cached value for the number of displays. int display_count_; @@ -130,11 +118,6 @@ // Reports pressure metrics. std::unique_ptr<PressureMetricsReporter> pressure_metrics_reporter_; #endif // BUILDFLAG(IS_LINUX) - -#if BUILDFLAG(IS_CHROMEOS_ASH) - base::ScopedObservation<ProfileManager, ChromeBrowserMainExtraPartsMetrics> - profile_manager_observation_{this}; -#endif }; #endif // CHROME_BROWSER_METRICS_CHROME_BROWSER_MAIN_EXTRA_PARTS_METRICS_H_
diff --git a/chrome/browser/picture_in_picture/auto_picture_in_picture_tab_helper.cc b/chrome/browser/picture_in_picture/auto_picture_in_picture_tab_helper.cc index 9f2195a..856fbd6 100644 --- a/chrome/browser/picture_in_picture/auto_picture_in_picture_tab_helper.cc +++ b/chrome/browser/picture_in_picture/auto_picture_in_picture_tab_helper.cc
@@ -44,10 +44,15 @@ audio_focus_remote->AddObserver( audio_focus_observer_receiver_.BindNewPipeAndPassRemote()); - // Connect to receive media session updates. - content::MediaSession::Get(web_contents) - ->AddObserver( - media_session_observer_receiver_.BindNewPipeAndPassRemote()); + // Connect to receive media session updates if the media session already + // exists. If it does not, then we'll become an observer in + // `MediaSessionCreated()`. + content::MediaSession* media_session = + content::MediaSession::GetIfExists(web_contents); + if (media_session) { + media_session->AddObserver( + media_session_observer_receiver_.BindNewPipeAndPassRemote()); + } } AutoPictureInPictureTabHelper::~AutoPictureInPictureTabHelper() = default; @@ -86,6 +91,13 @@ } } +void AutoPictureInPictureTabHelper::MediaSessionCreated( + content::MediaSession* media_session) { + // Connect to receive media session updates. + media_session->AddObserver( + media_session_observer_receiver_.BindNewPipeAndPassRemote()); +} + void AutoPictureInPictureTabHelper::OnTabActivatedChanged( bool is_tab_activated) { is_tab_activated_ = is_tab_activated;
diff --git a/chrome/browser/picture_in_picture/auto_picture_in_picture_tab_helper.h b/chrome/browser/picture_in_picture/auto_picture_in_picture_tab_helper.h index fc6a0a1..bee3598d 100644 --- a/chrome/browser/picture_in_picture/auto_picture_in_picture_tab_helper.h +++ b/chrome/browser/picture_in_picture/auto_picture_in_picture_tab_helper.h
@@ -47,6 +47,7 @@ // content::WebContentsObserver: void PrimaryPageChanged(content::Page& page) override; void MediaPictureInPictureChanged(bool is_in_picture_in_picture) override; + void MediaSessionCreated(content::MediaSession* media_session) override; // Called by `tab_strip_observer_helper_` when the tab changes between // activated and unactivated.
diff --git a/chrome/browser/policy/configuration_policy_handler_list_factory.cc b/chrome/browser/policy/configuration_policy_handler_list_factory.cc index 277034d..1ae5c2a 100644 --- a/chrome/browser/policy/configuration_policy_handler_list_factory.cc +++ b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
@@ -791,6 +791,11 @@ { key::kForceGoogleSafeSearch, policy_prefs::kForceGoogleSafeSearch, base::Value::Type::BOOLEAN }, +#if BUILDFLAG(IS_CHROMEOS) + { key::kEssentialSearchEnabled, + prefs::kEssentialSearchEnabled, + base::Value::Type::BOOLEAN }, +#endif // BUILDFLAG(IS_CHROMEOS) { key::kForceYouTubeRestrict, policy::policy_prefs::kForceYouTubeRestrict, base::Value::Type::INTEGER },
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc index 7a6e93f..58ca863 100644 --- a/chrome/browser/prefs/browser_prefs.cc +++ b/chrome/browser/prefs/browser_prefs.cc
@@ -1854,6 +1854,7 @@ registry->RegisterBooleanPref(prefs::kDeskAPIDeskSaveAndShareEnabled, false); registry->RegisterListPref(prefs::kDeskAPIThirdPartyAllowlist); registry->RegisterBooleanPref(prefs::kInsightsExtensionEnabled, false); + registry->RegisterBooleanPref(prefs::kEssentialSearchEnabled, false); // By default showing Sync Consent is set to true. It can changed by policy. registry->RegisterBooleanPref(prefs::kEnableSyncConsent, true); registry->RegisterListPref(
diff --git a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc index c2ba0da..908b53d9 100644 --- a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc +++ b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
@@ -210,6 +210,7 @@ #include "components/captive_portal/core/buildflags.h" #include "components/commerce/core/proto/commerce_subscription_db_content.pb.h" #include "components/commerce/core/proto/persisted_state_db_content.pb.h" +#include "components/enterprise/buildflags/buildflags.h" #include "components/enterprise/content/clipboard_restriction_service.h" #include "components/media_effects/media_effects_service_factory.h" #include "components/offline_pages/buildflags/buildflags.h" @@ -506,6 +507,10 @@ #endif // BUILDFLAG(ENABLE_BOUND_SESSION_CREDENTIALS) +#if BUILDFLAG(ENTERPRISE_DATA_CONTROLS) +#include "chrome/browser/enterprise/data_controls/rules_service.h" +#endif + namespace chrome { void AddProfilesExtraParts(ChromeBrowserMainParts* main_parts) { @@ -738,6 +743,9 @@ CrosAppsKeyEventHandlerFactory::GetInstance(); } #endif +#if BUILDFLAG(ENTERPRISE_DATA_CONTROLS) + data_controls::RulesServiceFactory::GetInstance(); +#endif data_sharing::DataSharingServiceFactory::GetInstance(); #if !BUILDFLAG(IS_ANDROID) DevToolsAndroidBridge::Factory::GetInstance();
diff --git a/chrome/browser/profiles/profile_keyed_service_browsertest.cc b/chrome/browser/profiles/profile_keyed_service_browsertest.cc index 7154c0f..2a89dba 100644 --- a/chrome/browser/profiles/profile_keyed_service_browsertest.cc +++ b/chrome/browser/profiles/profile_keyed_service_browsertest.cc
@@ -580,6 +580,7 @@ "AutocompleteControllerEmitter", "AutofillInternalsService", "CanMakePaymentQuery", + "DataControlsRulesService", "LocalPresentationManager", "OmniboxInputWatcher", "OmniboxSuggestionsWatcher", @@ -623,6 +624,7 @@ // default, however their creation is still possible. "AutocompleteControllerEmitter", "CanMakePaymentQuery", + "DataControlsRulesService", "OmniboxInputWatcher", "OmniboxSuggestionsWatcher", "PolicyBlocklist",
diff --git a/chrome/browser/push_notification/BUILD.gn b/chrome/browser/push_notification/BUILD.gn index 1e276149..db687e4c 100644 --- a/chrome/browser/push_notification/BUILD.gn +++ b/chrome/browser/push_notification/BUILD.gn
@@ -6,8 +6,6 @@ sources = [ "prefs/push_notification_prefs.cc", "prefs/push_notification_prefs.h", - "push_notification_client_manager_desktop_impl.cc", - "push_notification_client_manager_desktop_impl.h", "push_notification_service_desktop_impl.cc", "push_notification_service_desktop_impl.h", ]
diff --git a/chrome/browser/push_notification/push_notification_client_manager_desktop_impl.cc b/chrome/browser/push_notification/push_notification_client_manager_desktop_impl.cc deleted file mode 100644 index 641a35a..0000000 --- a/chrome/browser/push_notification/push_notification_client_manager_desktop_impl.cc +++ /dev/null
@@ -1,20 +0,0 @@ -// Copyright 2023 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/push_notification/push_notification_client_manager_desktop_impl.h" - -namespace push_notification { -PushNotificationClientManagerDesktopImpl:: - PushNotificationClientManagerDesktopImpl() = default; -PushNotificationClientManagerDesktopImpl:: - ~PushNotificationClientManagerDesktopImpl() = default; - -void PushNotificationClientManagerDesktopImpl:: - NotifyPushNotificationClientOfMessage(PushNotificationMessage message) { - // TODO(b/287340843): Parse the message and - // extract the `PushNotificationClientId` to pass the message to the correct - // `PushNotificationClient`. -} - -} // namespace push_notification
diff --git a/chrome/browser/push_notification/push_notification_client_manager_desktop_impl.h b/chrome/browser/push_notification/push_notification_client_manager_desktop_impl.h deleted file mode 100644 index e9a64f71..0000000 --- a/chrome/browser/push_notification/push_notification_client_manager_desktop_impl.h +++ /dev/null
@@ -1,29 +0,0 @@ -// Copyright 2023 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_PUSH_NOTIFICATION_PUSH_NOTIFICATION_CLIENT_MANAGER_DESKTOP_IMPL_H_ -#define CHROME_BROWSER_PUSH_NOTIFICATION_PUSH_NOTIFICATION_CLIENT_MANAGER_DESKTOP_IMPL_H_ - -#include "components/push_notification/push_notification_client_manager.h" - -namespace push_notification { - -class PushNotificationClientManagerDesktopImpl - : public PushNotificationClientManager { - public: - PushNotificationClientManagerDesktopImpl(); - PushNotificationClientManagerDesktopImpl( - const PushNotificationClientManagerDesktopImpl&) = delete; - PushNotificationClientManagerDesktopImpl& operator=( - const PushNotificationClientManagerDesktopImpl&) = delete; - ~PushNotificationClientManagerDesktopImpl() override; - - // PushNotificationClientManager: - void NotifyPushNotificationClientOfMessage( - PushNotificationMessage message) override; -}; - -} // namespace push_notification - -#endif // CHROME_BROWSER_PUSH_NOTIFICATION_PUSH_NOTIFICATION_CLIENT_MANAGER_DESKTOP_IMPL_H_
diff --git a/chrome/browser/push_notification/push_notification_client_manager_desktop_impl_unittest.cc b/chrome/browser/push_notification/push_notification_client_manager_desktop_impl_unittest.cc deleted file mode 100644 index 56523b6..0000000 --- a/chrome/browser/push_notification/push_notification_client_manager_desktop_impl_unittest.cc +++ /dev/null
@@ -1,34 +0,0 @@ -// Copyright 2023 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/push_notification/push_notification_client_manager_desktop_impl.h" - -#include "testing/gtest/include/gtest/gtest.h" - -#include <memory> - -namespace push_notification { - -class PushNotificationClientManagerDesktopImplTest : public testing::Test { - public: - PushNotificationClientManagerDesktopImplTest() = default; - ~PushNotificationClientManagerDesktopImplTest() override = default; - - // testing::Test: - void SetUp() override { - push_notification_client_manager_ = - std::make_unique<PushNotificationClientManagerDesktopImpl>(); - } - - std::unique_ptr<PushNotificationClientManagerDesktopImpl> - push_notification_client_manager_; -}; - -TEST_F(PushNotificationClientManagerDesktopImplTest, AddClient) { - EXPECT_TRUE(push_notification_client_manager_); - // TODO(b/306398998): Test adding, removing and passing a message to a client - // when that functionality is implemented. -} - -} // namespace push_notification
diff --git a/chrome/browser/push_notification/push_notification_service_desktop_impl.cc b/chrome/browser/push_notification/push_notification_service_desktop_impl.cc index 98aeeab..e265b56a 100644 --- a/chrome/browser/push_notification/push_notification_service_desktop_impl.cc +++ b/chrome/browser/push_notification/push_notification_service_desktop_impl.cc
@@ -3,6 +3,7 @@ // found in the LICENSE file. #include "chrome/browser/push_notification/push_notification_service_desktop_impl.h" + #include "base/check.h" #include "components/prefs/pref_service.h" @@ -16,6 +17,10 @@ PushNotificationServiceDesktopImpl::~PushNotificationServiceDesktopImpl() = default; -void PushNotificationServiceDesktopImpl::Shutdown() {} +void PushNotificationServiceDesktopImpl::Shutdown() { + // TODO(b/306398998): Once fetching GCM token is implemented, reset the token + // here. + client_manager_.reset(); +} } // namespace push_notification
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/ReadAloudController.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/ReadAloudController.java index b6a4706f..1580eae 100644 --- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/ReadAloudController.java +++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/ReadAloudController.java
@@ -733,6 +733,7 @@ promise.then( playback -> { Log.d(TAG, "Voice preview playback created."); + ReadAloudMetrics.recordVoicePreviewed(voice.getVoiceId()); mVoicePreviewPlayback = playback; playback.addListener(mVoicePreviewPlaybackListener); mVoicePreviewPlayback.play();
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/ReadAloudControllerUnitTest.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/ReadAloudControllerUnitTest.java index 62563aa3d..f7bcbd7 100644 --- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/ReadAloudControllerUnitTest.java +++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/ReadAloudControllerUnitTest.java
@@ -921,6 +921,28 @@ } @Test + public void testPreviewVoice_metric() { + final String histogramName = ReadAloudMetrics.VOICE_PREVIEWED; + + var histogram = HistogramWatcher.newSingleRecordWatcher(histogramName + "abc", true); + + // Play tab. + requestAndStartPlayback(); + + reset(mPlaybackHooks); + // Preview a voice. + var voice = new PlaybackVoice("en", "abc", ""); + doReturn(List.of(voice)).when(mPlaybackHooks).getVoicesFor(anyString()); + doReturn(List.of(voice)).when(mPlaybackHooks).getPlaybackVoiceList(any()); + mController.previewVoice(voice); + verify(mPlaybackHooks).createPlayback(any(), mPlaybackCallbackCaptor.capture()); + Playback previewPlayback = Mockito.mock(Playback.class); + onPlaybackSuccess(previewPlayback); + + histogram.assertExpected(); + } + + @Test public void testRestorePlaybackState_whileLoading() { // Request playback but don't succeed yet. mController.playTab(mTab);
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/ReadAloudMetrics.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/ReadAloudMetrics.java index 56e7ad2..431d4cce 100644 --- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/ReadAloudMetrics.java +++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/ReadAloudMetrics.java
@@ -29,6 +29,10 @@ public static String IS_TAB_PLAYBACK_CREATION_SUCCESSFUL = "ReadAloud.IsTabPlaybackCreationSuccessful"; + public static String VOICE_CHANGED = "ReadAloud.VoiceChanged."; + + public static String VOICE_PREVIEWED = "ReadAloud.VoicePreviewed."; + /** * The reason why we clear the prepared message. * @@ -136,4 +140,12 @@ public static void recordPlaybackStarted() { RecordUserAction.record("ReadAloud.PlaybackStarted"); } + + public static void recordVoiceChanged(String voiceID) { + RecordHistogram.recordBooleanHistogram(VOICE_CHANGED + voiceID, true); + } + + public static void recordVoicePreviewed(String voiceID) { + RecordHistogram.recordBooleanHistogram(VOICE_PREVIEWED + voiceID, true); + } }
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/ReadAloudPrefs.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/ReadAloudPrefs.java index 0605e81..ded68fe 100644 --- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/ReadAloudPrefs.java +++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/ReadAloudPrefs.java
@@ -51,6 +51,7 @@ if (language == null || language.isEmpty() || voiceId == null || voiceId.isEmpty()) { return; } + ReadAloudMetrics.recordVoiceChanged(voiceId); ReadAloudPrefsJni.get().setVoice(prefs, language, voiceId); }
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/ReadAloudPrefsUnitTest.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/ReadAloudPrefsUnitTest.java index 29d41f6..5ca0a6b 100644 --- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/ReadAloudPrefsUnitTest.java +++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/ReadAloudPrefsUnitTest.java
@@ -82,6 +82,19 @@ } @Test + public void testSetVoice_metric() { + final String histogramName = ReadAloudMetrics.VOICE_CHANGED; + + var histogram = HistogramWatcher.newSingleRecordWatcher(histogramName + "abc", true); + ReadAloudPrefs.setVoice(mPrefService, "en", "abc"); + histogram.assertExpected(); + + histogram = HistogramWatcher.newSingleRecordWatcher(histogramName + "def", true); + ReadAloudPrefs.setVoice(mPrefService, "es", "def"); + histogram.assertExpected(); + } + + @Test public void testDefaultSpeed() { assertEquals(1f, ReadAloudPrefs.getSpeed(mPrefService), /* delta= */ 0f); }
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu_browsertest.cc b/chrome/browser/renderer_context_menu/render_view_context_menu_browsertest.cc index abf1d05..e5b0b9c 100644 --- a/chrome/browser/renderer_context_menu/render_view_context_menu_browsertest.cc +++ b/chrome/browser/renderer_context_menu/render_view_context_menu_browsertest.cc
@@ -1357,13 +1357,7 @@ } // Opens a link in a new tab via a "real" context menu. -// TODO(crbug.com/1462760): Enable the test. -#if BUILDFLAG(IS_MAC) -#define MAYBE_RealMenu DISABLED_RealMenu -#else -#define MAYBE_RealMenu RealMenu -#endif -IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest, MAYBE_RealMenu) { +IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest, RealMenu) { ContextMenuNotificationObserver menu_observer( IDC_CONTENT_CONTEXT_OPENLINKNEWTAB); ui_test_utils::AllBrowserTabAddedWaiter add_tab; @@ -3055,24 +3049,12 @@ size_t request_attempts_ = 0u; }; -// TODO(crbug.com/1462760): Enable the test. -#if BUILDFLAG(IS_MAC) -#define MAYBE_LoadImage DISABLED_LoadImage -#else -#define MAYBE_LoadImage LoadImage -#endif -IN_PROC_BROWSER_TEST_F(LoadImageBrowserTest, MAYBE_LoadImage) { +IN_PROC_BROWSER_TEST_F(LoadImageBrowserTest, LoadImage) { SetupAndLoadImagePage("/load_image/image.html", "/load_image/image.png"); AttemptLoadImage(); } -// TODO(crbug.com/1462760): Enable the test. -#if BUILDFLAG(IS_MAC) -#define MAYBE_LoadImageWithMap DISABLED_LoadImageWithMap -#else -#define MAYBE_LoadImageWithMap LoadImageWithMap -#endif -IN_PROC_BROWSER_TEST_F(LoadImageBrowserTest, MAYBE_LoadImageWithMap) { +IN_PROC_BROWSER_TEST_F(LoadImageBrowserTest, LoadImageWithMap) { SetupAndLoadImagePage("/load_image/image_with_map.html", "/load_image/image.png"); AttemptLoadImage(); @@ -3176,26 +3158,14 @@ blink::mojom::ContextMenuDataMediaType::kNone, ui::MENU_SOURCE_MOUSE); } -// TODO(crbug.com/1462760): Enable the test. -#if BUILDFLAG(IS_MAC) -#define MAYBE_GifImageShare DISABLED_GifImageShare -#else -#define MAYBE_GifImageShare GifImageShare -#endif -IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest, MAYBE_GifImageShare) { +IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest, GifImageShare) { OpenImagePageAndContextMenu("/google/logo.gif"); RequestImageAndVerifyResponse( gfx::Size(2048, 2048), chrome::mojom::ImageFormat::ORIGINAL, gfx::Size(276, 110), gfx::Size(276, 110), ".gif"); } -// TODO(crbug.com/1462760): Enable the test. -#if BUILDFLAG(IS_MAC) -#define MAYBE_GifImageDownscaleToJpeg DISABLED_GifImageDownscaleToJpeg -#else -#define MAYBE_GifImageDownscaleToJpeg GifImageDownscaleToJpeg -#endif -IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest, MAYBE_GifImageDownscaleToJpeg) { +IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest, GifImageDownscaleToJpeg) { OpenImagePageAndContextMenu("/google/logo.gif"); RequestImageAndVerifyResponse( gfx::Size(100, 100), chrome::mojom::ImageFormat::ORIGINAL, @@ -3228,15 +3198,7 @@ gfx::Size(100, 50), ".png"); } -// TODO(crbug.com/1462760): Enable the test. -#if BUILDFLAG(IS_MAC) -#define MAYBE_PngImageOriginalDownscaleToPng \ - DISABLED_PngImageOriginalDownscaleToPng -#else -#define MAYBE_PngImageOriginalDownscaleToPng PngImageOriginalDownscaleToPng -#endif -IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest, - MAYBE_PngImageOriginalDownscaleToPng) { +IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest, PngImageOriginalDownscaleToPng) { OpenImagePageAndContextMenu("/image_search/valid.png"); RequestImageAndVerifyResponse( gfx::Size(100, 100), chrome::mojom::ImageFormat::ORIGINAL, @@ -3256,13 +3218,7 @@ gfx::Size(480, 320), gfx::Size(100, /* 100 / 480 * 320 = */ 66), ".jpg"); } -// TODO(crbug.com/1462760): Enable the test. -#if BUILDFLAG(IS_MAC) -#define MAYBE_JpgImageDownscaleToWebp DISABLED_JpgImageDownscaleToWebp -#else -#define MAYBE_JpgImageDownscaleToWebp JpgImageDownscaleToWebp -#endif -IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest, MAYBE_JpgImageDownscaleToWebp) { +IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest, JpgImageDownscaleToWebp) { OpenImagePageAndContextMenu("/android/watch.jpg"); RequestImageAndVerifyResponse( gfx::Size(100, 100), chrome::mojom::ImageFormat::WEBP,
diff --git a/chrome/browser/resources/ash/settings/nearby_share_page/nearby_share_high_visibility_page.html b/chrome/browser/resources/ash/settings/nearby_share_page/nearby_share_high_visibility_page.html index 0952fa6..c9e694b2 100644 --- a/chrome/browser/resources/ash/settings/nearby_share_page/nearby_share_high_visibility_page.html +++ b/chrome/browser/resources/ash/settings/nearby_share_page/nearby_share_high_visibility_page.html
@@ -122,11 +122,7 @@ cancel-button-label="$i18n{cancel}" close-only="[[getErrorTitle_(errorState_)]]"> <div id="content" slot="content"> - <!-- TODO(b/279623883): Remove dark mode handling. --> - <iron-media-query query="(prefers-color-scheme: dark)" - query-matches="{{isDarkModeActive_}}"> - </iron-media-query> - <cros-lottie-renderer id="animation" asset-url="[[getAnimationUrl_(isDarkModeActive_, isJellyEnabled_)]]" + <cros-lottie-renderer id="animation" asset-url="[[getAnimationUrl_()]]" autoplay dynamic aria-hidden> </cros-lottie-renderer> <div id="help">
diff --git a/chrome/browser/resources/ash/settings/nearby_share_page/nearby_share_high_visibility_page.ts b/chrome/browser/resources/ash/settings/nearby_share_page/nearby_share_high_visibility_page.ts index 76bc578..30bc27ad 100644 --- a/chrome/browser/resources/ash/settings/nearby_share_page/nearby_share_high_visibility_page.ts +++ b/chrome/browser/resources/ash/settings/nearby_share_page/nearby_share_high_visibility_page.ts
@@ -12,13 +12,11 @@ import 'chrome://resources/cros_components/lottie_renderer/lottie-renderer.js'; import 'chrome://resources/polymer/v3_0/iron-icon/iron-icon.js'; import 'chrome://resources/cr_components/localized_link/localized_link.js'; -import 'chrome://resources/polymer/v3_0/iron-media-query/iron-media-query.js'; import '/shared/nearby_page_template.js'; import '/shared/nearby_shared_icons.html.js'; import {RegisterReceiveSurfaceResult} from '/shared/nearby_share.mojom-webui.js'; import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js'; -import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {getTemplate} from './nearby_share_high_visibility_page.html.js'; @@ -33,22 +31,10 @@ SOMETHING_WRONG = 3, } -// TODO(TODO(b/279623883): Remove dark mode handling. - /** - * The pulse animation asset URL for light mode. + * The pulse animation asset URL. */ -const PULSE_ANIMATION_URL_LIGHT = 'nearby_share_pulse_animation_light.json'; - -/** - * The pulse animation asset URL for dark mode. - */ -const PULSE_ANIMATION_URL_DARK = 'nearby_share_pulse_animation_dark.json'; - -/** - * The pulse animation asset URL for jelly mode. - */ -const PULSE_ANIMATION_URL_JELLY = 'nearby_share_pulse_animation_jelly.json'; +const PULSE_ANIMATION_URL = 'nearby_share_pulse_animation.json'; const NearbyShareHighVisibilityPageElementBase = I18nMixin(PolymerElement); @@ -113,26 +99,6 @@ 'computeErrorState_(shutoffTimestamp, remainingTimeInSeconds_,' + 'registerResult, nearbyProcessStopped, startAdvertisingFailed)', }, - - /** - * Whether the high visibility page is being rendered in dark mode. - */ - isDarkModeActive_: { - type: Boolean, - value: false, - }, - - /** - * Return true if the Jelly feature flag is enabled. - */ - isJellyEnabled_: { - type: Boolean, - readOnly: true, - value() { - return loadTimeData.valueExists('isJellyEnabled') && - loadTimeData.getBoolean('isJellyEnabled'); - }, - }, }; } @@ -142,8 +108,6 @@ shutoffTimestamp: number; startAdvertisingFailed: boolean; private errorState_: NearbyVisibilityErrorState|null; - private isDarkModeActive_: boolean; - private isJellyEnabled_: boolean; private remainingTimeInSeconds_: number; private remainingTimeIntervalId_: number; @@ -287,14 +251,7 @@ * pulsing background animation. */ private getAnimationUrl_(): string { - if (this.isJellyEnabled_) { - return PULSE_ANIMATION_URL_JELLY; - } - - // TODO(b/279623883): Clean up dark mode logic and duplicate assets after - // Jelly is launched. - return this.isDarkModeActive_ ? PULSE_ANIMATION_URL_DARK : - PULSE_ANIMATION_URL_LIGHT; + return PULSE_ANIMATION_URL; } }
diff --git a/chrome/browser/resources/ash/settings/os_apps_page/app_management_page/arc_detail_view.html b/chrome/browser/resources/ash/settings/os_apps_page/app_management_page/arc_detail_view.html index e0b4f7e..8d96dc66 100644 --- a/chrome/browser/resources/ash/settings/os_apps_page/app_management_page/arc_detail_view.html +++ b/chrome/browser/resources/ash/settings/os_apps_page/app_management_page/arc_detail_view.html
@@ -2,6 +2,10 @@ #noPermissions { border-top: none; } + + #appDetails { + padding-bottom: 12px; + } </style> <div class="permission-list"> <app-management-pin-to-shelf-item
diff --git a/chrome/browser/resources/ash/settings/os_settings_page/os_settings_subpage.html b/chrome/browser/resources/ash/settings/os_settings_page/os_settings_subpage.html index 966d6e2..e85c707 100644 --- a/chrome/browser/resources/ash/settings/os_settings_page/os_settings_subpage.html +++ b/chrome/browser/resources/ash/settings/os_settings_page/os_settings_subpage.html
@@ -68,6 +68,13 @@ /* Keep normal icon spacing from subpage-title-extra controls. */ margin-inline-start: 16px; } + + /* Use ID to increase specificity over cros-color-overrides. */ + :host-context(body.revamp-wayfinding-enabled) + #searchField::part(searchInput) { + /* Add contrast between the search input and the subpage backdrop. */ + --cr-input-background-color: var(--cros-sys-input_field_on_shaded); + } </style> <div id="subpageHeader" class="cr-row first"> <cr-icon-button id="closeButton" class="icon-arrow-back" @@ -86,7 +93,8 @@ </cr-icon-button> </template> <template is="dom-if" if="[[searchLabel]]"> - <cr-search-field label="[[searchLabel]]" + <cr-search-field id="searchField" + label="[[searchLabel]]" on-search-changed="onSearchChanged_" clear-label="$i18n{clearSearch}"> </cr-search-field>
diff --git a/chrome/browser/resources/ash/settings/os_settings_search_box/os_search_result_row.html b/chrome/browser/resources/ash/settings/os_settings_search_box/os_search_result_row.html index a73a8dc..37b9263e 100644 --- a/chrome/browser/resources/ash/settings/os_settings_search_box/os_search_result_row.html +++ b/chrome/browser/resources/ash/settings/os_settings_search_box/os_search_result_row.html
@@ -28,6 +28,7 @@ display: flex; height: 48px; justify-content: center; + font: var(--cros-body-2-font); } #resultText {
diff --git a/chrome/browser/resources/ash/settings/os_settings_search_box/os_settings_search_box.html b/chrome/browser/resources/ash/settings/os_settings_search_box/os_settings_search_box.html index 361a3485..9a51c848 100644 --- a/chrome/browser/resources/ash/settings/os_settings_search_box/os_settings_search_box.html +++ b/chrome/browser/resources/ash/settings/os_settings_search_box/os_settings_search_box.html
@@ -50,8 +50,8 @@ --cr-toolbar-icon-button-focus-outline-color: var(--cros-focus-ring-color); --cr-toolbar-field-max-width: var(--cr-toolbar-field-width); + font: var(--cros-body-2-font); height: var(--settings-toolbar-search-box-height); - font-size: 13px; } :host([narrow][showing-search]) cr-toolbar-search-field { @@ -125,6 +125,7 @@ height: 32px; line-height: 32px; margin-inline-start: 24px; + font: var(--cros-body-2-font); } #reportSearchResult {
diff --git a/chrome/browser/resources/chromeos/arc_graphics_tracing/arc_overview_tracing_ui.js b/chrome/browser/resources/chromeos/arc_graphics_tracing/arc_overview_tracing_ui.js index c471ea4..e05c5e5 100644 --- a/chrome/browser/resources/chromeos/arc_graphics_tracing/arc_overview_tracing_ui.js +++ b/chrome/browser/resources/chromeos/arc_graphics_tracing/arc_overview_tracing_ui.js
@@ -49,15 +49,6 @@ */ const targetFrameTime = 16667; -// Graphics event types which are used in the model JSON data. These must match -// the graphics event types in -// chrome/browser/ash/arc/tracing/arc_tracing_graphics_model.h. To aid in -// maintaining consistency, do not modify values once added - deprecation and -// removal are allowed. -const kExoSurfaceCommit = 206; -const kChromeOSPresentationDone = 503; -const kChromeOSSwapDone = 504; - function initializeOverviewUi() { initializeUi(8 /* zoomLevel */, function() { // Update function. @@ -696,8 +687,10 @@ * @param {number} duration length of the chart in microseconds. * @param {string} title the title of the view * @param {number} eventType type of event whose rate to track + * @param {number} jankEventType type of event indicating a jank (optional) */ -function addDeltaView(parent, resolution, duration, title, eventType) { +function addDeltaView( + parent, resolution, duration, title, eventType, jankEventType) { // time range from 0 to 67ms. 66.67ms is for 15 FPS. // 1 ms 1 pixel resolution. Each grid lines correspond 1/120 FPS time update. const bands = createChart( @@ -716,6 +709,14 @@ const timeEvents = createDeltaEvents(events); attributes.color = modelColors.get(models[i]); bands.addChartSources([timeEvents], false /* smooth */, attributes); + if (jankEventType) { + // Offset each model's janks at a different y position, avoiding max and + // min positions (0 or 1), as these are awkward when the models are few. + const y = (i + 1) / (models.length + 1); + bands.addGlobal( + getGraphicsEvents(models[i], jankEventType), 'circle', + attributes.color, y); + } } } @@ -790,14 +791,16 @@ addFPSView(parent, resolution, duration, 'App FPS', kExoSurfaceCommit); addDeltaView( - parent, resolution, duration, 'App commit time', kExoSurfaceCommit); + parent, resolution, duration, 'App commit time', kExoSurfaceCommit, + kExoSurfaceCommitJank); addDeltaView( - parent, resolution, duration, 'ChromeOS swap time', kChromeOSSwapDone); + parent, resolution, duration, 'ChromeOS swap time', kChromeOSSwapDone, + kChromeOSSwapJank); addFPSView( parent, resolution, duration, 'Perceived FPS', kChromeOSPresentationDone); addDeltaView( parent, resolution, duration, 'Perceived swap time', - kChromeOSPresentationDone); + kChromeOSPresentationDone, kChromeOSPerceivedJank); addFPSHistograms( parent, parent.lastChild, false /* timeBasedView */,
diff --git a/chrome/browser/resources/chromeos/arc_graphics_tracing/arc_tracing_ui.js b/chrome/browser/resources/chromeos/arc_graphics_tracing/arc_tracing_ui.js index 6daf1bf..e0ba440 100644 --- a/chrome/browser/resources/chromeos/arc_graphics_tracing/arc_tracing_ui.js +++ b/chrome/browser/resources/chromeos/arc_graphics_tracing/arc_tracing_ui.js
@@ -35,6 +35,18 @@ // Active zoom level, as index in |zooms|. By default 100 mcs per pixel. let zoomLevel = 5; +// Graphics event types which are used in the model JSON data. These must match +// the graphics event types in +// chrome/browser/ash/arc/tracing/arc_tracing_graphics_model.h. To aid in +// maintaining consistency, do not modify values once added - deprecation and +// removal are allowed. +const kExoSurfaceCommit = 206; +const kExoSurfaceCommitJank = 207; +const kChromeOSPresentationDone = 503; +const kChromeOSSwapDone = 504; +const kChromeOSPerceivedJank = 506; +const kChromeOSSwapJank = 507; + /** * Keep in sync with ArcTracingGraphicsModel::EventType * See chrome/browser/ash/arc/tracing/arc_tracing_graphics_model.h. @@ -67,6 +79,8 @@ // kBufferFillJank 106: {color: '#ff0000', name: 'buffer filling jank', width: 1.0, radius: 4.0}, + [kExoSurfaceCommitJank]: {name: 'commit jank', radius: 4.0}, + // kChromeBarrierOrder. 300: {color: '#ff9933', name: 'barrier order'}, // kChromeBarrierFlush @@ -98,6 +112,14 @@ width: 1.0, radius: 4.0, }, + [kChromeOSPerceivedJank]: { + name: 'perceived jank', + radius: 4.0, + }, + [kChromeOSSwapJank]: { + name: 'swap jank', + radius: 4.0, + }, // kCustomEvent 600: {color: '#7cb342', name: 'Custom event', width: 1.0, radius: 4.0}, @@ -915,9 +937,18 @@ * @param {Events} events to add. * @param {string} renderType defines how to render events, can be underfined * for default or set to 'circle'. + * @param {string} color the color (fill color if rendered as a circle), or + * omitted to use the color defined in eventAttributes for + * each event type. + * @param {number} y for circles, the y position, as a fraction of this band's + * height, such as 0.5 for vertically-centered, or 0.95 for + * close to the bottom. */ - addGlobal(events, renderType) { + addGlobal(events, renderType, color, y) { let eventIndex = -1; + if (typeof y == 'undefined') { + y = 0.5; + } while (true) { eventIndex = events.getNextEvent(eventIndex, 1 /* direction */); if (eventIndex < 0) { @@ -926,13 +957,13 @@ const event = events.events[eventIndex]; const attributes = events.getEventAttributes(eventIndex); const x = this.timestampToOffset(event[1]) + this.bandOffsetX; + const evColor = color || attributes.color; if (renderType == 'circle') { SVG.addCircle( - this.svg, x, this.height / 2, attributes.radius, - 1 /* strokeWidth */, attributes.color, 'black' /* strokeColor */); + this.svg, x, this.height * y, attributes.radius, + 1 /* strokeWidth */, evColor, 'black' /* strokeColor */); } else { - SVG.addLine( - this.svg, x, 0, x, this.height, attributes.color, attributes.width); + SVG.addLine(this.svg, x, 0, x, this.height, evColor, attributes.width); } } this.globalEvents.push(events);
diff --git a/chrome/browser/resources/compose/app.html b/chrome/browser/resources/compose/app.html index 909a0d4..f6b0550 100644 --- a/chrome/browser/resources/compose/app.html +++ b/chrome/browser/resources/compose/app.html
@@ -507,6 +507,11 @@ inert$="[[hasPartialResponse_(partialResponse_)]]"> <div class="footer-text"> <div on-click="onFooterClick_"> + <b id="onDeviceUsedFooter" + hidden$="[[!onDeviceEvaluationUsed_(response_)]]" + >$i18nRaw{onDeviceUsedFooter} + + </b> $i18nRaw{resultFooter} </div> <cr-feedback-buttons
diff --git a/chrome/browser/resources/compose/app.ts b/chrome/browser/resources/compose/app.ts index 8a2a7f7..b8ad172 100644 --- a/chrome/browser/resources/compose/app.ts +++ b/chrome/browser/resources/compose/app.ts
@@ -61,6 +61,7 @@ submitButton: CrButtonElement, submitEditButton: CrButtonElement, submitFooter: HTMLElement, + onDeviceUsedFooter: HTMLElement, textarea: ComposeTextareaElement, lengthMenu: HTMLSelectElement, toneMenu: HTMLSelectElement, @@ -559,6 +560,10 @@ return this.response_.status !== ComposeStatus.kOk; } + private onDeviceEvaluationUsed_(): boolean { + return Boolean(this.response_?.onDeviceEvaluationUsed); + } + private acceptButtonText_(): string { return this.textSelected_ ? this.i18n('replaceButton') : this.i18n('insertButton');
diff --git a/chrome/browser/resources/compose/textarea.ts b/chrome/browser/resources/compose/textarea.ts index dadfe23..aa2ba1220 100644 --- a/chrome/browser/resources/compose/textarea.ts +++ b/chrome/browser/resources/compose/textarea.ts
@@ -110,9 +110,11 @@ validate() { const value = this.$.input.value; const wordCount = value.match(/\S+/g)?.length || 0; - this.tooShort_ = wordCount < this.inputParams.minWordLimit; this.tooLong_ = value.length > this.inputParams.maxCharacterLimit || wordCount > this.inputParams.maxWordLimit; + // If it's too long, then it can't be too short. + this.tooShort_ = + wordCount < this.inputParams.minWordLimit && !this.tooLong_; this.invalidInput_ = this.tooLong_ || this.tooShort_; return !this.invalidInput_; }
diff --git a/chrome/browser/resources/nearby_share/nearby_discovery_page.html b/chrome/browser/resources/nearby_share/nearby_discovery_page.html index eebacce..589bdd4 100644 --- a/chrome/browser/resources/nearby_share/nearby_discovery_page.html +++ b/chrome/browser/resources/nearby_share/nearby_discovery_page.html
@@ -229,11 +229,7 @@ cancel-button-event-name="close" close-only="[[errorTitle_]]"> <div id="centerContent" slot="content"> - <!-- TODO(b/279623883): Remove dark mode handling. --> - <iron-media-query query="(prefers-color-scheme: dark)" - query-matches="{{isDarkModeActive_}}"> - </iron-media-query> - <cros-lottie-renderer id="animation" asset-url="[[getAnimationUrl_(isDarkModeActive_, isJellyEnabled_)]]" + <cros-lottie-renderer id="animation" asset-url="[[getAnimationUrl_()]]" autoplay dynamic aria-hidden> </cros-lottie-renderer> <div id="process-row">
diff --git a/chrome/browser/resources/nearby_share/nearby_discovery_page.ts b/chrome/browser/resources/nearby_share/nearby_discovery_page.ts index 296fb30..4630785 100644 --- a/chrome/browser/resources/nearby_share/nearby_discovery_page.ts +++ b/chrome/browser/resources/nearby_share/nearby_discovery_page.ts
@@ -43,26 +43,10 @@ return a.high === b.high && a.low === b.low; } -// TODO(TODO(b/279623883): Remove dark mode handling. - /** - * The pulse animation asset URL for light mode. + * The pulse animation asset URL. */ -const PULSE_ANIMATION_URL_LIGHT: string = - 'nearby_share_pulse_animation_light.json'; - -/** - * The pulse animation asset URL for dark mode. - */ -const PULSE_ANIMATION_URL_DARK: string = - 'nearby_share_pulse_animation_dark.json'; - -/** - * The pulse animation asset URL for jelly mode. - */ -const PULSE_ANIMATION_URL_JELLY: string = - 'nearby_share_pulse_animation_jelly.json'; - +const PULSE_ANIMATION_URL: string = 'nearby_share_pulse_animation.json'; const NearbyDiscoveryPageElementBase = I18nMixin(PolymerElement); @@ -160,26 +144,6 @@ }, /** - * Whether the discovery page is being rendered in dark mode. - */ - isDarkModeActive_: { - type: Boolean, - value: false, - }, - - /** - * Return true if the Jelly feature flag is enabled. - */ - isJellyEnabled_: { - type: Boolean, - readOnly: true, - value() { - return loadTimeData.valueExists('isJellyEnabled') && - loadTimeData.getBoolean('isJellyEnabled'); - }, - }, - - /** * Return true if the Nearby Share Self Share feature flag is enabled. */ isSelfShareEnabled: { @@ -204,8 +168,6 @@ private nonSelfShareTargets_: ShareTarget[]; private errorTitle_: string|null; private errorDescription_: string|null; - private isDarkModeActive_: boolean; - private isJellyEnabled_: boolean; private mojoEventTarget_: ShareTargetListenerCallbackRouter|null = null; private listenerIds_: number[]|null = null; @@ -654,14 +616,7 @@ * pulsing background animation */ private getAnimationUrl_(): string { - if (this.isJellyEnabled_) { - return PULSE_ANIMATION_URL_JELLY; - } - - // TODO(b/279623883): Clean up dark mode logic and duplicate assets after - // Jelly is launched. - return this.isDarkModeActive_ ? PULSE_ANIMATION_URL_DARK : - PULSE_ANIMATION_URL_LIGHT; + return PULSE_ANIMATION_URL; } /**
diff --git a/chrome/browser/resources/nearby_share/shared/BUILD.gn b/chrome/browser/resources/nearby_share/shared/BUILD.gn index 1cccbb6b..e356f80d 100644 --- a/chrome/browser/resources/nearby_share/shared/BUILD.gn +++ b/chrome/browser/resources/nearby_share/shared/BUILD.gn
@@ -67,8 +67,6 @@ input_files_base_dir = rebase_path(".", "//") input_files = [ "nearby_share_progress_bar.json", - "nearby_share_pulse_animation_dark.json", - "nearby_share_pulse_animation_light.json", - "nearby_share_pulse_animation_jelly.json", + "nearby_share_pulse_animation.json", ] }
diff --git a/chrome/browser/resources/nearby_share/shared/nearby_share_pulse_animation_jelly.json b/chrome/browser/resources/nearby_share/shared/nearby_share_pulse_animation.json similarity index 100% rename from chrome/browser/resources/nearby_share/shared/nearby_share_pulse_animation_jelly.json rename to chrome/browser/resources/nearby_share/shared/nearby_share_pulse_animation.json
diff --git a/chrome/browser/resources/nearby_share/shared/nearby_share_pulse_animation_dark.json b/chrome/browser/resources/nearby_share/shared/nearby_share_pulse_animation_dark.json deleted file mode 100644 index 77c1f76..0000000 --- a/chrome/browser/resources/nearby_share/shared/nearby_share_pulse_animation_dark.json +++ /dev/null
@@ -1 +0,0 @@ -{"v":"5.7.4","fr":60,"ip":0,"op":189,"w":783,"h":257,"nm":"ripple","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Layer 2 Outlines","sr":1,"ks":{"o":{"a":0,"k":10,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[391.562,256.875,0],"ix":2,"l":2},"a":{"a":0,"k":[64,64,0],"ix":1,"l":2},"s":{"a":0,"k":[303,303,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[13.254,0],[0,-13.255],[0,0],[0,0]],"o":[[-13.255,0],[0,0],[0,0],[0,-13.255]],"v":[[0,-12],[-24,12],[2.187,12],[24,12]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.541176470588,0.705882352941,0.972549019608,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":[63.999,52],"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":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1440,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Layer 1 Outlines 3","sr":1,"ks":{"o":{"a":0,"k":10,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[391.562,256.875,0],"ix":2,"l":2},"a":{"a":0,"k":[64,64,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.4,0.4,0.4],"y":[1,1,1]},"o":{"x":[0.001,0.001,0.001],"y":[0,0,0]},"t":58,"s":[113,113,100]},{"t":189,"s":[352,352,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[34.518,0],[0,-34.518]],"o":[[0,-34.518],[-34.519,0],[0,0]],"v":[[62.5,31.25],[0,-31.25],[-62.5,31.25]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.541176470588,0.705882352941,0.972549019608,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.001],"y":[0]},"t":58,"s":[3]},{"t":189,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[64,32.75],"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":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":59,"op":1496,"st":56,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Layer 1 Outlines 2","sr":1,"ks":{"o":{"a":0,"k":10,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[391.562,256.875,0],"ix":2,"l":2},"a":{"a":0,"k":[64,64,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.4,0.4,0.4],"y":[1,1,1]},"o":{"x":[0.001,0.001,0.001],"y":[0,0,0]},"t":30,"s":[113,113,100]},{"t":161,"s":[352,352,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[34.518,0],[0,-34.518]],"o":[[0,-34.518],[-34.519,0],[0,0]],"v":[[62.5,31.25],[0,-31.25],[-62.5,31.25]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.541176470588,0.705882352941,0.972549019608,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.001],"y":[0]},"t":30,"s":[3]},{"t":161,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[64,32.75],"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":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":31,"op":1468,"st":28,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Layer 1 Outlines","sr":1,"ks":{"o":{"a":0,"k":10,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[391.562,256.875,0],"ix":2,"l":2},"a":{"a":0,"k":[64,64,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.4,0.4,0.4],"y":[1,1,1]},"o":{"x":[0.001,0.001,0.001],"y":[0,0,0]},"t":2,"s":[113,113,100]},{"t":133,"s":[352,352,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[34.518,0],[0,-34.518]],"o":[[0,-34.518],[-34.519,0],[0,0]],"v":[[62.5,31.25],[0,-31.25],[-62.5,31.25]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.541176470588,0.705882352941,0.972549019608,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.001],"y":[0]},"t":2,"s":[3]},{"t":133,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[64,32.75],"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":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":3,"op":1440,"st":0,"bm":0}],"markers":[]} \ No newline at end of file
diff --git a/chrome/browser/resources/nearby_share/shared/nearby_share_pulse_animation_light.json b/chrome/browser/resources/nearby_share/shared/nearby_share_pulse_animation_light.json deleted file mode 100644 index 0a2d4c1..0000000 --- a/chrome/browser/resources/nearby_share/shared/nearby_share_pulse_animation_light.json +++ /dev/null
@@ -1 +0,0 @@ -{"v":"5.6.4","fr":60,"ip":0,"op":189,"w":783,"h":257,"nm":"ripple","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Layer 2 Outlines","sr":1,"ks":{"o":{"a":0,"k":10,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[391.562,256.875,0],"ix":2},"a":{"a":0,"k":[64,64,0],"ix":1},"s":{"a":0,"k":[303,303,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[13.254,0],[0,-13.255],[0,0],[0,0]],"o":[[-13.255,0],[0,0],[0,0],[0,-13.255]],"v":[[0,-12],[-24,12],[2.187,12],[24,12]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.258999992819,0.522000002394,0.957000014361,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":[63.999,52],"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":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1440,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Layer 1 Outlines 3","sr":1,"ks":{"o":{"a":0,"k":10,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[391.562,256.875,0],"ix":2},"a":{"a":0,"k":[64,64,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.4,0.4,0.4],"y":[1,1,1]},"o":{"x":[0.001,0.001,0.001],"y":[0,0,0]},"t":58,"s":[113,113,100]},{"t":189,"s":[352,352,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[34.518,0],[0,-34.518]],"o":[[0,-34.518],[-34.519,0],[0,0]],"v":[[62.5,31.25],[0,-31.25],[-62.5,31.25]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.258999992819,0.522000002394,0.957000014361,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.001],"y":[0]},"t":58,"s":[3]},{"t":189,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[64,32.75],"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":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":59,"op":1496,"st":56,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Layer 1 Outlines 2","sr":1,"ks":{"o":{"a":0,"k":10,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[391.562,256.875,0],"ix":2},"a":{"a":0,"k":[64,64,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.4,0.4,0.4],"y":[1,1,1]},"o":{"x":[0.001,0.001,0.001],"y":[0,0,0]},"t":30,"s":[113,113,100]},{"t":161,"s":[352,352,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[34.518,0],[0,-34.518]],"o":[[0,-34.518],[-34.519,0],[0,0]],"v":[[62.5,31.25],[0,-31.25],[-62.5,31.25]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.258999992819,0.522000002394,0.957000014361,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.001],"y":[0]},"t":30,"s":[3]},{"t":161,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[64,32.75],"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":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":31,"op":1468,"st":28,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Layer 1 Outlines","sr":1,"ks":{"o":{"a":0,"k":10,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[391.562,256.875,0],"ix":2},"a":{"a":0,"k":[64,64,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.4,0.4,0.4],"y":[1,1,1]},"o":{"x":[0.001,0.001,0.001],"y":[0,0,0]},"t":2,"s":[113,113,100]},{"t":133,"s":[352,352,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[34.518,0],[0,-34.518]],"o":[[0,-34.518],[-34.519,0],[0,0]],"v":[[62.5,31.25],[0,-31.25],[-62.5,31.25]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.258999992819,0.522000002394,0.957000014361,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.001],"y":[0]},"t":2,"s":[3]},{"t":133,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[64,32.75],"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":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":3,"op":1440,"st":0,"bm":0}],"markers":[]} \ No newline at end of file
diff --git a/chrome/browser/resources/privacy_sandbox/internals/content_setting_pattern_source.ts b/chrome/browser/resources/privacy_sandbox/internals/content_setting_pattern_source.ts index 1962760..730d8b1 100644 --- a/chrome/browser/resources/privacy_sandbox/internals/content_setting_pattern_source.ts +++ b/chrome/browser/resources/privacy_sandbox/internals/content_setting_pattern_source.ts
@@ -11,7 +11,7 @@ import {getTemplate} from './content_setting_pattern_source.html.js'; import {ContentSetting, ContentSettingPatternSource, SessionModel} from './content_settings.mojom-webui.js'; -import {PageHandlerRemote} from './privacy_sandbox_internals.mojom-webui.js'; +import {PageHandlerInterface} from './privacy_sandbox_internals.mojom-webui.js'; import {defaultLogicalFn, LogicalFn} from './value_display.js'; function contentSettingLogicalValue(v: Value) { @@ -40,7 +40,7 @@ return el; } -class ContentSettingPatternSourceElement extends CustomElement { +export class ContentSettingPatternSourceElement extends CustomElement { static observedAttributes = ['collapsed']; static override get template() { @@ -90,23 +90,25 @@ } } - configure(pageHandler: PageHandlerRemote, cs: ContentSettingPatternSource) { - pageHandler.contentSettingsPatternToString(cs.primaryPattern) - .then( - (obj) => { - this.setField('primary-pattern', obj.s); - }, - (err) => { - console.error(err); - }); - pageHandler.contentSettingsPatternToString(cs.secondaryPattern) - .then( - (obj) => { - this.setField('secondary-pattern', obj.s); - }, - (err) => { - console.error(err); - }); + async configure( + pageHandler: PageHandlerInterface, cs: ContentSettingPatternSource) { + try { + this.setField( + 'primary-pattern', + (await pageHandler.contentSettingsPatternToString(cs.primaryPattern)) + .s); + } catch (e) { + console.error('Error parsing primary pattern ', e); + } + try { + this.setField( + 'secondary-pattern', + (await pageHandler.contentSettingsPatternToString( + cs.secondaryPattern)) + .s); + } catch (e) { + console.error('Error parsing secondary pattern ', e); + } this.setFieldValue('value', cs.settingValue, contentSettingLogicalValue); this.setField('source', cs.source);
diff --git a/chrome/browser/resources/side_panel/customize_chrome/icons/BUILD.gn b/chrome/browser/resources/side_panel/customize_chrome/icons/BUILD.gn index 714b964..eb7678bb 100644 --- a/chrome/browser/resources/side_panel/customize_chrome/icons/BUILD.gn +++ b/chrome/browser/resources/side_panel/customize_chrome/icons/BUILD.gn
@@ -13,6 +13,7 @@ "chrome_web_store.svg", "corner_new_tab_page.svg", "coupons.svg", + "delete.svg", "generated_image.svg", "gm3_corner_new_tab_page.svg", "gm3_mini_new_tab_page.svg",
diff --git a/chrome/browser/resources/side_panel/customize_chrome/icons/delete.svg b/chrome/browser/resources/side_panel/customize_chrome/icons/delete.svg new file mode 100644 index 0000000..b1ac98c --- /dev/null +++ b/chrome/browser/resources/side_panel/customize_chrome/icons/delete.svg
@@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="none" viewBox="0 0 20 20"><path fill="#1F1F1F" d="M6.5 17c-.417 0-.77-.146-1.063-.438A1.447 1.447 0 0 1 5 15.5v-10H4V4h4V3h4v1h4v1.5h-1v10c0 .417-.146.77-.438 1.063A1.446 1.446 0 0 1 13.5 17h-7Zm7-11.5h-7v10h7v-10ZM8 14h1.5V7H8v7Zm2.5 0H12V7h-1.5v7Zm-4-8.5v10-10Z"/></svg> \ No newline at end of file
diff --git a/chrome/browser/resources/side_panel/customize_chrome/wallpaper_search/wallpaper_search.html b/chrome/browser/resources/side_panel/customize_chrome/wallpaper_search/wallpaper_search.html index 5730e57..4e3e075 100644 --- a/chrome/browser/resources/side_panel/customize_chrome/wallpaper_search/wallpaper_search.html +++ b/chrome/browser/resources/side_panel/customize_chrome/wallpaper_search/wallpaper_search.html
@@ -150,6 +150,12 @@ width: 16px; } + #deleteSelectedHueButton { + --cr-icon-image: url(icons/delete.svg); + margin-inline-start: 0; + margin-inline-end: -24px; + } + #btnContainer { display: flex; justify-content: flex-end; @@ -311,6 +317,12 @@ </cr-grid> <cr-theme-hue-slider-dialog id="hueSlider" on-selected-hue-changed="onSelectedHueChanged_"> + <cr-icon-button slot="headerSuffix" id="deleteSelectedHueButton" + hidden$="[[!shouldShowDeleteSelectedHueButton_(selectedHue_)]]" + title="$i18n{hueSliderDeleteTitle}" + aria-label="$i18n{hueSliderDeleteA11yLabel}" + on-click="onSelectedHueDelete_"> + </cr-icon-button> </cr-theme-hue-slider-dialog> <div id="btnContainer"> <cr-button @@ -405,7 +417,7 @@ <cr-grid columns="3" disable-arrow-navigation> <template is="dom-repeat" id="historyRepeat" items="[[history_]]"> <div class="tile result" tabindex="0" role="button" - aria-label$="[[getHistoryTileTitle_(index)]]" + aria-label$="[[getHistoryResultAriaLabel_(index, item)]]" on-click="onHistoryImageClick_" aria-current$="[[getBackgroundCheckedStatus_(item.id, theme_)]]"> <customize-chrome-check-mark-wrapper class="image-check-mark"
diff --git a/chrome/browser/resources/side_panel/customize_chrome/wallpaper_search/wallpaper_search.ts b/chrome/browser/resources/side_panel/customize_chrome/wallpaper_search/wallpaper_search.ts index 507119e..b456ce9a 100644 --- a/chrome/browser/resources/side_panel/customize_chrome/wallpaper_search/wallpaper_search.ts +++ b/chrome/browser/resources/side_panel/customize_chrome/wallpaper_search/wallpaper_search.ts
@@ -35,7 +35,7 @@ import {CustomizeChromeAction, recordCustomizeChromeAction} from '../common.js'; import {CustomizeChromePageCallbackRouter, CustomizeChromePageHandlerInterface, Theme} from '../customize_chrome.mojom-webui.js'; import {CustomizeChromeApiProxy} from '../customize_chrome_api_proxy.js'; -import {DescriptorA, DescriptorB, DescriptorDValue, Descriptors, UserFeedback, WallpaperSearchClientCallbackRouter, WallpaperSearchHandlerInterface, WallpaperSearchResult, WallpaperSearchStatus} from '../wallpaper_search.mojom-webui.js'; +import {DescriptorA, DescriptorB, DescriptorDValue, Descriptors, ResultDescriptors, UserFeedback, WallpaperSearchClientCallbackRouter, WallpaperSearchHandlerInterface, WallpaperSearchResult, WallpaperSearchStatus} from '../wallpaper_search.mojom-webui.js'; import {WindowProxy} from '../window_proxy.js'; import {ComboboxGroup, ComboboxItem, CustomizeChromeCombobox} from './combobox/customize_chrome_combobox.js'; @@ -92,6 +92,7 @@ export interface WallpaperSearchElement { $: { customColorContainer: HTMLElement, + deleteSelectedHueButton: HTMLElement, descriptorComboboxA: CustomizeChromeCombobox, descriptorComboboxB: CustomizeChromeCombobox, descriptorComboboxC: CustomizeChromeCombobox, @@ -181,7 +182,10 @@ type: Object, observer: 'onColorDescriptorChange_', }, - selectedHue_: Number, + selectedHue_: { + type: Number, + value: null, + }, status_: { type: WallpaperSearchStatus, value: WallpaperSearchStatus.kOk, @@ -213,7 +217,7 @@ private selectedDescriptorC_: string|null; private selectedDescriptorD_: DescriptorDValue|null; private selectedFeedbackOption_: CrFeedbackOption; - private selectedHue_: number|undefined; + private selectedHue_: number|null; private status_: WallpaperSearchStatus; private theme_: Theme|undefined; @@ -405,12 +409,31 @@ } private getCustomColorCheckedStatus_(): string { - return this.selectedHue_ !== undefined ? 'true' : 'false'; + return this.selectedHue_ !== null ? 'true' : 'false'; } - private getHistoryTileTitle_(index: number): string { + private getHistoryResultAriaLabel_( + index: number, result: WallpaperSearchResult): string { + if (!result.descriptors || !result.descriptors.subject) { + return loadTimeData.getStringF( + 'wallpaperSearchHistoryResultLabelNoDescriptor', index + 1); + } else if (result.descriptors.style && result.descriptors.mood) { + return loadTimeData.getStringF( + 'wallpaperSearchHistoryResultLabelBC', index + 1, + result.descriptors.subject, result.descriptors.style, + result.descriptors.mood); + } else if (result.descriptors.style) { + return loadTimeData.getStringF( + 'wallpaperSearchHistoryResultLabelB', index + 1, + result.descriptors.subject, result.descriptors.style); + } else if (result.descriptors.mood) { + return loadTimeData.getStringF( + 'wallpaperSearchHistoryResultLabelC', index + 1, + result.descriptors.subject, result.descriptors.mood); + } return loadTimeData.getStringF( - 'wallpaperSearchHistoryTileTitle', index + 1); + 'wallpaperSearchHistoryResultLabel', index + 1, + result.descriptors.subject); } private getResultAriaLabel_(index: number): string { @@ -470,7 +493,7 @@ } private onDefaultColorClick_(e: DomRepeatEvent<string>) { - this.selectedHue_ = undefined; + this.selectedHue_ = null; this.selectedDefaultColor_ = e.model.item; this.selectedDescriptorD_ = { color: hexColorToSkColor(this.selectedDefaultColor_), @@ -520,7 +543,8 @@ private onHistoryImageClick_(e: DomRepeatEvent<WallpaperSearchResult>) { recordCustomizeChromeAction( CustomizeChromeAction.WALLPAPER_SEARCH_HISTORY_IMAGE_SELECTED); - this.wallpaperSearchHandler_.setBackgroundToHistoryImage(e.model.item.id); + this.wallpaperSearchHandler_.setBackgroundToHistoryImage( + e.model.item.id, e.model.item.descriptors ?? {}); } private onLearnMoreClick_(e: Event) { @@ -528,12 +552,19 @@ this.wallpaperSearchHandler_.openHelpArticle(); } - private async onSelectedHueChanged_() { + private onSelectedHueChanged_() { this.selectedDefaultColor_ = undefined; this.selectedHue_ = this.$.hueSlider.selectedHue; this.selectedDescriptorD_ = {hue: this.selectedHue_}; } + private onSelectedHueDelete_() { + this.selectedHue_ = null; + this.selectedDescriptorD_ = null; + this.$.hueSlider.hide(); + this.$.customColorContainer.focus(); + } + private async onSearchClick_() { if (!WindowProxy.getInstance().onLine) { this.status_ = WallpaperSearchStatus.kOffline; @@ -583,8 +614,14 @@ private async onResultClick_(e: DomRepeatEvent<WallpaperSearchResult>) { recordCustomizeChromeAction( CustomizeChromeAction.WALLPAPER_SEARCH_RESULT_IMAGE_SELECTED); + const descriptors: ResultDescriptors = { + subject: this.selectedDescriptorA_!, + style: this.selectedDescriptorB_ ?? undefined, + mood: this.selectedDescriptorC_ ?? undefined, + color: this.selectedDescriptorD_ ?? undefined, + }; this.wallpaperSearchHandler_.setBackgroundToWallpaperSearchResult( - e.model.item.id, WindowProxy.getInstance().now()); + e.model.item.id, WindowProxy.getInstance().now(), descriptors); } private onStatusChange_() { @@ -595,6 +632,10 @@ } } + private shouldShowDeleteSelectedHueButton_() { + return this.selectedHue_ !== null; + } + private shouldShowFeedbackButtons_() { return !this.loading_ && this.results_.length > 0; }
diff --git a/chrome/browser/search/background/wallpaper_search/wallpaper_search_background_manager.cc b/chrome/browser/search/background/wallpaper_search/wallpaper_search_background_manager.cc index 6381c0d..6c27b89 100644 --- a/chrome/browser/search/background/wallpaper_search/wallpaper_search_background_manager.cc +++ b/chrome/browser/search/background/wallpaper_search/wallpaper_search_background_manager.cc
@@ -30,6 +30,9 @@ namespace { const char kWallpaperSearchHistoryId[] = "id"; +const char kWallpaperSearchHistoryMood[] = "mood"; +const char kWallpaperSearchHistoryStyle[] = "style"; +const char kWallpaperSearchHistorySubject[] = "subject"; void WriteFileToPath(const std::string& data, const base::FilePath& path) { base::WriteFile(path, base::as_bytes(base::make_span(data))); @@ -47,12 +50,29 @@ absl::optional<HistoryEntry> GetHistoryEntryFromPrefValue( const base::Value& pref_value) { if (pref_value.is_dict()) { + const base::Value::Dict& pref_dict = pref_value.GetDict(); const std::string* id_string = - pref_value.GetDict().FindString(kWallpaperSearchHistoryId); + pref_dict.FindString(kWallpaperSearchHistoryId); if (id_string) { absl::optional<base::Token> id = base::Token::FromString(*id_string); if (id.has_value()) { - return HistoryEntry(*id); + HistoryEntry history_entry = HistoryEntry(*id); + const std::string* subject_string = + pref_dict.FindString(kWallpaperSearchHistorySubject); + if (subject_string) { + history_entry.subject = *subject_string; + } + const std::string* style_string = + pref_dict.FindString(kWallpaperSearchHistoryStyle); + if (style_string) { + history_entry.style = *style_string; + } + const std::string* mood_string = + pref_dict.FindString(kWallpaperSearchHistoryMood); + if (mood_string) { + history_entry.mood = *mood_string; + } + return history_entry; } } } @@ -60,8 +80,19 @@ } base::Value::Dict GetHistoryEntryDict(const HistoryEntry& history_entry) { - return base::Value::Dict().Set(kWallpaperSearchHistoryId, - history_entry.id.ToString()); + base::Value::Dict history_entry_dict = base::Value::Dict().Set( + kWallpaperSearchHistoryId, history_entry.id.ToString()); + if (history_entry.subject) { + history_entry_dict.Set(kWallpaperSearchHistorySubject, + *history_entry.subject); + } + if (history_entry.style) { + history_entry_dict.Set(kWallpaperSearchHistoryStyle, *history_entry.style); + } + if (history_entry.mood) { + history_entry_dict.Set(kWallpaperSearchHistoryMood, *history_entry.mood); + } + return history_entry_dict; } } // namespace @@ -123,14 +154,14 @@ WallpaperSearchBackgroundManager::~WallpaperSearchBackgroundManager() = default; -std::vector<base::Token> WallpaperSearchBackgroundManager::GetHistory() { +std::vector<HistoryEntry> WallpaperSearchBackgroundManager::GetHistory() { auto& history_list = pref_service_->GetList(prefs::kNtpWallpaperSearchHistory); - std::vector<base::Token> history; + std::vector<HistoryEntry> history; for (auto& entry : history_list) { const auto entry_obj = GetHistoryEntryFromPrefValue(entry); if (entry_obj) { - history.push_back(entry_obj->id); + history.push_back(*entry_obj); } } return history; @@ -195,10 +226,10 @@ const HistoryEntry& history_entry) { absl::optional<CustomBackground> current_theme = ntp_custom_background_service_->GetCustomBackground(); - std::string entry_id_str = history_entry.id.ToString(); if (current_theme.has_value() && current_theme->local_background_id.has_value() && - current_theme->local_background_id->ToString() == entry_id_str) { + current_theme->local_background_id->ToString() == + history_entry.id.ToString()) { const base::Value::List& current_history = pref_service_->GetList(prefs::kNtpWallpaperSearchHistory); base::Value::List new_history = @@ -209,14 +240,13 @@ for (const auto& value : current_history) { const auto value_obj = GetHistoryEntryFromPrefValue(value); if (value_obj) { - const std::string id_str = value_obj->id.ToString(); - if (id_str != entry_id_str) { + if (value_obj.value() != history_entry) { if (new_history.size() >= 6) { // Delete values that will no longer be in the history. - DeleteWallpaperSearchImage(id_str, profile_->GetPath()); + DeleteWallpaperSearchImage(value_obj->id.ToString(), + profile_->GetPath()); } else { - new_history.Append( - base::Value::Dict().Set(kWallpaperSearchHistoryId, id_str)); + new_history.Append(GetHistoryEntryDict(value_obj.value())); } } }
diff --git a/chrome/browser/search/background/wallpaper_search/wallpaper_search_background_manager.h b/chrome/browser/search/background/wallpaper_search/wallpaper_search_background_manager.h index 7767cea..2f43833 100644 --- a/chrome/browser/search/background/wallpaper_search/wallpaper_search_background_manager.h +++ b/chrome/browser/search/background/wallpaper_search/wallpaper_search_background_manager.h
@@ -30,7 +30,7 @@ virtual ~WallpaperSearchBackgroundManager(); // Gets the current history list. - virtual std::vector<base::Token> GetHistory(); + virtual std::vector<HistoryEntry> GetHistory(); // Sets a history image to the NTP background and sets matching theme color. virtual void SelectHistoryImage(const base::Token& id,
diff --git a/chrome/browser/search/background/wallpaper_search/wallpaper_search_background_manager_unittest.cc b/chrome/browser/search/background/wallpaper_search/wallpaper_search_background_manager_unittest.cc index d2a7b5a2..b3a6216e8 100644 --- a/chrome/browser/search/background/wallpaper_search/wallpaper_search_background_manager_unittest.cc +++ b/chrome/browser/search/background/wallpaper_search/wallpaper_search_background_manager_unittest.cc
@@ -28,6 +28,9 @@ namespace { const char kWallpaperSearchHistoryId[] = "id"; +const char kWallpaperSearchHistoryMood[] = "mood"; +const char kWallpaperSearchHistoryStyle[] = "style"; +const char kWallpaperSearchHistorySubject[] = "subject"; using testing::Return; using testing::SaveArg; @@ -112,17 +115,25 @@ TEST_F(WallpaperSearchBackgroundManagerTest, GetHistory) { // Fill history pref. base::Value::List history = base::Value::List(); - std::vector<base::Token> tokens; + std::vector<HistoryEntry> history_entries; for (int i = 0; i < 3; i++) { base::Token temp_token = base::Token::CreateRandom(); - tokens.push_back(temp_token); - history.Append(base::Value::Dict().Set(kWallpaperSearchHistoryId, - temp_token.ToString())); + HistoryEntry entry = HistoryEntry(temp_token); + entry.subject = "foo" + base::NumberToString(i); + entry.mood = "bar" + base::NumberToString(i); + entry.style = "foobar" + base::NumberToString(i); + history_entries.push_back(entry); + history.Append( + base::Value::Dict() + .Set(kWallpaperSearchHistoryId, temp_token.ToString()) + .Set(kWallpaperSearchHistorySubject, entry.subject.value()) + .Set(kWallpaperSearchHistoryMood, entry.mood.value()) + .Set(kWallpaperSearchHistoryStyle, entry.style.value())); } pref_service().SetList(prefs::kNtpWallpaperSearchHistory, std::move(history)); auto result = wallpaper_search_background_manager().GetHistory(); - EXPECT_EQ(result, tokens); + EXPECT_EQ(result, history_entries); } TEST_F(WallpaperSearchBackgroundManagerTest, SetHistoryImage) { @@ -235,18 +246,31 @@ ON_CALL(mock_ntp_custom_background_service(), GetCustomBackground()) .WillByDefault(Return(absl::make_optional(custom_background))); - wallpaper_search_background_manager().SaveCurrentBackgroundToHistory( - HistoryEntry(token)); + HistoryEntry entry = HistoryEntry(token); + entry.subject = "foo"; + entry.mood = "bar"; + entry.style = "foobar"; + wallpaper_search_background_manager().SaveCurrentBackgroundToHistory(entry); task_environment().RunUntilIdle(); const base::Value::List& history = pref_service().GetList(prefs::kNtpWallpaperSearchHistory); ASSERT_EQ(history.size(), 1u); ASSERT_TRUE(history.front().is_dict()); - const base::Value* id = - history.front().GetDict().Find(kWallpaperSearchHistoryId); + const base::Value::Dict& history_dict = history.front().GetDict(); + const base::Value* id = history_dict.Find(kWallpaperSearchHistoryId); + const base::Value* subject = + history_dict.Find(kWallpaperSearchHistorySubject); + const base::Value* mood = history_dict.Find(kWallpaperSearchHistoryMood); + const base::Value* style = history_dict.Find(kWallpaperSearchHistoryStyle); ASSERT_TRUE(id->is_string()); + ASSERT_TRUE(subject->is_string()); + ASSERT_TRUE(mood->is_string()); + ASSERT_TRUE(style->is_string()); EXPECT_EQ(token.ToString(), id->GetString()); + EXPECT_EQ(entry.subject, subject->GetString()); + EXPECT_EQ(entry.mood, mood->GetString()); + EXPECT_EQ(entry.style, style->GetString()); } // Test that the last history entry is deleted when a new entry is added, @@ -272,8 +296,10 @@ ON_CALL(mock_ntp_custom_background_service(), GetCustomBackground()) .WillByDefault(Return(absl::make_optional(custom_background))); - wallpaper_search_background_manager().SaveCurrentBackgroundToHistory( - HistoryEntry(theme_token)); + HistoryEntry entry = HistoryEntry(theme_token); + entry.subject = "foo"; + entry.mood = "bar"; + wallpaper_search_background_manager().SaveCurrentBackgroundToHistory(entry); task_environment().RunUntilIdle(); // Check that the history is still 6 long and the first entry is the new one. @@ -281,10 +307,19 @@ pref_service().GetList(prefs::kNtpWallpaperSearchHistory); ASSERT_EQ(new_history.size(), 6u); ASSERT_TRUE(new_history.front().is_dict()); - const base::Value* id = - new_history.front().GetDict().Find(kWallpaperSearchHistoryId); + const base::Value::Dict& history_dict = new_history.front().GetDict(); + const base::Value* id = history_dict.Find(kWallpaperSearchHistoryId); + const base::Value* subject = + history_dict.Find(kWallpaperSearchHistorySubject); + const base::Value* mood = history_dict.Find(kWallpaperSearchHistoryMood); + const base::Value* style = history_dict.Find(kWallpaperSearchHistoryStyle); ASSERT_TRUE(id->is_string()); + ASSERT_TRUE(subject->is_string()); + ASSERT_TRUE(mood->is_string()); + EXPECT_EQ(style, nullptr); EXPECT_EQ(theme_token.ToString(), id->GetString()); + EXPECT_EQ(entry.subject, subject->GetString()); + EXPECT_EQ(entry.mood, mood->GetString()); // Check that the file for deleted history entry has been deleted and the // rest are still there. @@ -304,8 +339,10 @@ for (int i = 0; i < 6; ++i) { base::Token temp_token = base::Token::CreateRandom(); tokens.push_back(temp_token); - history.Append(base::Value::Dict().Set(kWallpaperSearchHistoryId, - temp_token.ToString())); + history.Append(base::Value::Dict() + .Set(kWallpaperSearchHistoryId, temp_token.ToString()) + .Set(kWallpaperSearchHistorySubject, + "foo" + base::NumberToString(i))); base::WriteFile(GetFilePathForBackground(temp_token), "hi"); } pref_service().SetList(prefs::kNtpWallpaperSearchHistory, std::move(history)); @@ -317,8 +354,10 @@ ON_CALL(mock_ntp_custom_background_service(), GetCustomBackground()) .WillByDefault(Return(absl::make_optional(custom_background))); + HistoryEntry theme_entry = HistoryEntry(theme_token); + theme_entry.subject = "foo2"; wallpaper_search_background_manager().SaveCurrentBackgroundToHistory( - HistoryEntry(theme_token)); + theme_entry); task_environment().RunUntilIdle(); // Check that the history is still 6 long and in the correct order. @@ -328,20 +367,40 @@ pref_service().GetList(prefs::kNtpWallpaperSearchHistory); ASSERT_EQ(new_history.size(), 6u); ASSERT_TRUE(new_history.front().is_dict()); + const base::Value::Dict& first_history_dict = new_history.front().GetDict(); const base::Value* first_id = - new_history.front().GetDict().Find(kWallpaperSearchHistoryId); + first_history_dict.Find(kWallpaperSearchHistoryId); + const base::Value* first_subject = + first_history_dict.Find(kWallpaperSearchHistorySubject); + const base::Value* first_mood = + first_history_dict.Find(kWallpaperSearchHistoryMood); + const base::Value* first_style = + first_history_dict.Find(kWallpaperSearchHistoryStyle); ASSERT_TRUE(first_id->is_string()); + ASSERT_TRUE(first_subject->is_string()); + EXPECT_EQ(first_mood, nullptr); + EXPECT_EQ(first_style, nullptr); EXPECT_EQ(theme_token.ToString(), first_id->GetString()); + EXPECT_EQ(theme_entry.subject, first_subject->GetString()); bool before_entry_pos = true; for (int i = 1; i < 6; ++i) { // If we haven't hit where |theme_token| used to be in the history, // the entry we are looking at will be one index back in |tokens| vs // |new_history|. ASSERT_TRUE(new_history[i].is_dict()); - const base::Value* id = - new_history[i].GetDict().Find(kWallpaperSearchHistoryId); + const base::Value::Dict& history_dict = new_history[i].GetDict(); + const base::Value* id = history_dict.Find(kWallpaperSearchHistoryId); + const base::Value* subject = + history_dict.Find(kWallpaperSearchHistorySubject); + const base::Value* mood = history_dict.Find(kWallpaperSearchHistoryMood); + const base::Value* style = history_dict.Find(kWallpaperSearchHistoryStyle); ASSERT_TRUE(id->is_string()); + ASSERT_TRUE(subject->is_string()); + EXPECT_EQ(mood, nullptr); + EXPECT_EQ(style, nullptr); EXPECT_EQ(id->GetString(), tokens[before_entry_pos ? i - 1 : i].ToString()); + EXPECT_EQ("foo" + base::NumberToString(before_entry_pos ? i - 1 : i), + subject->GetString()); if (tokens[i].ToString() == theme_token.ToString()) { before_entry_pos = false;
diff --git a/chrome/browser/search/background/wallpaper_search/wallpaper_search_data.cc b/chrome/browser/search/background/wallpaper_search/wallpaper_search_data.cc index 4eb5e8e..8651f57 100644 --- a/chrome/browser/search/background/wallpaper_search/wallpaper_search_data.cc +++ b/chrome/browser/search/background/wallpaper_search/wallpaper_search_data.cc
@@ -6,6 +6,7 @@ #include "base/token.h" +HistoryEntry::HistoryEntry() = default; HistoryEntry::HistoryEntry(const base::Token& id) : id(id) {} HistoryEntry::HistoryEntry(const HistoryEntry&) = default; HistoryEntry::HistoryEntry(HistoryEntry&&) = default; @@ -13,3 +14,8 @@ HistoryEntry& HistoryEntry::operator=(const HistoryEntry&) = default; HistoryEntry& HistoryEntry::operator=(HistoryEntry&&) = default; +bool HistoryEntry::operator==(const HistoryEntry& rhs) const { + return this->id.ToString() == rhs.id.ToString() && + this->subject == rhs.subject && this->style == rhs.style && + this->mood == rhs.mood; +}
diff --git a/chrome/browser/search/background/wallpaper_search/wallpaper_search_data.h b/chrome/browser/search/background/wallpaper_search/wallpaper_search_data.h index 95d0f41..433f4b2 100644 --- a/chrome/browser/search/background/wallpaper_search/wallpaper_search_data.h +++ b/chrome/browser/search/background/wallpaper_search/wallpaper_search_data.h
@@ -11,7 +11,7 @@ // Represents a history entry in wallpaper search. struct HistoryEntry { - HistoryEntry() = default; + HistoryEntry(); explicit HistoryEntry(const base::Token& id); HistoryEntry(const HistoryEntry&); HistoryEntry(HistoryEntry&&); @@ -19,8 +19,12 @@ HistoryEntry& operator=(const HistoryEntry&); HistoryEntry& operator=(HistoryEntry&&); + bool operator==(const HistoryEntry& rhs) const; base::Token id; + absl::optional<std::string> subject; + absl::optional<std::string> style; + absl::optional<std::string> mood; }; #endif // CHROME_BROWSER_SEARCH_BACKGROUND_WALLPAPER_SEARCH_WALLPAPER_SEARCH_DATA_H_
diff --git a/chrome/browser/tpcd/experiment/BUILD.gn b/chrome/browser/tpcd/experiment/BUILD.gn index 9edb87c..4d60186b3 100644 --- a/chrome/browser/tpcd/experiment/BUILD.gn +++ b/chrome/browser/tpcd/experiment/BUILD.gn
@@ -2,6 +2,8 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("//build/config/chromeos/ui_mode.gni") + source_set("unit_tests") { testonly = true sources = [ @@ -20,4 +22,8 @@ "//content/test:test_support", "//testing/gtest", ] + + if (is_chromeos_ash) { + deps += [ "//chromeos/ash/components/browser_context_helper" ] + } }
diff --git a/chrome/browser/tpcd/experiment/experiment_manager_impl.cc b/chrome/browser/tpcd/experiment/experiment_manager_impl.cc index 471a555..f6ad212 100644 --- a/chrome/browser/tpcd/experiment/experiment_manager_impl.cc +++ b/chrome/browser/tpcd/experiment/experiment_manager_impl.cc
@@ -16,6 +16,8 @@ #include "base/no_destructor.h" #include "base/sequence_checker.h" #include "base/task/single_thread_task_runner.h" +#include "build/buildflag.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/metrics/chrome_metrics_service_accessor.h" #include "chrome/browser/profiles/profile.h" @@ -28,6 +30,10 @@ #include "content/public/common/content_features.h" #include "third_party/abseil-cpp/absl/types/optional.h" +#if BUILDFLAG(IS_CHROMEOS_ASH) +#include "chrome/browser/profiles/profile_types_ash.h" +#endif // BUILDFLAG(IS_CHROMEOS_ASH) + namespace tpcd::experiment { namespace { @@ -58,6 +64,14 @@ return nullptr; } +#if BUILDFLAG(IS_CHROMEOS_ASH) + // Ash internal profile should not be accounted for the experiment + // eligibility, and therefore should not create the experiment manager. + if (!IsUserProfile(profile)) { + return nullptr; + } +#endif // BUILDFLAG(IS_CHROMEOS_ASH) + if (!features::kCookieDeprecationFacilitatedTestingEnableOTRProfiles.Get() && (profile->IsOffTheRecord() || profile->IsGuestSession())) { return nullptr;
diff --git a/chrome/browser/tpcd/experiment/experiment_manager_impl_unittest.cc b/chrome/browser/tpcd/experiment/experiment_manager_impl_unittest.cc index 879cc128..9e42f7e 100644 --- a/chrome/browser/tpcd/experiment/experiment_manager_impl_unittest.cc +++ b/chrome/browser/tpcd/experiment/experiment_manager_impl_unittest.cc
@@ -7,18 +7,25 @@ #include "base/test/bind.h" #include "base/test/mock_callback.h" #include "base/test/scoped_feature_list.h" -#include "base/test/task_environment.h" #include "base/time/time.h" +#include "build/buildflag.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/tpcd/experiment/tpcd_experiment_features.h" #include "chrome/browser/tpcd/experiment/tpcd_pref_names.h" #include "chrome/browser/tpcd/experiment/tpcd_utils.h" #include "chrome/test/base/scoped_testing_local_state.h" #include "chrome/test/base/testing_browser_process.h" +#include "chrome/test/base/testing_profile_manager.h" #include "components/prefs/testing_pref_service.h" #include "content/public/common/content_features.h" +#include "content/public/test/browser_task_environment.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +#if BUILDFLAG(IS_CHROMEOS_ASH) +#include "chromeos/ash/components/browser_context_helper/browser_context_types.h" +#endif // BUILDFLAG(IS_CHROMEOS_ASH) + namespace tpcd::experiment { namespace { @@ -38,12 +45,11 @@ class ExperimentManagerImplTestBase : public testing::Test { public: - ExperimentManagerImplTestBase() - : local_state_(TestingBrowserProcess::GetGlobal()) {} - - PrefService& prefs() { return *local_state_.Get(); } + PrefService& prefs() { return *profile_manager_.local_state()->Get(); } void SetUp() override { + ASSERT_TRUE(profile_manager_.SetUp()); + prefs().SetInteger( prefs::kTPCDExperimentClientState, static_cast<int>(utils::ExperimentState::kUnknownEligibility)); @@ -51,9 +57,9 @@ } protected: - base::test::TaskEnvironment task_environment_{ + content::BrowserTaskEnvironment task_environment_{ base::test::TaskEnvironment::TimeSource::MOCK_TIME}; - ScopedTestingLocalState local_state_; + TestingProfileManager profile_manager_{TestingBrowserProcess::GetGlobal()}; base::MockCallback<ExperimentManager::EligibilityDecisionCallback> mock_callback_; base::TimeDelta delay_time_; @@ -317,6 +323,14 @@ EXPECT_EQ(TestingExperimentManagerImpl().IsClientEligible(), absl::nullopt); } +#if BUILDFLAG(IS_CHROMEOS_ASH) +TEST_F(ExperimentManagerImplTest, AshInternalProfile_NotCreated) { + auto* internal_profile = + profile_manager_.CreateTestingProfile(ash::kSigninBrowserContextBaseName); + EXPECT_FALSE(ExperimentManagerImpl::GetForProfile(internal_profile)); +} +#endif // BUILDFLAG(IS_CHROMEOS_ASH) + // The parameter indicates whether to disable 3pcs. class ExperimentManagerImplSyntheticTrialTest : public ExperimentManagerImplTestBase,
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index 11553e8..d9ee733 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -5678,6 +5678,12 @@ "views/performance_controls/memory_saver_chip_view.h", "views/performance_controls/memory_saver_resource_view.cc", "views/performance_controls/memory_saver_resource_view.h", + "views/permissions/chip/permission_dashboard_controller.cc", + "views/permissions/chip/permission_dashboard_controller.h", + "views/permissions/chip/permission_dashboard_layout.cc", + "views/permissions/chip/permission_dashboard_layout.h", + "views/permissions/chip/permission_dashboard_view.cc", + "views/permissions/chip/permission_dashboard_view.h", "views/permissions/chip_controller.cc", "views/permissions/chip_controller.h", "views/permissions/chooser_bubble_ui.cc",
diff --git a/chrome/browser/ui/android/webid/account_selection_view_android.cc b/chrome/browser/ui/android/webid/account_selection_view_android.cc index 66584597..3dfd2c3b 100644 --- a/chrome/browser/ui/android/webid/account_selection_view_android.cc +++ b/chrome/browser/ui/android/webid/account_selection_view_android.cc
@@ -259,7 +259,6 @@ content::WebContents* AccountSelectionViewAndroid::ShowModalDialog( const GURL& url) { - // TODO(crbug.com/1510449): Connect dismiss callback to closing of CCT. if (!MaybeCreateJavaObject()) { // The Java object is tied to the bottomsheet availability, so if we hadn't // created one and the bottomsheet is not available then the CCT will not be
diff --git a/chrome/browser/ui/side_panel/companion/companion_utils.cc b/chrome/browser/ui/side_panel/companion/companion_utils.cc index 9b1924f..5b3a314 100644 --- a/chrome/browser/ui/side_panel/companion/companion_utils.cc +++ b/chrome/browser/ui/side_panel/companion/companion_utils.cc
@@ -5,6 +5,7 @@ #include "chrome/browser/ui/side_panel/companion/companion_utils.h" #include "base/metrics/histogram_functions.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/companion/core/constants.h" #include "chrome/browser/companion/core/features.h" #include "chrome/browser/companion/core/utils.h" @@ -21,7 +22,7 @@ namespace companion { bool IsCompanionFeatureEnabled() { -#if BUILDFLAG(GOOGLE_CHROME_BRANDING) +#if BUILDFLAG(GOOGLE_CHROME_BRANDING) && !BUILDFLAG(IS_CHROMEOS) if (!base::FeatureList::IsEnabled(lens::features::kLensStandalone)) { return false; } @@ -33,7 +34,7 @@ features::internal::kCompanionEnabledByObservingExpsNavigations); #else return false; -#endif // BUILDFLAG(GOOGLE_CHROME_BRANDING) +#endif // BUILDFLAG(GOOGLE_CHROME_BRANDING) && !BUILDFLAG(IS_CHROMEOS) } bool IsCompanionAvailableForCurrentActiveTab(const Browser* browser) {
diff --git a/chrome/browser/ui/views/bubble_anchor_util_views.cc b/chrome/browser/ui/views/bubble_anchor_util_views.cc index 84a4399..7932fe5 100644 --- a/chrome/browser/ui/views/bubble_anchor_util_views.cc +++ b/chrome/browser/ui/views/bubble_anchor_util_views.cc
@@ -11,7 +11,7 @@ #include "chrome/browser/ui/views/frame/picture_in_picture_browser_frame_view.h" #include "chrome/browser/ui/views/location_bar/location_bar_view.h" #include "chrome/browser/ui/views/toolbar/toolbar_view.h" -#include "components/permissions/features.h" +#include "components/content_settings/core/common/features.h" #include "ui/views/bubble/bubble_border.h" // This file contains the bubble_anchor_util implementation for a Views @@ -22,21 +22,37 @@ AnchorConfiguration GetPageInfoAnchorConfiguration(Browser* browser, Anchor anchor) { BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser); - if (anchor == kLocationBar && - browser_view->GetLocationBarView()->chip_controller() && - browser_view->GetLocationBarView() - ->chip_controller() - ->chip() - ->GetVisible()) { - return {browser_view->GetLocationBarView()->chip_controller()->chip(), - browser_view->GetLocationBarView()->chip_controller()->chip(), - views::BubbleBorder::TOP_LEFT}; + auto* location_bar_view = browser_view->GetLocationBarView(); + + if (base::FeatureList::IsEnabled( + content_settings::features::kLeftHandSideActivityIndicators)) { + auto* permission_dashboard_view = + location_bar_view->permission_dashboard_controller() + ->permission_dashboard_view(); + + if (anchor == kLocationBar && permission_dashboard_view->GetVisible()) { + if (permission_dashboard_view->GetIndicatorChip()->GetVisible()) { + return {permission_dashboard_view->GetIndicatorChip(), + permission_dashboard_view->GetIndicatorChip(), + views::BubbleBorder::TOP_LEFT}; + } + + return {permission_dashboard_view->GetRequestChip(), + permission_dashboard_view->GetRequestChip(), + views::BubbleBorder::TOP_LEFT}; + } + } else { + auto* request_chip_view = location_bar_view->GetChipController()->chip(); + if (anchor == kLocationBar && request_chip_view->GetVisible()) { + return {request_chip_view, request_chip_view, + views::BubbleBorder::TOP_LEFT}; + } } - if (anchor == kLocationBar && browser_view->GetLocationBarView()->IsDrawn()) - return {browser_view->GetLocationBarView(), - browser_view->GetLocationBarView()->location_icon_view(), + if (anchor == kLocationBar && location_bar_view->IsDrawn()) { + return {location_bar_view, location_bar_view->location_icon_view(), views::BubbleBorder::TOP_LEFT}; + } if (anchor == kLocationBar && browser_view->GetIsPictureInPictureType()) { auto* frame_view = static_cast<PictureInPictureBrowserFrameView*>( @@ -69,12 +85,12 @@ AnchorConfiguration GetPermissionPromptBubbleAnchorConfiguration( Browser* browser) { BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser); - if (browser_view->GetLocationBarView()->chip_controller() && + if (browser_view->GetLocationBarView()->GetChipController() && browser_view->GetLocationBarView() - ->chip_controller() + ->GetChipController() ->IsPermissionPromptChipVisible()) { return {browser_view->GetLocationBarView(), - browser_view->GetLocationBarView()->chip_controller()->chip(), + browser_view->GetLocationBarView()->GetChipController()->chip(), views::BubbleBorder::TOP_LEFT}; } return GetPageInfoAnchorConfiguration(browser);
diff --git a/chrome/browser/ui/views/chrome_layout_provider.cc b/chrome/browser/ui/views/chrome_layout_provider.cc index 7c1b718..1b49700 100644 --- a/chrome/browser/ui/views/chrome_layout_provider.cc +++ b/chrome/browser/ui/views/chrome_layout_provider.cc
@@ -166,6 +166,8 @@ return 24; case DISTANCE_OMNIBOX_CELL_VERTICAL_PADDING: return OmniboxFieldTrial::IsCr23LayoutEnabled() ? 12 : 8; + case DISTANCE_OMNIBOX_CHIPS_OVERLAP: + return 10; case DISTANCE_OMNIBOX_TWO_LINE_CELL_VERTICAL_PADDING: return 4; case DISTANCE_SIDE_PANEL_HEADER_VECTOR_ICON_SIZE:
diff --git a/chrome/browser/ui/views/chrome_layout_provider.h b/chrome/browser/ui/views/chrome_layout_provider.h index 99d7c68..259be6f 100644 --- a/chrome/browser/ui/views/chrome_layout_provider.h +++ b/chrome/browser/ui/views/chrome_layout_provider.h
@@ -89,6 +89,9 @@ DISTANCE_BETWEEN_PRIMARY_AND_SECONDARY_LABELS_HORIZONTAL, // Vertical padding at the top and bottom of the an omnibox match row. DISTANCE_OMNIBOX_CELL_VERTICAL_PADDING, + // Horizontal overlap between an activity indicator chip and a permission + // request chip. + DISTANCE_OMNIBOX_CHIPS_OVERLAP, // Vertical padding at the top and bottom of the an omnibox match row for two // line layout. DISTANCE_OMNIBOX_TWO_LINE_CELL_VERTICAL_PADDING,
diff --git a/chrome/browser/ui/views/chrome_views_delegate.h b/chrome/browser/ui/views/chrome_views_delegate.h index 2d08ec1..381ccad 100644 --- a/chrome/browser/ui/views/chrome_views_delegate.h +++ b/chrome/browser/ui/views/chrome_views_delegate.h
@@ -42,6 +42,11 @@ bool ShouldCloseMenuIfMouseCaptureLost() const override; #endif +#if BUILDFLAG(IS_CHROMEOS_LACROS) + bool ShouldWindowHaveRoundedCorners( + const gfx::NativeWindow window) const override; +#endif + #if BUILDFLAG(IS_CHROMEOS) std::unique_ptr<views::NonClientFrameView> CreateDefaultNonClientFrameView( views::Widget* widget) override;
diff --git a/chrome/browser/ui/views/chrome_views_delegate_lacros.cc b/chrome/browser/ui/views/chrome_views_delegate_lacros.cc index 4c6eb95..38181b7d 100644 --- a/chrome/browser/ui/views/chrome_views_delegate_lacros.cc +++ b/chrome/browser/ui/views/chrome_views_delegate_lacros.cc
@@ -6,9 +6,16 @@ #include <memory> +#include "chromeos/ui/frame/frame_utils.h" #include "chromeos/ui/frame/non_client_frame_view_base.h" +#include "ui/gfx/native_widget_types.h" std::unique_ptr<views::NonClientFrameView> ChromeViewsDelegate::CreateDefaultNonClientFrameView(views::Widget* widget) { return std::make_unique<chromeos::NonClientFrameViewBase>(widget); } + +bool ChromeViewsDelegate::ShouldWindowHaveRoundedCorners( + gfx::NativeWindow window) const { + return chromeos::ShouldWindowHaveRoundedCorners(window); +}
diff --git a/chrome/browser/ui/views/extensions/extension_popup_interactive_uitest.cc b/chrome/browser/ui/views/extensions/extension_popup_interactive_uitest.cc index 6177563a..f97c1da 100644 --- a/chrome/browser/ui/views/extensions/extension_popup_interactive_uitest.cc +++ b/chrome/browser/ui/views/extensions/extension_popup_interactive_uitest.cc
@@ -114,9 +114,9 @@ // If so, click on the chip to open the bubble. BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser()); LocationBarView* lbv = browser_view->toolbar()->location_bar(); - if (lbv->chip_controller()->IsPermissionPromptChipVisible() && - !lbv->chip_controller()->IsBubbleShowing()) { - views::test::ButtonTestApi(lbv->chip_controller()->chip()) + if (lbv->GetChipController()->IsPermissionPromptChipVisible() && + !lbv->GetChipController()->IsBubbleShowing()) { + views::test::ButtonTestApi(lbv->GetChipController()->chip()) .NotifyClick(ui::MouseEvent(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, 0));
diff --git a/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_lacros.cc b/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_lacros.cc index 0e17f89..8837b8c 100644 --- a/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_lacros.cc +++ b/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_lacros.cc
@@ -9,7 +9,6 @@ #include "base/check.h" #include "chrome/browser/ui/ui_features.h" #include "chrome/browser/ui/views/frame/browser_frame.h" -#include "chrome/browser/ui/views/frame/browser_non_client_frame_view.h" #include "chrome/browser/ui/views/frame/browser_view.h" #include "chrome/browser/ui/views/frame/desktop_browser_frame_lacros.h" #include "chrome/browser/ui/views/tabs/tab_drag_controller.h" @@ -17,10 +16,6 @@ #include "chromeos/ui/base/window_properties.h" #include "chromeos/ui/frame/frame_utils.h" #include "ui/base/dragdrop/mojom/drag_drop_types.mojom-shared.h" -#include "ui/compositor/layer.h" -#include "ui/gfx/geometry/rect_f.h" -#include "ui/gfx/geometry/rounded_corners_f.h" -#include "ui/gfx/geometry/rrect_f.h" #include "ui/platform_window/extensions/wayland_extension.h" #include "ui/platform_window/platform_window.h" @@ -62,97 +57,6 @@ native_frame_->set_host(nullptr); } -void BrowserDesktopWindowTreeHostLacros::UpdateFrameHints() { - const float scale = device_scale_factor(); - const gfx::Size widget_size_px = - platform_window()->GetBoundsInPixels().size(); - - auto* wayland_extension = ui::GetWaylandExtension(*platform_window()); - DCHECK(wayland_extension); - - const gfx::RoundedCornersF window_radii = - wayland_extension->GetWindowCornersRadii(); - - std::vector<gfx::Rect> opaque_region; - - const aura::Window* native_window = browser_view_->GetNativeWindow(); - const bool should_have_rounded_corners = - chromeos::ShouldWindowHaveRoundedCorners(native_window); - if (should_have_rounded_corners) { - GetContentWindow()->layer()->SetRoundedCornerRadius(window_radii); - GetContentWindow()->layer()->SetIsFastRoundedCorner(true); - - // The opaque region is a list of rectangles that contain only fully - // opaque pixels of the window. We need to convert the clipping - // rounded-rect into this format. - - const BrowserNonClientFrameView* view = - browser_view_->frame()->GetFrameView(); - gfx::Rect local_bounds = view->GetLocalBounds(); - gfx::RRectF rounded_corners_rect(gfx::RectF(local_bounds), window_radii); - gfx::RectF rect_f = rounded_corners_rect.rect(); - rect_f.Scale(scale); - - // It is acceptable to omit some pixels that are opaque, but the region - // must not include any translucent pixels. Therefore, we must - // conservatively scale to the enclosed rectangle. - gfx::Rect rect = gfx::ToEnclosedRect(rect_f); - - // Create the initial region from the clipping rectangle without rounded - // corners. - cc::Region region(rect); - - // Now subtract out the small rectangles that cover the corners. - struct { - gfx::RRectF::Corner corner; - bool left; - bool upper; - } kCorners[] = { - {gfx::RRectF::Corner::kUpperLeft, true, true}, - {gfx::RRectF::Corner::kUpperRight, false, true}, - {gfx::RRectF::Corner::kLowerLeft, true, false}, - {gfx::RRectF::Corner::kLowerRight, false, false}, - }; - for (const auto& corner : kCorners) { - auto corner_radii = rounded_corners_rect.GetCornerRadii(corner.corner); - auto rx = std::ceil(scale * corner_radii.x()); - auto ry = std::ceil(scale * corner_radii.y()); - auto corner_rect = - gfx::Rect(corner.left ? rect.x() : rect.right() - rx, - corner.upper ? rect.y() : rect.bottom() - ry, rx, ry); - region.Subtract(corner_rect); - } - - // Convert the region to a list of rectangles. - for (gfx::Rect i : region) { - opaque_region.push_back(i); - } - } else { - GetContentWindow()->layer()->SetRoundedCornerRadius({}); - GetContentWindow()->layer()->SetIsFastRoundedCorner(false); - opaque_region.push_back({{}, widget_size_px}); - } - // TODO(crbug.com/1306688): Instead of setting OpaqueRegion, set the rounded - // corners in dp. - platform_window()->SetOpaqueRegion(opaque_region); - - // If the window is rounded, we hint the platform to match the drop shadow's - // radii to the window's radii. Otherwise, we allow the platform to - // determine the drop shadow's radii. - if (should_have_rounded_corners) { - wayland_extension->SetShadowCornersRadii(window_radii); - } -} - -//////////////////////////////////////////////////////////////////////////////// -// BrowserDesktopWindowTreeHostLacros, -// DesktopWindowTreeHost implementation: - -void BrowserDesktopWindowTreeHostLacros::OnWidgetInitDone() { - DesktopWindowTreeHostLacros::OnWidgetInitDone(); - - UpdateFrameHints(); -} //////////////////////////////////////////////////////////////////////////////// // BrowserDesktopWindowTreeHostLacros, @@ -211,13 +115,6 @@ } } -void BrowserDesktopWindowTreeHostLacros::OnBoundsChanged( - const BoundsChange& change) { - DesktopWindowTreeHostLacros::OnBoundsChanged(change); - - UpdateFrameHints(); -} - void BrowserDesktopWindowTreeHostLacros::OnWindowStateChanged( ui::PlatformWindowState old_window_show_state, ui::PlatformWindowState new_window_show_state) { @@ -232,8 +129,6 @@ // BrowserView::ProcessFullscreen will no-op, so this call is harmless. browser_view_->FullscreenStateChanging(); } - - UpdateFrameHints(); } void BrowserDesktopWindowTreeHostLacros::OnFullscreenTypeChanged( @@ -246,18 +141,6 @@ browser_view_->FullscreenStateChanged(); } -void BrowserDesktopWindowTreeHostLacros::OnOverviewModeChanged( - bool in_overview) { - DesktopWindowTreeHostLacros::OnOverviewModeChanged(in_overview); - - // Window corner radius depends on weather the window is in overview mode or - // not. Once the overview property has been updated, the browser window - // corners needs to be updated. - // See `chromeos::GetFrameCornerRadius()` for more details. - // TODO(b/301501363): Rename to UpdateWindowHints. - UpdateFrameHints(); -} - //////////////////////////////////////////////////////////////////////////////// // BrowserDesktopWindowTreeHostLacros, // DesktopWindowTreeHostPlatform implementation:
diff --git a/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_lacros.h b/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_lacros.h index de8d94b3..c571d2e7 100644 --- a/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_lacros.h +++ b/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_lacros.h
@@ -37,12 +37,6 @@ void TabDraggingKindChanged(TabDragKind tab_drag_kind); private: - // Sets hints for the WM/compositor that reflect the rounded corners. - void UpdateFrameHints(); - - // DesktopWindowTreeHost: - void OnWidgetInitDone() override; - // BrowserDesktopWindowTreeHost: DesktopWindowTreeHost* AsDesktopWindowTreeHost() override; int GetMinimizeButtonOffset() const override; @@ -56,12 +50,10 @@ void UnlockMouse(aura::Window* window) override; // ui::PlatformWindowDelegate - void OnBoundsChanged(const BoundsChange& change) override; void OnWindowStateChanged(ui::PlatformWindowState old_state, ui::PlatformWindowState new_state) override; void OnFullscreenTypeChanged(ui::PlatformFullscreenType old_type, ui::PlatformFullscreenType new_type) override; - void OnOverviewModeChanged(bool in_overview) override; const raw_ptr<BrowserView> browser_view_; raw_ptr<DesktopBrowserFrameLacros> native_frame_ = nullptr;
diff --git a/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_linux.cc b/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_linux.cc index a0d2a65..bf788b2 100644 --- a/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_linux.cc +++ b/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_linux.cc
@@ -179,7 +179,7 @@ bool BrowserDesktopWindowTreeHostLinux::SupportsClientFrameShadow() const { return platform_window()->CanSetDecorationInsets() && - platform_window()->IsTranslucentWindowOpacitySupported(); + views::Widget::IsWindowCompositingSupported(); } void BrowserDesktopWindowTreeHostLinux::UpdateFrameHints() { @@ -216,7 +216,7 @@ showing_frame ? std::optional<gfx::Rect>(input_bounds) : std::nullopt); } - if (window->IsTranslucentWindowOpacitySupported()) { + if (ui::OzonePlatform::GetInstance()->IsWindowCompositingSupported()) { // Set the opaque region. std::vector<gfx::Rect> opaque_region; if (showing_frame) {
diff --git a/chrome/browser/ui/views/frame/browser_frame_view_layout_linux_native_unittest.cc b/chrome/browser/ui/views/frame/browser_frame_view_layout_linux_native_unittest.cc index 3bbdbe9..c64354b 100644 --- a/chrome/browser/ui/views/frame/browser_frame_view_layout_linux_native_unittest.cc +++ b/chrome/browser/ui/views/frame/browser_frame_view_layout_linux_native_unittest.cc
@@ -79,7 +79,6 @@ bool EverHasVisibleBackgroundTabShapes() const override { return false; } void UpdateWindowControlsOverlay( const gfx::Rect& bounding_rect) const override {} - bool IsTranslucentWindowOpacitySupported() const override { return true; } bool ShouldDrawRestoredFrameShadow() const override { return true; } #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS) ui::WindowTiledEdges GetTiledEdges() const override { return {}; }
diff --git a/chrome/browser/ui/views/frame/browser_frame_view_layout_linux_unittest.cc b/chrome/browser/ui/views/frame/browser_frame_view_layout_linux_unittest.cc index 423dba0..15b1229 100644 --- a/chrome/browser/ui/views/frame/browser_frame_view_layout_linux_unittest.cc +++ b/chrome/browser/ui/views/frame/browser_frame_view_layout_linux_unittest.cc
@@ -46,7 +46,6 @@ bool EverHasVisibleBackgroundTabShapes() const override { return false; } void UpdateWindowControlsOverlay( const gfx::Rect& bounding_rect) const override {} - bool IsTranslucentWindowOpacitySupported() const override { return true; } bool ShouldDrawRestoredFrameShadow() const override { return true; } #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS) ui::WindowTiledEdges GetTiledEdges() const override { return tiled_edges_; }
diff --git a/chrome/browser/ui/views/frame/browser_frame_view_linux.cc b/chrome/browser/ui/views/frame/browser_frame_view_linux.cc index 4bbafb7..bbdb7b8b 100644 --- a/chrome/browser/ui/views/frame/browser_frame_view_linux.cc +++ b/chrome/browser/ui/views/frame/browser_frame_view_linux.cc
@@ -10,6 +10,7 @@ #include "chrome/browser/ui/views/frame/desktop_browser_frame_aura_linux.h" #include "ui/gfx/geometry/skia_conversions.h" #include "ui/linux/linux_ui.h" +#include "ui/ozone/public/ozone_platform.h" #include "ui/views/layout/layout_provider.h" #include "ui/views/window/window_button_order_provider.h" @@ -95,7 +96,8 @@ } float BrowserFrameViewLinux::GetRestoredCornerRadiusDip() const { - if (!UseCustomFrame() || !IsTranslucentWindowOpacitySupported()) { + if (!UseCustomFrame() || + !ui::OzonePlatform::GetInstance()->IsWindowCompositingSupported()) { return 0; } return ChromeLayoutProvider::Get()->GetCornerRadiusMetric(
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc index a0d0eaf..255a99a 100644 --- a/chrome/browser/ui/views/frame/browser_view.cc +++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -187,6 +187,7 @@ #include "chrome/grit/theme_resources.h" #include "chromeos/components/mgs/managed_guest_session_utils.h" #include "components/autofill/core/common/autofill_payments_features.h" +#include "components/content_settings/core/common/features.h" #include "components/feature_engagement/public/event_constants.h" #include "components/feature_engagement/public/feature_constants.h" #include "components/feature_engagement/public/tracker.h" @@ -3518,9 +3519,9 @@ // Tab has a pending permission request. if (toolbar_ && toolbar_->location_bar() && - toolbar_->location_bar()->chip_controller() && + toolbar_->location_bar()->GetChipController() && toolbar_->location_bar() - ->chip_controller() + ->GetChipController() ->IsPermissionPromptChipVisible()) { return l10n_util::GetStringFUTF16( IDS_TAB_AX_LABEL_PERMISSION_REQUESTED_FORMAT, title); @@ -4072,15 +4073,28 @@ if (webui_tab_strip_) panes->push_back(webui_tab_strip_); #endif - // When permission is requested, permission chip must be first pane in the - // pane traversal order to be easily accessible for keyboard users. - if (toolbar_ && toolbar_->location_bar() && - toolbar_->location_bar()->chip_controller() && - toolbar_->location_bar() - ->chip_controller() - ->IsPermissionPromptChipVisible()) { - panes->push_back(toolbar_->location_bar()->chip_controller()->chip()); + // If activity indicators or a permission request chip is visible, it must be + // in the first position in the pane traversal order to be easily accessible + // for keyboard users. + if (base::FeatureList::IsEnabled( + content_settings::features::kLeftHandSideActivityIndicators)) { + if (toolbar_ && toolbar_->location_bar() && + toolbar_->location_bar() + ->permission_dashboard_controller() + ->permission_dashboard_view() + ->GetVisible()) { + panes->push_back(toolbar_->location_bar() + ->permission_dashboard_controller() + ->permission_dashboard_view()); + } + } else if (toolbar_ && toolbar_->location_bar() && + toolbar_->location_bar()->GetChipController() && + toolbar_->location_bar() + ->GetChipController() + ->IsPermissionPromptChipVisible()) { + panes->push_back(toolbar_->location_bar()->GetChipController()->chip()); } + panes->push_back(toolbar_button_provider_->GetAsAccessiblePaneView()); if (tab_strip_region_view_) panes->push_back(tab_strip_region_view_);
diff --git a/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc b/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc index 1f72952..8d3fcc4 100644 --- a/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc +++ b/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc
@@ -581,10 +581,6 @@ } } -bool OpaqueBrowserFrameView::IsTranslucentWindowOpacitySupported() const { - return frame()->IsTranslucentWindowOpacitySupported(); -} - bool OpaqueBrowserFrameView::ShouldDrawRestoredFrameShadow() const { return false; }
diff --git a/chrome/browser/ui/views/frame/opaque_browser_frame_view.h b/chrome/browser/ui/views/frame/opaque_browser_frame_view.h index c8e89e6..63cddfec 100644 --- a/chrome/browser/ui/views/frame/opaque_browser_frame_view.h +++ b/chrome/browser/ui/views/frame/opaque_browser_frame_view.h
@@ -114,7 +114,6 @@ FrameButtonStyle GetFrameButtonStyle() const override; void UpdateWindowControlsOverlay( const gfx::Rect& bounding_rect) const override; - bool IsTranslucentWindowOpacitySupported() const override; bool ShouldDrawRestoredFrameShadow() const override; #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS) ui::WindowTiledEdges GetTiledEdges() const override;
diff --git a/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout_delegate.h b/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout_delegate.h index 8a62abb..08c01550 100644 --- a/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout_delegate.h +++ b/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout_delegate.h
@@ -91,9 +91,6 @@ virtual void UpdateWindowControlsOverlay( const gfx::Rect& bounding_rect) const = 0; - // Returns true if the system compositor supports translucent windows. - virtual bool IsTranslucentWindowOpacitySupported() const = 0; - // Returns true if a client-side shadow should be drawn for restored windows. virtual bool ShouldDrawRestoredFrameShadow() const = 0;
diff --git a/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout_unittest.cc b/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout_unittest.cc index fd9490e..d4299a3 100644 --- a/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout_unittest.cc +++ b/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout_unittest.cc
@@ -90,7 +90,6 @@ bool EverHasVisibleBackgroundTabShapes() const override { return false; } void UpdateWindowControlsOverlay( const gfx::Rect& bounding_rect) const override {} - bool IsTranslucentWindowOpacitySupported() const override { return true; } bool ShouldDrawRestoredFrameShadow() const override { return true; } #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS) ui::WindowTiledEdges GetTiledEdges() const override { return {}; }
diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.cc b/chrome/browser/ui/views/location_bar/location_bar_view.cc index 7444fd9d..be7f16ec 100644 --- a/chrome/browser/ui/views/location_bar/location_bar_view.cc +++ b/chrome/browser/ui/views/location_bar/location_bar_view.cc
@@ -69,6 +69,7 @@ #include "chrome/browser/ui/views/page_action/page_action_icon_params.h" #include "chrome/browser/ui/views/page_info/page_info_bubble_view.h" #include "chrome/browser/ui/views/passwords/manage_passwords_icon_views.h" +#include "chrome/browser/ui/views/permissions/chip/permission_dashboard_view.h" #include "chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_icon_view.h" #include "chrome/browser/ui/views/sharing_hub/sharing_hub_icon_view.h" #include "chrome/browser/ui/web_applications/app_browser_controller.h" @@ -223,7 +224,20 @@ SetPaintToLayer(); layer()->SetFillsBoundsOpaquely(false); - CreateChip(); + if (base::FeatureList::IsEnabled( + content_settings::features::kLeftHandSideActivityIndicators)) { + permission_dashboard_view_ = + AddChildViewAt(std::make_unique<PermissionDashboardView>(), 0); + + permission_dashboard_controller_ = + std::make_unique<PermissionDashboardController>( + browser_, this, permission_dashboard_view_); + } else { + chip_controller_ = std::make_unique<ChipController>( + browser_, AddChildViewAt(std::make_unique<OmniboxChipButton>( + OmniboxChipButton::PressedCallback()), + 0)); + } const auto& typography_provider = views::TypographyProvider::Get(); const gfx::FontList& font_list = typography_provider.GetFont( @@ -616,8 +630,12 @@ !ShouldShowKeywordBubble(); const bool show_overriding_permission_chip = - chip_controller_ && chip_controller_->chip()->GetVisible() && - !ShouldShowKeywordBubble(); + base::FeatureList::IsEnabled( + content_settings::features::kLeftHandSideActivityIndicators) + ? permission_dashboard_view_->GetVisible() && + !ShouldShowKeywordBubble() + : chip_controller_->chip()->GetVisible() && + !ShouldShowKeywordBubble(); // There are 2 CR23 features that impact location bar layout. Make sure layout // is correct when neither, either, or both are enabled. Touch UI, whether the @@ -713,9 +731,16 @@ const double kLeadingDecorationMaxFraction = 0.5; if (show_overriding_permission_chip) { - leading_decorations.AddDecoration(vertical_padding, location_height, false, - 0, /*intra_item_padding=*/0, icon_left, - chip_controller_->chip()); + if (base::FeatureList::IsEnabled( + content_settings::features::kLeftHandSideActivityIndicators)) { + leading_decorations.AddDecoration(vertical_padding, location_height, + false, 0, /*intra_item_padding=*/0, + icon_left, permission_dashboard_view_); + } else { + leading_decorations.AddDecoration(vertical_padding, location_height, + false, 0, /*intra_item_padding=*/0, + icon_left, chip_controller_->chip()); + } } if (ShouldShowKeywordBubble()) { @@ -879,8 +904,9 @@ ? kColorPageActionIcon : kColorOmniboxResultsIcon); page_action_icon_controller_->SetIconColor(icon_color); - for (ContentSettingImageView* image_view : content_setting_views_) + for (ContentSettingImageView* image_view : content_setting_views_) { image_view->SetIconColor(icon_color); + } RefreshBackground(); RefreshClearAllButtonIcon(); @@ -942,19 +968,13 @@ ->ActivateFirstInactiveBubbleForAccessibility(); } -void LocationBarView::CreateChip() { - DCHECK(!chip_controller_); +ChipController* LocationBarView::GetChipController() { + if (base::FeatureList::IsEnabled( + content_settings::features::kLeftHandSideActivityIndicators)) { + return permission_dashboard_controller_->request_chip_controller(); + } - if (!browser_) - return; - - if (web_app::AppBrowserController::IsWebApp(browser_)) - return; - - chip_controller_ = std::make_unique<ChipController>( - browser_, AddChildViewAt(std::make_unique<OmniboxChipButton>( - OmniboxChipButton::PressedCallback()), - 0)); + return chip_controller_.get(); } void LocationBarView::UpdateWithoutTabRestore() { @@ -1488,7 +1508,7 @@ } bool LocationBarView::ShouldChipOverrideLocationIcon() { - return chip_controller_ && chip_controller_->chip()->GetVisible(); + return GetChipController()->chip()->GetVisible(); } bool LocationBarView::IsEditingOrEmpty() const { @@ -1563,16 +1583,16 @@ } void LocationBarView::RecordPageInfoMetrics() { - if (chip_controller_) { + if (GetChipController()) { bool confirmation_chip_collapsed_recently = base::TimeTicks::Now() - confirmation_chip_collapsed_time_ <= permissions::kConfirmationConsiderationDurationForUma; - if (!chip_controller_->chip()->GetVisible() && + if (!GetChipController()->chip()->GetVisible() && !confirmation_chip_collapsed_recently) { permissions::PermissionUmaUtil::RecordPageInfoDialogAccessType( permissions::PageInfoDialogAccessType::LOCK_CLICK); - } else if (chip_controller_->chip()->GetVisible()) { + } else if (GetChipController()->chip()->GetVisible()) { permissions::PermissionUmaUtil::RecordPageInfoDialogAccessType( permissions::PageInfoDialogAccessType:: LOCK_CLICK_DURING_CONFIRMATION_CHIP); @@ -1611,14 +1631,14 @@ } void LocationBarView::UpdateChipVisibility() { - if (!chip_controller_ || !chip_controller_->chip()->GetVisible()) { + if (!GetChipController()->chip()->GetVisible()) { return; } if (IsEditingOrEmpty()) { // If a user starts typing, a permission request should be ignored and the // chip finalized. - chip_controller_->ResetPermissionPromptChip(); + GetChipController()->ResetPermissionPromptChip(); } }
diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.h b/chrome/browser/ui/views/location_bar/location_bar_view.h index 65ca764..face072 100644 --- a/chrome/browser/ui/views/location_bar/location_bar_view.h +++ b/chrome/browser/ui/views/location_bar/location_bar_view.h
@@ -25,6 +25,7 @@ #include "chrome/browser/ui/views/location_bar/content_setting_image_view.h" #include "chrome/browser/ui/views/location_bar/location_icon_view.h" #include "chrome/browser/ui/views/page_action/page_action_icon_view.h" +#include "chrome/browser/ui/views/permissions/chip/permission_dashboard_controller.h" #include "chrome/browser/ui/views/permissions/chip_controller.h" #include "components/permissions/permission_prompt.h" #include "components/security_state/core/security_state.h" @@ -48,6 +49,7 @@ class OmniboxViewViews; class PageActionIconController; class PageActionIconContainerView; +class PermissionDashboardView; class Profile; class SelectedKeywordView; @@ -171,11 +173,13 @@ // accessibility. bool ActivateFirstInactiveBubbleForAccessibility(); - // Adds chip into the LocationBarView in the first position. - void CreateChip(); + // Controls the chip in the LocationBarView. + ChipController* GetChipController(); - // Controls the chip in the LocationBarView - ChipController* chip_controller() { return chip_controller_.get(); } + // Controls the permission dashboard in the LocationBarView. + PermissionDashboardController* permission_dashboard_controller() { + return permission_dashboard_controller_.get(); + } IntentChipButton* intent_chip() { return intent_chip_; } @@ -413,6 +417,10 @@ // permission information and requests. std::unique_ptr<ChipController> chip_controller_ = nullptr; + std::unique_ptr<PermissionDashboardController> + permission_dashboard_controller_; + raw_ptr<PermissionDashboardView> permission_dashboard_view_; + // An icon to the left of the edit field: the HTTPS lock, blank page icon, // search icon, EV HTTPS bubble, etc. raw_ptr<LocationIconView> location_icon_view_ = nullptr;
diff --git a/chrome/browser/ui/views/permissions/chip/permission_dashboard_controller.cc b/chrome/browser/ui/views/permissions/chip/permission_dashboard_controller.cc new file mode 100644 index 0000000..b5202f1 --- /dev/null +++ b/chrome/browser/ui/views/permissions/chip/permission_dashboard_controller.cc
@@ -0,0 +1,21 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/views/permissions/chip/permission_dashboard_controller.h" + +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/views/location_bar/location_bar_view.h" + +PermissionDashboardController::PermissionDashboardController( + Browser* browser, + LocationBarView* location_bar_view, + PermissionDashboardView* permission_dashboard_view) + : location_bar_view_(location_bar_view), + permission_dashboard_view_(permission_dashboard_view) { + request_chip_controller_ = std::make_unique<ChipController>( + browser, permission_dashboard_view_->GetRequestChip(), + permission_dashboard_view_); +} + +PermissionDashboardController::~PermissionDashboardController() = default;
diff --git a/chrome/browser/ui/views/permissions/chip/permission_dashboard_controller.h b/chrome/browser/ui/views/permissions/chip/permission_dashboard_controller.h new file mode 100644 index 0000000..0e06d88 --- /dev/null +++ b/chrome/browser/ui/views/permissions/chip/permission_dashboard_controller.h
@@ -0,0 +1,44 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_VIEWS_PERMISSIONS_CHIP_PERMISSION_DASHBOARD_CONTROLLER_H_ +#define CHROME_BROWSER_UI_VIEWS_PERMISSIONS_CHIP_PERMISSION_DASHBOARD_CONTROLLER_H_ + +#include <memory> + +#include "base/memory/raw_ptr.h" +#include "chrome/browser/ui/views/permissions/chip/permission_dashboard_view.h" + +class Browser; +class LocationBarView; +class ChipController; + +class PermissionDashboardController { + public: + PermissionDashboardController( + Browser* browser, + LocationBarView* location_bar_view, + PermissionDashboardView* permission_dashboard_view); + + ~PermissionDashboardController(); + PermissionDashboardController(const PermissionDashboardController&) = delete; + PermissionDashboardController& operator=( + const PermissionDashboardController&) = delete; + + ChipController* request_chip_controller() { + return request_chip_controller_.get(); + } + + PermissionDashboardView* permission_dashboard_view() { + return permission_dashboard_view_; + } + + private: + raw_ptr<LocationBarView> location_bar_view_; + raw_ptr<PermissionDashboardView> permission_dashboard_view_; + + std::unique_ptr<ChipController> request_chip_controller_; +}; + +#endif // CHROME_BROWSER_UI_VIEWS_PERMISSIONS_CHIP_PERMISSION_DASHBOARD_CONTROLLER_H_
diff --git a/chrome/browser/ui/views/permissions/chip/permission_dashboard_layout.cc b/chrome/browser/ui/views/permissions/chip/permission_dashboard_layout.cc new file mode 100644 index 0000000..86660bf --- /dev/null +++ b/chrome/browser/ui/views/permissions/chip/permission_dashboard_layout.cc
@@ -0,0 +1,56 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/views/permissions/chip/permission_dashboard_layout.h" + +#include "chrome/browser/ui/views/chrome_layout_provider.h" +#include "ui/gfx/geometry/point.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/geometry/size.h" +#include "ui/views/layout/layout_types.h" +#include "ui/views/view.h" + +PermissionDashboardLayout::PermissionDashboardLayout() = default; + +PermissionDashboardLayout::~PermissionDashboardLayout() = default; + +views::ProposedLayout PermissionDashboardLayout::CalculateProposedLayout( + const views::SizeBounds& size_bounds) const { + views::ProposedLayout layout; + int x = 0; + + auto views = host_view()->children(); + DCHECK(views.size() == 2); + + views::View* indicator_chip_view = views[1]; + if (indicator_chip_view->GetVisible()) { + gfx::Size preferred_size = indicator_chip_view->GetPreferredSize(); + gfx::Rect proposed_bounds = gfx::Rect(gfx::Point(0, 0), preferred_size); + views::SizeBounds available_bounds = views::SizeBounds(preferred_size); + + layout.child_layouts.push_back({indicator_chip_view, + indicator_chip_view->GetVisible(), + proposed_bounds, available_bounds}); + + // `indicator_chip_view` and `request_chip_view` overlaps to create an + // illusion that `request_chip_view` is placed under `indicator_chip_view`. + // To achieve that move `request_chip_view` x coordinate to the left by + // subtracting the overlap value from it. + x = preferred_size.width() - ChromeLayoutProvider::Get()->GetDistanceMetric( + DISTANCE_OMNIBOX_CHIPS_OVERLAP); + } + + views::View* request_chip_view = views[0]; + if (request_chip_view->GetVisible()) { + gfx::Size preferred_size = request_chip_view->GetPreferredSize(); + gfx::Rect proposed_bounds = gfx::Rect(gfx::Point(x, 0), preferred_size); + views::SizeBounds available_bounds = views::SizeBounds(preferred_size); + + layout.child_layouts.push_back({request_chip_view, + request_chip_view->GetVisible(), + proposed_bounds, available_bounds}); + } + + return layout; +}
diff --git a/chrome/browser/ui/views/permissions/chip/permission_dashboard_layout.h b/chrome/browser/ui/views/permissions/chip/permission_dashboard_layout.h new file mode 100644 index 0000000..2565ff4 --- /dev/null +++ b/chrome/browser/ui/views/permissions/chip/permission_dashboard_layout.h
@@ -0,0 +1,31 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_VIEWS_PERMISSIONS_CHIP_PERMISSION_DASHBOARD_LAYOUT_H_ +#define CHROME_BROWSER_UI_VIEWS_PERMISSIONS_CHIP_PERMISSION_DASHBOARD_LAYOUT_H_ + +#include "ui/views/layout/layout_manager_base.h" +#include "ui/views/layout/layout_types.h" +#include "ui/views/layout/proposed_layout.h" + +// PermissionDashboardLayout is a LayoutManager that is designed to be used only +// for `PermissionDashboardView`. The layout manager positions views in a row +// with a small overlay so that the first view is displayed on top of the second +// view. +class PermissionDashboardLayout : public views::LayoutManagerBase { + public: + PermissionDashboardLayout(); + + PermissionDashboardLayout(const PermissionDashboardLayout&) = delete; + PermissionDashboardLayout& operator=(const PermissionDashboardLayout&) = + delete; + + ~PermissionDashboardLayout() override; + + // LayoutManagerBase: + views::ProposedLayout CalculateProposedLayout( + const views::SizeBounds& size_bounds) const override; +}; + +#endif // CHROME_BROWSER_UI_VIEWS_PERMISSIONS_CHIP_PERMISSION_DASHBOARD_LAYOUT_H_
diff --git a/chrome/browser/ui/views/permissions/chip/permission_dashboard_view.cc b/chrome/browser/ui/views/permissions/chip/permission_dashboard_view.cc new file mode 100644 index 0000000..98c31f9 --- /dev/null +++ b/chrome/browser/ui/views/permissions/chip/permission_dashboard_view.cc
@@ -0,0 +1,93 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/views/permissions/chip/permission_dashboard_view.h" + +#include "base/time/time.h" +#include "chrome/browser/ui/color/chrome_color_id.h" +#include "chrome/browser/ui/views/chrome_layout_provider.h" +#include "chrome/browser/ui/views/location_bar/omnibox_chip_button.h" +#include "chrome/browser/ui/views/permissions/chip/permission_dashboard_layout.h" +#include "components/vector_icons/vector_icons.h" +#include "ui/base/metadata/metadata_impl_macros.h" +#include "ui/compositor/layer.h" +#include "ui/gfx/geometry/size.h" +#include "ui/views/style/platform_style.h" + +namespace { +// Indicator chip and request chip have an overlap. +int kChipOverlaps; +} // namespace + +PermissionDashboardView::PermissionDashboardView() { + SetVisible(false); + + SetLayoutManager(std::make_unique<PermissionDashboardLayout>()); + + // Permission request chip should be created the first because it is displayed + // under all other views. + request_chip_ = AddChildView(std::make_unique<OmniboxChipButton>( + OmniboxChipButton::PressedCallback())); + + // Activity indicators chip should be created the last because it is displayed + // above all other views. + indicator_chip_ = AddChildView(std::make_unique<OmniboxChipButton>( + OmniboxChipButton::PressedCallback())); + + // It is unclear which chip will be shown first, hence hide both of them. + request_chip_->SetVisible(false); + indicator_chip_->SetVisible(false); + + kChipOverlaps = ChromeLayoutProvider::Get()->GetDistanceMetric( + DISTANCE_OMNIBOX_CHIPS_OVERLAP); +} + +PermissionDashboardView::~PermissionDashboardView() = default; + +gfx::Size PermissionDashboardView::CalculatePreferredSize() const { + if (!request_chip_->GetVisible() && !indicator_chip_->GetVisible()) { + return gfx::Size(0, 0); + } + + gfx::Size first_chip_size = indicator_chip_->GetPreferredSize(); + if (!request_chip_->GetVisible()) { + return first_chip_size; + } + + if (!indicator_chip_->GetVisible()) { + return request_chip_->GetPreferredSize(); + } + + gfx::Size second_chip_size = request_chip_->GetPreferredSize(); + int width = + first_chip_size.width() + second_chip_size.width() - kChipOverlaps; + int height = first_chip_size.height(); + + return gfx::Size(width, height); +} + +gfx::Size PermissionDashboardView::GetMinimumSize() const { + if (!request_chip_->GetVisible() && !indicator_chip_->GetVisible()) { + return gfx::Size(0, 0); + } + + if (!request_chip_->GetVisible()) { + return indicator_chip_->GetMinimumSize(); + } + + if (!indicator_chip_->GetVisible()) { + return request_chip_->GetMinimumSize(); + } + + gfx::Size first_chip_size = indicator_chip_->GetMinimumSize(); + gfx::Size second_chip_size = request_chip_->GetMinimumSize(); + int width = + first_chip_size.width() + second_chip_size.width() - kChipOverlaps; + int height = first_chip_size.height(); + + return gfx::Size(width, height); +} + +BEGIN_METADATA(PermissionDashboardView) +END_METADATA
diff --git a/chrome/browser/ui/views/permissions/chip/permission_dashboard_view.h b/chrome/browser/ui/views/permissions/chip/permission_dashboard_view.h new file mode 100644 index 0000000..074151bb --- /dev/null +++ b/chrome/browser/ui/views/permissions/chip/permission_dashboard_view.h
@@ -0,0 +1,37 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_VIEWS_PERMISSIONS_CHIP_PERMISSION_DASHBOARD_VIEW_H_ +#define CHROME_BROWSER_UI_VIEWS_PERMISSIONS_CHIP_PERMISSION_DASHBOARD_VIEW_H_ + +#include "base/memory/raw_ptr.h" +#include "ui/gfx/geometry/size.h" +#include "ui/views/view.h" + +class OmniboxChipButton; + +// UI component for activity indicators and chip button located in the omnibox. +class PermissionDashboardView : public views::View { + METADATA_HEADER(PermissionDashboardView, views::View) + + public: + PermissionDashboardView(); + PermissionDashboardView(const PermissionDashboardView& button) = delete; + PermissionDashboardView& operator=(const PermissionDashboardView& button) = + delete; + ~PermissionDashboardView() override; + + OmniboxChipButton* GetRequestChip() { return request_chip_; } + OmniboxChipButton* GetIndicatorChip() { return indicator_chip_; } + + // views::View. + gfx::Size CalculatePreferredSize() const override; + gfx::Size GetMinimumSize() const override; + + private: + raw_ptr<OmniboxChipButton> indicator_chip_; + raw_ptr<OmniboxChipButton> request_chip_; +}; + +#endif // CHROME_BROWSER_UI_VIEWS_PERMISSIONS_CHIP_PERMISSION_DASHBOARD_VIEW_H_
diff --git a/chrome/browser/ui/views/permissions/chip_controller.cc b/chrome/browser/ui/views/permissions/chip_controller.cc index d0e951f..f49102e 100644 --- a/chrome/browser/ui/views/permissions/chip_controller.cc +++ b/chrome/browser/ui/views/permissions/chip_controller.cc
@@ -7,6 +7,7 @@ #include <memory> #include <string> #include <utility> + #include "base/check.h" #include "base/feature_list.h" #include "base/functional/bind.h" @@ -20,11 +21,13 @@ #include "chrome/browser/ui/views/location_bar/location_bar_view.h" #include "chrome/browser/ui/views/omnibox/omnibox_view_views.h" #include "chrome/browser/ui/views/page_info/page_info_bubble_view.h" +#include "chrome/browser/ui/views/permissions/chip/permission_dashboard_view.h" #include "chrome/browser/ui/views/permissions/permission_prompt_bubble_view_factory.h" #include "chrome/browser/ui/views/permissions/permission_prompt_chip_model.h" #include "chrome/browser/ui/views/permissions/permission_prompt_style.h" #include "chrome/common/webui_url_constants.h" #include "chrome/grit/generated_resources.h" +#include "components/content_settings/core/common/features.h" #include "components/permissions/features.h" #include "components/permissions/permission_prompt.h" #include "components/permissions/permission_request_manager.h" @@ -76,8 +79,13 @@ raw_ptr<BubbleOwnerDelegate, DanglingUntriaged> bubble_owner_ = nullptr; }; -ChipController::ChipController(Browser* browser, OmniboxChipButton* chip_view) - : chip_(chip_view), browser_(browser) { +ChipController::ChipController( + Browser* browser, + OmniboxChipButton* chip_view, + PermissionDashboardView* permission_dashboard_view) + : browser_(browser), + chip_(chip_view), + permission_dashboard_view_(permission_dashboard_view) { chip_->SetVisible(false); } @@ -235,6 +243,9 @@ // a request chip is shown --> only once a confirmation should be displayed, // the chip should become visible. chip_->SetVisible(false); + if (permission_dashboard_view_) { + permission_dashboard_view_->SetVisible(false); + } permission_prompt_model_ = std::make_unique<PermissionPromptChipModel>(delegate); @@ -289,6 +300,9 @@ AnnouncePermissionRequestForAccessibility( permission_prompt_model_->GetAccessibilityChipText()); chip_->SetVisible(true); + if (permission_dashboard_view_) { + permission_dashboard_view_->SetVisible(true); + } SyncChipWithModel(); @@ -413,6 +427,9 @@ chip_->ResetAnimation(); chip_->AnimateExpand(GetAnimationDuration(base::Milliseconds(350))); chip_->SetVisible(true); + if (permission_dashboard_view_) { + permission_dashboard_view_->SetVisible(true); + } } void ChipController::HandleConfirmation( @@ -426,7 +443,10 @@ permission_prompt_model_->CanDisplayConfirmation()) { is_confirmation_showing_ = true; - if (chip_->GetVisible()) { + // AnimateToFit isn't working for `PermissionDashboardView`. + if (chip_->GetVisible() && + !base::FeatureList::IsEnabled( + content_settings::features::kLeftHandSideActivityIndicators)) { chip_->AnimateToFit(GetAnimationDuration(base::Milliseconds(200))); } else { // No request chip was shown, always expand independently of what contents @@ -497,6 +517,9 @@ return; chip_->SetVisible(false); + if (permission_dashboard_view_) { + permission_dashboard_view_->SetVisible(false); + } // When the chip visibility changed from visible -> hidden, the locationbar // layout should be updated. GetLocationBarView()->InvalidateLayout();
diff --git a/chrome/browser/ui/views/permissions/chip_controller.h b/chrome/browser/ui/views/permissions/chip_controller.h index 8841d236f..6cc0f4c 100644 --- a/chrome/browser/ui/views/permissions/chip_controller.h +++ b/chrome/browser/ui/views/permissions/chip_controller.h
@@ -21,6 +21,7 @@ class PermissionPromptChipModel; class LocationBarView; +class PermissionDashboardView; // ButtonController that NotifyClick from being called when the // BubbleOwnerDelegate's bubble is showing. Otherwise the bubble will show again // immediately after being closed via losing focus. @@ -42,7 +43,9 @@ public BubbleOwnerDelegate, public OmniboxChipButton::Observer { public: - ChipController(Browser* browser_, OmniboxChipButton* chip_view); + ChipController(Browser* browser, + OmniboxChipButton* chip_view, + PermissionDashboardView* permission_dashboard_view = nullptr); ~ChipController() override; ChipController(const ChipController&) = delete; @@ -207,10 +210,13 @@ bool is_confirmation_showing_ = false; bool is_waiting_for_confirmation_collapse_ = false; + raw_ptr<Browser> browser_; + // The chip view this controller modifies. raw_ptr<OmniboxChipButton> chip_; - raw_ptr<Browser> browser_; + // `PermissionDashboardView` is owner of OmniboxChipButton. + raw_ptr<PermissionDashboardView> permission_dashboard_view_; // The time when the request chip was displayed. base::TimeTicks request_chip_shown_time_;
diff --git a/chrome/browser/ui/views/permissions/permission_bubble_interactive_uitest.cc b/chrome/browser/ui/views/permissions/permission_bubble_interactive_uitest.cc index bf0b7dd..b26616e 100644 --- a/chrome/browser/ui/views/permissions/permission_bubble_interactive_uitest.cc +++ b/chrome/browser/ui/views/permissions/permission_bubble_interactive_uitest.cc
@@ -120,9 +120,9 @@ BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser()); LocationBarView* lbv = browser_view->toolbar()->location_bar(); - if (lbv->chip_controller()->IsPermissionPromptChipVisible() && - !lbv->chip_controller()->IsBubbleShowing()) { - views::test::ButtonTestApi(lbv->chip_controller()->chip()) + if (lbv->GetChipController()->IsPermissionPromptChipVisible() && + !lbv->GetChipController()->IsBubbleShowing()) { + views::test::ButtonTestApi(lbv->GetChipController()->chip()) .NotifyClick(ui::MouseEvent(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, 0));
diff --git a/chrome/browser/ui/views/permissions/permission_chip_interactive_test.cc b/chrome/browser/ui/views/permissions/permission_chip_interactive_test.cc index 5246a536..41d620c 100644 --- a/chrome/browser/ui/views/permissions/permission_chip_interactive_test.cc +++ b/chrome/browser/ui/views/permissions/permission_chip_interactive_test.cc
@@ -158,7 +158,7 @@ } OmniboxChipButton* GetChip() { - return GetLocationBarView()->chip_controller()->chip(); + return GetLocationBarView()->GetChipController()->chip(); } ChipController* GetChipController() { @@ -166,7 +166,7 @@ BrowserView::GetBrowserViewForBrowser(browser()); LocationBarView* lbv = browser_view->toolbar()->location_bar(); - return lbv->chip_controller(); + return lbv->GetChipController(); } PermissionPromptChip* GetPermissionPromptChip() { @@ -1592,7 +1592,7 @@ LocationBarView* location_bar = BrowserView::GetBrowserViewForBrowser(browser())->GetLocationBarView(); ASSERT_TRUE(location_bar); - ChipController* chip_controller = location_bar->chip_controller(); + ChipController* chip_controller = location_bar->GetChipController(); ChipExpansionObserver chip_expansion_observer(chip_controller->chip()); EXPECT_FALSE(manager->IsRequestInProgress());
diff --git a/chrome/browser/ui/views/permissions/permission_prompt_bubble.cc b/chrome/browser/ui/views/permissions/permission_prompt_bubble.cc index bc796ee..ff70d77 100644 --- a/chrome/browser/ui/views/permissions/permission_prompt_bubble.cc +++ b/chrome/browser/ui/views/permissions/permission_prompt_bubble.cc
@@ -21,7 +21,7 @@ LocationBarView* lbv = GetLocationBarView(); if (lbv && lbv->IsDrawn() && delegate->Requests()[0]->IsConfirmationChipSupported()) { - lbv->chip_controller()->InitializePermissionPrompt( + lbv->GetChipController()->InitializePermissionPrompt( delegate->GetWeakPtr(), base::BindOnce(&PermissionPromptBubble::ShowBubble, weak_factory_.GetWeakPtr())); @@ -127,7 +127,7 @@ if (lbv && lbv->IsDrawn() && !lbv->GetWidget()->IsFullscreen() && !lbv->IsEditingOrEmpty()) { - auto* chip_controller = lbv->chip_controller(); + auto* chip_controller = lbv->GetChipController(); chip_controller->InitializePermissionPrompt(delegate()->GetWeakPtr()); } }
diff --git a/chrome/browser/ui/views/permissions/permission_prompt_bubble_base_view_browsertest.cc b/chrome/browser/ui/views/permissions/permission_prompt_bubble_base_view_browsertest.cc index 581f004..bd602e9 100644 --- a/chrome/browser/ui/views/permissions/permission_prompt_bubble_base_view_browsertest.cc +++ b/chrome/browser/ui/views/permissions/permission_prompt_bubble_base_view_browsertest.cc
@@ -141,7 +141,7 @@ ChipController* GetChipController() { BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser()); - return browser_view->toolbar()->location_bar()->chip_controller(); + return browser_view->toolbar()->location_bar()->GetChipController(); } ContentSettingImageView& GetContentSettingImageView(
diff --git a/chrome/browser/ui/views/permissions/permission_prompt_chip.cc b/chrome/browser/ui/views/permissions/permission_prompt_chip.cc index 357452ab..486ef2201 100644 --- a/chrome/browser/ui/views/permissions/permission_prompt_chip.cc +++ b/chrome/browser/ui/views/permissions/permission_prompt_chip.cc
@@ -33,10 +33,6 @@ DCHECK(delegate_); LocationBarView* lbv = GetLocationBarView(); - if (!lbv->chip_controller()->chip()) { - lbv->CreateChip(); - } - // Before showing a chip make sure the LocationBar is in a valid state. That // fixes a bug when a chip overlays the padlock icon. lbv->InvalidateLayout(); @@ -44,7 +40,7 @@ if (delegate->ShouldCurrentRequestUseQuietUI()) PreemptivelyResolvePermissionRequest(web_contents, delegate); - chip_controller_ = lbv->chip_controller(); + chip_controller_ = lbv->GetChipController(); chip_controller_->ShowPermissionPrompt(delegate->GetWeakPtr()); } @@ -107,8 +103,8 @@ LocationBarView* lbv = GetLocationBarView(); return chip_controller_->IsPermissionPromptChipVisible() && - lbv->chip_controller()->IsBubbleShowing() - ? lbv->chip_controller()->GetBubbleWidget() + lbv->GetChipController()->IsBubbleShowing() + ? lbv->GetChipController()->GetBubbleWidget() : nullptr; }
diff --git a/chrome/browser/ui/views/permissions/permission_request_chip_browsertest.cc b/chrome/browser/ui/views/permissions/permission_request_chip_browsertest.cc index a922bea..878103b 100644 --- a/chrome/browser/ui/views/permissions/permission_request_chip_browsertest.cc +++ b/chrome/browser/ui/views/permissions/permission_request_chip_browsertest.cc
@@ -61,7 +61,7 @@ ChipFinalizedWhenInteractingWithOmnibox) { RequestPermission(browser()); LocationBarView* lbv = GetLocationBarView(browser()); - auto* animation = lbv->chip_controller()->chip()->animation_for_testing(); + auto* animation = lbv->GetChipController()->chip()->animation_for_testing(); // Animate the chip expand. gfx::AnimationTestApi animation_api(animation); @@ -71,12 +71,14 @@ // After animation ended, the chip is expanded and the bubble is shown because // the gesture sensitive request feature is enabled. - EXPECT_TRUE(lbv->chip_controller()->IsPermissionPromptChipVisible()); - EXPECT_TRUE(lbv->chip_controller()->IsBubbleShowing()); + EXPECT_TRUE(lbv->GetChipController()->IsPermissionPromptChipVisible()); + EXPECT_TRUE(lbv->GetChipController()->IsBubbleShowing()); // Because the bubble is shown, callback timers should be abandoned - EXPECT_FALSE(lbv->chip_controller()->is_collapse_timer_running_for_testing()); - EXPECT_FALSE(lbv->chip_controller()->is_dismiss_timer_running_for_testing()); + EXPECT_FALSE( + lbv->GetChipController()->is_collapse_timer_running_for_testing()); + EXPECT_FALSE( + lbv->GetChipController()->is_dismiss_timer_running_for_testing()); // Type something in the omnibox. auto* omnibox_view = lbv->GetOmniboxView(); @@ -87,8 +89,8 @@ // While the user is interacting with the omnibox, the chip is hidden, the // location icon isn't offset by the chip and the bubble is hidden. - EXPECT_FALSE(lbv->chip_controller()->IsPermissionPromptChipVisible()); - EXPECT_FALSE(lbv->chip_controller()->IsBubbleShowing()); + EXPECT_FALSE(lbv->GetChipController()->IsPermissionPromptChipVisible()); + EXPECT_FALSE(lbv->GetChipController()->IsBubbleShowing()); if (!features::IsChromeRefresh2023() && !OmniboxFieldTrial::IsCr23LayoutEnabled()) { // CR2023 has a few experimental flavors of LocationIconView positioning. @@ -99,8 +101,10 @@ } // Ensure no callbacks are pending. - EXPECT_FALSE(lbv->chip_controller()->is_collapse_timer_running_for_testing()); - EXPECT_FALSE(lbv->chip_controller()->is_dismiss_timer_running_for_testing()); + EXPECT_FALSE( + lbv->GetChipController()->is_collapse_timer_running_for_testing()); + EXPECT_FALSE( + lbv->GetChipController()->is_dismiss_timer_running_for_testing()); } IN_PROC_BROWSER_TEST_F(PermissionRequestChipGestureSensitiveBrowserTest, @@ -108,7 +112,7 @@ LocationBarView* lbv = GetLocationBarView(browser()); // The chip is not shown because there is no active permission request. - EXPECT_FALSE(lbv->chip_controller()->IsPermissionPromptChipVisible()); + EXPECT_FALSE(lbv->GetChipController()->IsPermissionPromptChipVisible()); // Type something in the omnibox. auto* omnibox_view = lbv->GetOmniboxView(); @@ -119,7 +123,7 @@ // While the user is interacting with the omnibox, an incoming permission // request will be automatically ignored. The chip is not shown. - EXPECT_FALSE(lbv->chip_controller()->IsPermissionPromptChipVisible()); + EXPECT_FALSE(lbv->GetChipController()->IsPermissionPromptChipVisible()); } // This is an end-to-end test that verifies that a permission prompt bubble will @@ -257,7 +261,7 @@ LocationBarView* location_bar = BrowserView::GetBrowserViewForBrowser(browser())->GetLocationBarView(); ASSERT_TRUE(location_bar); - ChipController* chip_controller = location_bar->chip_controller(); + ChipController* chip_controller = location_bar->GetChipController(); // Trigger permission request on first tab EXPECT_FALSE(manager_tab_0->IsRequestInProgress()); @@ -306,7 +310,7 @@ CallbacksResetWhenInteractingWithOmnibox) { RequestPermission(browser()); LocationBarView* lbv = GetLocationBarView(browser()); - auto* animation = lbv->chip_controller()->chip()->animation_for_testing(); + auto* animation = lbv->GetChipController()->chip()->animation_for_testing(); // Animate the chip expand. gfx::AnimationTestApi animation_api(animation); @@ -315,13 +319,15 @@ animation_api.Step(now + animation->GetSlideDuration()); // After animation ended, the chip is expanded and a bubble is shown. - EXPECT_TRUE(lbv->chip_controller()->IsPermissionPromptChipVisible()); - EXPECT_TRUE(lbv->chip_controller()->IsBubbleShowing()); + EXPECT_TRUE(lbv->GetChipController()->IsPermissionPromptChipVisible()); + EXPECT_TRUE(lbv->GetChipController()->IsBubbleShowing()); // Because a bubble is shown, the collapse callback timer should not be // running. - EXPECT_FALSE(lbv->chip_controller()->is_collapse_timer_running_for_testing()); - EXPECT_FALSE(lbv->chip_controller()->is_dismiss_timer_running_for_testing()); + EXPECT_FALSE( + lbv->GetChipController()->is_collapse_timer_running_for_testing()); + EXPECT_FALSE( + lbv->GetChipController()->is_dismiss_timer_running_for_testing()); // Type something in the omnibox. auto* omnibox_view = lbv->GetOmniboxView(); @@ -331,9 +337,11 @@ base::RunLoop().RunUntilIdle(); // Ensure chip is no longer visible and callbacks are no longer running. - EXPECT_FALSE(lbv->chip_controller()->IsPermissionPromptChipVisible()); - EXPECT_FALSE(lbv->chip_controller()->is_collapse_timer_running_for_testing()); - EXPECT_FALSE(lbv->chip_controller()->is_dismiss_timer_running_for_testing()); + EXPECT_FALSE(lbv->GetChipController()->IsPermissionPromptChipVisible()); + EXPECT_FALSE( + lbv->GetChipController()->is_collapse_timer_running_for_testing()); + EXPECT_FALSE( + lbv->GetChipController()->is_dismiss_timer_running_for_testing()); } class PermissionRequestChipBrowserUiTest : public UiBrowserTest { @@ -345,7 +353,7 @@ bool VerifyUi() override { LocationBarView* const location_bar = GetLocationBarView(browser()); - OmniboxChipButton* const chip = location_bar->chip_controller()->chip(); + OmniboxChipButton* const chip = location_bar->GetChipController()->chip(); if (!chip || !chip->GetVisible() || chip->is_fully_collapsed()) { return false; } @@ -383,10 +391,10 @@ LocationBarView* lbv = GetLocationBarView(browser()); // The chip is expanded and a bubble is shown. - EXPECT_TRUE(lbv->chip_controller()->IsPermissionPromptChipVisible()); - EXPECT_TRUE(lbv->chip_controller()->IsBubbleShowing()); + EXPECT_TRUE(lbv->GetChipController()->IsPermissionPromptChipVisible()); + EXPECT_TRUE(lbv->GetChipController()->IsBubbleShowing()); - lbv->chip_controller() + lbv->GetChipController() ->active_permission_request_manager_for_testing() .value() ->Deny(); @@ -394,18 +402,20 @@ base::RunLoop().RunUntilIdle(); // The chip is visible as we show the confirmation. - EXPECT_TRUE(lbv->chip_controller()->IsPermissionPromptChipVisible()); - EXPECT_FALSE(lbv->chip_controller()->IsBubbleShowing()); - EXPECT_TRUE(lbv->chip_controller()->is_confirmation_showing_for_testing()); - EXPECT_TRUE(lbv->chip_controller()->is_collapse_timer_running_for_testing()); - EXPECT_FALSE(lbv->chip_controller() + EXPECT_TRUE(lbv->GetChipController()->IsPermissionPromptChipVisible()); + EXPECT_FALSE(lbv->GetChipController()->IsBubbleShowing()); + EXPECT_TRUE(lbv->GetChipController()->is_confirmation_showing_for_testing()); + EXPECT_TRUE( + lbv->GetChipController()->is_collapse_timer_running_for_testing()); + EXPECT_FALSE(lbv->GetChipController() ->is_waiting_for_confirmation_collapse_for_testing()); - lbv->chip_controller()->fire_collapse_timer_for_testing(); + lbv->GetChipController()->fire_collapse_timer_for_testing(); - EXPECT_FALSE(lbv->chip_controller()->IsPermissionPromptChipVisible()); - EXPECT_FALSE(lbv->chip_controller()->is_confirmation_showing_for_testing()); - EXPECT_FALSE(lbv->chip_controller()->is_collapse_timer_running_for_testing()); - EXPECT_FALSE(lbv->chip_controller() + EXPECT_FALSE(lbv->GetChipController()->IsPermissionPromptChipVisible()); + EXPECT_FALSE(lbv->GetChipController()->is_confirmation_showing_for_testing()); + EXPECT_FALSE( + lbv->GetChipController()->is_collapse_timer_running_for_testing()); + EXPECT_FALSE(lbv->GetChipController() ->is_waiting_for_confirmation_collapse_for_testing()); }
diff --git a/chrome/browser/ui/web_applications/BUILD.gn b/chrome/browser/ui/web_applications/BUILD.gn index 79abee4b..31d46ba 100644 --- a/chrome/browser/ui/web_applications/BUILD.gn +++ b/chrome/browser/ui/web_applications/BUILD.gn
@@ -51,6 +51,7 @@ "web_app_menu_model_browsertest.cc", "web_app_metrics_browsertest.cc", "web_app_navigate_browsertest.cc", + "web_app_title_browsertest.cc", "web_app_ui_manager_impl_browsertest.cc", "web_app_uninstall_browsertest.cc", ]
diff --git a/chrome/browser/ui/web_applications/web_app_browser_controller.cc b/chrome/browser/ui/web_applications/web_app_browser_controller.cc index b18c4a7..0feda079 100644 --- a/chrome/browser/ui/web_applications/web_app_browser_controller.cc +++ b/chrome/browser/ui/web_applications/web_app_browser_controller.cc
@@ -11,6 +11,7 @@ #include "base/functional/callback.h" #include "base/functional/callback_helpers.h" #include "base/memory/raw_ptr.h" +#include "base/metrics/histogram_functions.h" #include "base/strings/strcat.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" @@ -37,6 +38,7 @@ #include "chrome/browser/web_applications/web_app_sync_bridge.h" #include "chrome/browser/web_applications/web_app_tab_helper.h" #include "chrome/browser/web_applications/web_app_ui_manager.h" +#include "chrome/grit/generated_resources.h" #include "components/password_manager/core/common/password_manager_features.h" #include "components/services/app_service/public/cpp/app_registry_cache.h" #include "components/services/app_service/public/cpp/app_types.h" @@ -46,6 +48,7 @@ #include "content/public/browser/web_contents.h" #include "content/public/common/content_features.h" #include "third_party/blink/public/common/features.h" +#include "ui/base/l10n/l10n_util.h" #include "ui/gfx/favicon_size.h" #include "ui/gfx/image/image.h" #include "ui/native_theme/native_theme.h" @@ -575,6 +578,19 @@ std::u16string app_name = base::UTF8ToUTF16( provider_->registrar_unsafe().GetAppShortName(app_id())); + + // If app title is set, then use that with the app name as the title. + std::u16string app_title; + content::WebContents* web_contents = + browser()->tab_strip_model()->GetActiveWebContents(); + if (web_contents) { + app_title = web_contents->GetAppTitle(); + } + + if (!app_title.empty()) { + return l10n_util::GetStringFUTF16(IDS_WEB_APP_WITH_APP_TITLE, app_name, + app_title); + } if (base::StartsWith(raw_title, app_name)) { return raw_title; }
diff --git a/chrome/browser/ui/web_applications/web_app_title_browsertest.cc b/chrome/browser/ui/web_applications/web_app_title_browsertest.cc new file mode 100644 index 0000000..2eda884 --- /dev/null +++ b/chrome/browser/ui/web_applications/web_app_title_browsertest.cc
@@ -0,0 +1,159 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/web_applications/web_app_controller_browsertest.h" +#include "chrome/browser/web_applications/web_app_helpers.h" +#include "chrome/test/base/ui_test_utils.h" +#include "content/public/common/content_switches.h" +#include "content/public/test/browser_test.h" + +namespace web_app { + +// Test app title scenarios with valid, empty and dynamic app title. +class WebAppTitleBrowserTest : public WebAppControllerBrowserTest { + public: + WebAppTitleBrowserTest() = default; + + void SetUpCommandLine(base::CommandLine* command_line) override { + command_line->AppendSwitchASCII(switches::kEnableBlinkFeatures, "AppTitle"); + } +}; + +IN_PROC_BROWSER_TEST_F(WebAppTitleBrowserTest, ValidAppTitle) { + const GURL app_url = + https_server()->GetURL("/web_apps/page_with_app_title.html"); + const std::u16string app_title = u"A Web App"; + + auto web_app_info = std::make_unique<WebAppInstallInfo>( + GenerateManifestIdFromStartUrlOnly(app_url)); + web_app_info->start_url = app_url; + web_app_info->scope = app_url.GetWithoutFilename(); + web_app_info->title = app_title; + const webapps::AppId app_id = InstallWebApp(std::move(web_app_info)); + + Browser* const app_browser = LaunchWebAppBrowser(app_id); + content::WebContents* const web_contents = + app_browser->tab_strip_model()->GetActiveWebContents(); + EXPECT_TRUE(content::WaitForLoadStop(web_contents)); + + // Validate app title has app title. + EXPECT_EQ(u"A Web App - AppTitle", + app_browser->GetWindowTitleForCurrentTab(false)); +} + +IN_PROC_BROWSER_TEST_F(WebAppTitleBrowserTest, WithoutAppTitle) { + const GURL app_url = + https_server()->GetURL("/web_apps/page_without_app_title.html"); + const std::u16string app_title = u"A Web App"; + + auto web_app_info = std::make_unique<WebAppInstallInfo>( + GenerateManifestIdFromStartUrlOnly(app_url)); + web_app_info->start_url = app_url; + web_app_info->scope = app_url.GetWithoutFilename(); + web_app_info->title = app_title; + const webapps::AppId app_id = InstallWebApp(std::move(web_app_info)); + + Browser* const app_browser = LaunchWebAppBrowser(app_id); + content::WebContents* const web_contents = + app_browser->tab_strip_model()->GetActiveWebContents(); + EXPECT_TRUE(content::WaitForLoadStop(web_contents)); + + // Validate app title is the same as page title. + EXPECT_EQ(u"A Web App", app_browser->GetWindowTitleForCurrentTab(false)); +} + +IN_PROC_BROWSER_TEST_F(WebAppTitleBrowserTest, DynamicAppTitle) { + const GURL app_url = + https_server()->GetURL("/web_apps/page_without_app_title.html"); + const std::u16string app_title = u"A Web App"; + + auto web_app_info = std::make_unique<WebAppInstallInfo>( + GenerateManifestIdFromStartUrlOnly(app_url)); + web_app_info->start_url = app_url; + web_app_info->scope = app_url.GetWithoutFilename(); + web_app_info->title = app_title; + const webapps::AppId app_id = InstallWebApp(std::move(web_app_info)); + + Browser* const app_browser = LaunchWebAppBrowser(app_id); + content::WebContents* const web_contents = + app_browser->tab_strip_model()->GetActiveWebContents(); + EXPECT_TRUE(content::WaitForLoadStop(web_contents)); + + // Validate that app title matches page title. + EXPECT_EQ(u"A Web App", app_browser->GetWindowTitleForCurrentTab(false)); + + { + // Add app title via script and validate title is updated. + std::string add_app_title = + "var meta = document.createElement('meta'); meta.name = 'app-title'; " + "meta.content = 'AppTitle'; " + "document.getElementsByTagName('head')[0].appendChild(meta);"; + EXPECT_TRUE(content::ExecJs(web_contents, add_app_title)); + EXPECT_TRUE(content::WaitForLoadStop(web_contents)); + EXPECT_EQ(u"A Web App - AppTitle", + app_browser->GetWindowTitleForCurrentTab(false)); + } + + { + // Update app title via script and validate title is updated. + std::string update_app_title = + "document.head.getElementsByTagName('meta')['app-title'].content = " + "'New'"; + EXPECT_TRUE(content::ExecJs(web_contents, update_app_title)); + EXPECT_TRUE(content::WaitForLoadStop(web_contents)); + EXPECT_EQ(u"A Web App - New", + app_browser->GetWindowTitleForCurrentTab(false)); + } + + { + // Remove app title via script and validate title is updated. + std::string remove_app_title = + "document.head.getElementsByTagName('meta')['app-title'].remove()"; + EXPECT_TRUE(content::ExecJs(web_contents, remove_app_title)); + EXPECT_TRUE(content::WaitForLoadStop(web_contents)); + EXPECT_EQ(u"A Web App", app_browser->GetWindowTitleForCurrentTab(false)); + } +} + +// Navigate to page with and without app title to validate app title is updated. +IN_PROC_BROWSER_TEST_F(WebAppTitleBrowserTest, AppTitleNavigation) { + const GURL app_url = + https_server()->GetURL("/web_apps/page_with_app_title.html"); + const std::u16string app_title = u"A Web App"; + + auto web_app_info = std::make_unique<WebAppInstallInfo>( + GenerateManifestIdFromStartUrlOnly(app_url)); + web_app_info->start_url = app_url; + web_app_info->scope = app_url.GetWithoutFilename(); + web_app_info->title = app_title; + const webapps::AppId app_id = InstallWebApp(std::move(web_app_info)); + + Browser* const app_browser = LaunchWebAppBrowser(app_id); + content::WebContents* const web_contents = + app_browser->tab_strip_model()->GetActiveWebContents(); + EXPECT_TRUE(content::WaitForLoadStop(web_contents)); + + // Validate app title has app title. + EXPECT_EQ(u"A Web App - AppTitle", + app_browser->GetWindowTitleForCurrentTab(false)); + + // Navigate to page without app title. + const GURL page_without_url = + https_server()->GetURL("/web_apps/page_without_app_title.html"); + EXPECT_TRUE(ui_test_utils::NavigateToURL(app_browser, page_without_url)); + EXPECT_EQ(u"A Web App", app_browser->GetWindowTitleForCurrentTab(false)); + + // Navigate to page with app title. + web_contents->GetController().GoBack(); + EXPECT_TRUE(content::WaitForLoadStop(web_contents)); + EXPECT_EQ(u"A Web App - AppTitle", + app_browser->GetWindowTitleForCurrentTab(false)); + + // Navigate again to page without app title. + web_contents->GetController().GoForward(); + EXPECT_TRUE(content::WaitForLoadStop(web_contents)); + EXPECT_EQ(u"A Web App", app_browser->GetWindowTitleForCurrentTab(false)); +} +} // namespace web_app
diff --git a/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog.cc b/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog.cc index 0869d2b..c6fa7c6 100644 --- a/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog.cc +++ b/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog.cc
@@ -60,7 +60,6 @@ #include "ui/base/l10n/l10n_util.h" #include "ui/chromeos/strings/grit/ui_chromeos_strings.h" #include "ui/gfx/geometry/size.h" -#include "ui/gfx/native_widget_types.h" #include "ui/message_center/public/cpp/notification.h" #include "ui/message_center/public/cpp/notification_delegate.h" @@ -397,11 +396,9 @@ Profile* profile, const std::vector<storage::FileSystemURL>& file_urls, const CloudProvider cloud_provider, - gfx::NativeWindow modal_parent, std::unique_ptr<CloudOpenMetrics> cloud_open_metrics) { - scoped_refptr<CloudOpenTask> upload_task = WrapRefCounted( - new CloudOpenTask(profile, file_urls, cloud_provider, modal_parent, - std::move(cloud_open_metrics))); + scoped_refptr<CloudOpenTask> upload_task = WrapRefCounted(new CloudOpenTask( + profile, file_urls, cloud_provider, std::move(cloud_open_metrics))); // Keep `upload_task` alive until `TaskFinished` executes. bool status = upload_task->ExecuteInternal(); return status; @@ -411,12 +408,10 @@ Profile* profile, std::vector<storage::FileSystemURL> file_urls, const CloudProvider cloud_provider, - gfx::NativeWindow modal_parent, std::unique_ptr<CloudOpenMetrics> cloud_open_metrics) : profile_(profile), file_urls_(file_urls), cloud_provider_(cloud_provider), - modal_parent_(modal_parent), cloud_open_metrics_(std::move(cloud_open_metrics)) {} CloudOpenTask::~CloudOpenTask() = default; @@ -991,8 +986,9 @@ // Creates and shows a new dialog for the cloud upload workflow. If there are // local file tasks from `resulting_tasks`, include them in the dialog // arguments. These tasks are can be selected by the user to open the files -// instead of using a cloud provider. If no modal_parent was provided, first -// launches a new Files app window, which we listen for in OnBrowserAdded(). +// instead of using a cloud provider. If there is no Files app window currently +// open to use as a modal parent for the dialog, first launches a new Files app +// window, which we listen for in OnBrowserAdded(). void CloudOpenTask::ShowDialog( mojom::DialogArgsPtr args, std::unique_ptr<fm_tasks::ResultingTasks> resulting_tasks) { @@ -1031,7 +1027,13 @@ std::move(args), base::BindOnce(&CloudOpenTask::OnDialogComplete, this), office_move_confirmation_shown); - if (!modal_parent_) { + // Get Files App window, if it exists. + Browser* browser = + FindSystemWebAppBrowser(profile_, ash::SystemWebAppType::FILE_MANAGER); + gfx::NativeWindow modal_parent = + browser ? browser->window()->GetNativeWindow() : nullptr; + + if (!modal_parent) { BrowserList::AddObserver(this); DCHECK(!pending_dialog_); pending_dialog_ = dialog; @@ -1041,7 +1043,7 @@ file_manager::util::ShowItemInFolder(profile_, file_urls_.at(0).path(), base::DoNothing()); } else { - dialog->ShowSystemDialog(modal_parent_); + dialog->ShowSystemDialog(modal_parent); } } @@ -1087,8 +1089,7 @@ } BrowserList::RemoveObserver(this); - modal_parent_ = browser->window()->GetNativeWindow(); - pending_dialog_->ShowSystemDialog(modal_parent_); + pending_dialog_->ShowSystemDialog(browser->window()->GetNativeWindow()); // The dialog is deleted in `SystemWebDialogDelegate::OnDialogClosed`. pending_dialog_ = nullptr; } @@ -1210,7 +1211,7 @@ ? OfficeSetupFileHandler::kQuickOffice : OfficeSetupFileHandler::kOtherLocalHandler); fm_tasks::ExecuteFileTask( - profile_, task, file_urls_, nullptr, + profile_, task, file_urls_, base::BindOnce(&CloudOpenTask::LocalTaskExecuted, this, task)); }
diff --git a/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog.h b/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog.h index 86613f1..69a9094 100644 --- a/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog.h +++ b/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog.h
@@ -26,6 +26,7 @@ #include "components/drive/file_errors.h" #include "storage/browser/file_system/file_system_url.h" #include "ui/gfx/geometry/size.h" +#include "ui/gfx/native_widget_types.h" class Profile; @@ -107,7 +108,6 @@ static bool Execute(Profile* profile, const std::vector<storage::FileSystemURL>& file_urls, const CloudProvider cloud_provider, - gfx::NativeWindow modal_parent, std::unique_ptr<CloudOpenMetrics> cloud_open_metrics); // Set the local tasks that are passed to the File Handler dialog. Normally @@ -159,7 +159,6 @@ CloudOpenTask(Profile* profile, std::vector<storage::FileSystemURL> file_urls, const CloudProvider cloud_provider, - gfx::NativeWindow modal_parent, std::unique_ptr<CloudOpenMetrics> cloud_open_metrics); ~CloudOpenTask() override; @@ -234,7 +233,6 @@ raw_ptr<Profile, DanglingUntriaged> profile_; std::vector<storage::FileSystemURL> file_urls_; CloudProvider cloud_provider_; - gfx::NativeWindow modal_parent_; std::unique_ptr<CloudOpenMetrics> cloud_open_metrics_; std::vector<::file_manager::file_tasks::TaskDescriptor> local_tasks_; size_t pending_uploads_ = 0;
diff --git a/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog_browsertest.cc b/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog_browsertest.cc index 4b7f559..85c77bf 100644 --- a/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog_browsertest.cc +++ b/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog_browsertest.cc
@@ -255,8 +255,7 @@ base::test::ScopedFeatureList feature_list_; }; -// Tests that a new Files app window is created if no modal parent window is -// passed in. +// Tests that a new Files app window is created if no Files app window exists. IN_PROC_BROWSER_TEST_F(FileHandlerDialogBrowserTest, NewModalParentCreated) { file_manager::test::AddDefaultComponentExtensionsOnMainThread(profile()); @@ -271,7 +270,7 @@ // Launch File Handler dialog. ASSERT_TRUE(CloudOpenTask::Execute( - profile(), files_, CloudProvider::kGoogleDrive, nullptr, + profile(), files_, CloudProvider::kGoogleDrive, std::make_unique<CloudOpenMetrics>(CloudProvider::kGoogleDrive, /*file_count=*/1))); @@ -283,51 +282,10 @@ ASSERT_NE(nullptr, browser); } -// Tests that a new Files app window is created even if there is a Files app -// window open, but it's not the window that was passed in to CloudOpenTask. -IN_PROC_BROWSER_TEST_F(FileHandlerDialogBrowserTest, - NewModalParentCreatedWithExisting) { - file_manager::test::AddDefaultComponentExtensionsOnMainThread(profile()); - - Browser* browser = - FindSystemWebAppBrowser(profile(), SystemWebAppType::FILE_MANAGER); - ASSERT_EQ(nullptr, browser); - - // Open a files app window. - base::test::TestFuture<platform_util::OpenOperationResult> future; - file_manager::util::ShowItemInFolder(profile(), files_.at(0).path(), - future.GetCallback()); - EXPECT_EQ(future.Get(), platform_util::OpenOperationResult::OPEN_SUCCEEDED); - Browser* first_files_app = ui_test_utils::WaitForBrowserToOpen(); - - browser = FindSystemWebAppBrowser(profile(), SystemWebAppType::FILE_MANAGER); - ASSERT_NE(nullptr, browser); - ASSERT_EQ(first_files_app, browser); - - // Watch for File Handler dialog URL chrome://cloud-upload. - content::TestNavigationObserver navigation_observer_dialog( - (GURL(chrome::kChromeUICloudUploadURL))); - navigation_observer_dialog.StartWatchingNewWebContents(); - - // Launch File Handler dialog. - ASSERT_TRUE(CloudOpenTask::Execute( - profile(), files_, CloudProvider::kGoogleDrive, nullptr, - std::make_unique<CloudOpenMetrics>(CloudProvider::kGoogleDrive, - /*file_count=*/1))); - // Check that a new browser opened. - Browser* new_browser = ui_test_utils::WaitForBrowserToOpen(); - ASSERT_NE(new_browser, first_files_app); - ASSERT_TRUE( - IsBrowserForSystemWebApp(new_browser, SystemWebAppType::FILE_MANAGER)); - - // Wait for File Handler dialog to open at chrome://cloud-upload. - navigation_observer_dialog.Wait(); - ASSERT_TRUE(navigation_observer_dialog.last_navigation_succeeded()); -} - // Tests that a new Files app window is not created when there is a Files app -// window already open, and it's passed in as the modal parent. -IN_PROC_BROWSER_TEST_F(FileHandlerDialogBrowserTest, ModalParentProvided) { +// window already open. +IN_PROC_BROWSER_TEST_F(FileHandlerDialogBrowserTest, + ExistingWindowUsedAsModalParent) { file_manager::test::AddDefaultComponentExtensionsOnMainThread(profile()); Browser* browser = @@ -354,7 +312,6 @@ // Launch File Handler dialog. ASSERT_TRUE(CloudOpenTask::Execute( profile(), files_, CloudProvider::kGoogleDrive, - browser->window()->GetNativeWindow(), std::make_unique<CloudOpenMetrics>(CloudProvider::kGoogleDrive, /*file_count=*/1))); @@ -387,7 +344,7 @@ // Launch File Handler dialog. ASSERT_TRUE(CloudOpenTask::Execute(profile(), files_, - CloudProvider::kGoogleDrive, nullptr, + CloudProvider::kGoogleDrive, std::move(cloud_open_metrics))); // Wait for File Handler dialog to open at chrome://cloud-upload. @@ -438,7 +395,7 @@ // Launch File Handler dialog. ASSERT_TRUE(CloudOpenTask::Execute(profile(), files_, - CloudProvider::kGoogleDrive, nullptr, + CloudProvider::kGoogleDrive, std::move(cloud_open_metrics))); // Wait for File Handler dialog to open at chrome://cloud-upload. @@ -568,7 +525,7 @@ // Launch File Handler dialog. ASSERT_TRUE(CloudOpenTask::Execute( - profile(), files_, CloudProvider::kGoogleDrive, nullptr, + profile(), files_, CloudProvider::kGoogleDrive, std::make_unique<CloudOpenMetrics>(CloudProvider::kGoogleDrive, /*file_count=*/1))); @@ -725,7 +682,6 @@ : CloudProvider::kOneDrive; ASSERT_TRUE(CloudOpenTask::Execute( profile(), {doc_file}, cloud_provider, - /*modal_parent=*/nullptr, std::make_unique<CloudOpenMetrics>(cloud_provider, /*file_count=*/1))); // Wait for File Handler dialog to open at chrome://cloud-upload. @@ -784,7 +740,7 @@ // Launch File Handler dialog. ASSERT_TRUE(CloudOpenTask::Execute( - profile(), {doc_file}, CloudProvider::kOneDrive, /*modal_parent=*/nullptr, + profile(), {doc_file}, CloudProvider::kOneDrive, std::make_unique<CloudOpenMetrics>(CloudProvider::kOneDrive, /*file_count=*/1))); @@ -955,7 +911,7 @@ ? CloudProvider::kGoogleDrive : CloudProvider::kOneDrive; ASSERT_TRUE(CloudOpenTask::Execute( - profile(), files_, cloud_provider, nullptr, + profile(), files_, cloud_provider, std::make_unique<CloudOpenMetrics>(cloud_provider, /*file_count=*/1))); // Wait for File Handler dialog to open at chrome://cloud-upload. @@ -1154,7 +1110,7 @@ auto cloud_open_task = base::WrapRefCounted( new CloudOpenTask(profile(), files_, CloudProvider::kGoogleDrive, - nullptr, std::move(cloud_open_metrics))); + std::move(cloud_open_metrics))); cloud_open_task->SetTasksForTest(tasks_); for (int selected_task = 0; selected_task < num_tasks_; selected_task++) { @@ -1189,7 +1145,7 @@ { auto cloud_open_task = base::WrapRefCounted( new CloudOpenTask(profile(), files_, CloudProvider::kGoogleDrive, - nullptr, std::move(cloud_open_metrics))); + std::move(cloud_open_metrics))); cloud_open_task->SetTasksForTest(tasks_); int out_of_range_task = num_tasks_; @@ -1278,10 +1234,9 @@ (GURL(chrome::kChromeUICloudUploadURL))); navigation_observer_dialog.StartWatchingNewWebContents(); - gfx::NativeWindow modal_parent = LaunchFilesAppAndWait(browser()->profile()); + LaunchFilesAppAndWait(browser()->profile()); CloudOpenTask::Execute(profile(), files_, CloudProvider::kOneDrive, - modal_parent, std::make_unique<CloudOpenMetrics>( CloudProvider::kOneDrive, /*file_count=*/1)); @@ -1325,10 +1280,9 @@ (GURL(chrome::kChromeUICloudUploadURL))); navigation_observer_dialog.StartWatchingNewWebContents(); - gfx::NativeWindow modal_parent = LaunchFilesAppAndWait(browser()->profile()); + LaunchFilesAppAndWait(browser()->profile()); CloudOpenTask::Execute(profile(), files_, CloudProvider::kOneDrive, - modal_parent, std::make_unique<CloudOpenMetrics>( CloudProvider::kOneDrive, /*file_count=*/1)); @@ -1386,7 +1340,7 @@ AddFakeOfficePWA(); auto cloud_open_task = base::WrapRefCounted( - new CloudOpenTask(profile(), files_, CloudProvider::kOneDrive, nullptr, + new CloudOpenTask(profile(), files_, CloudProvider::kOneDrive, std::make_unique<CloudOpenMetrics>( CloudProvider::kOneDrive, /*file_count=*/1))); mojom::DialogArgsPtr args = @@ -1461,7 +1415,7 @@ AddFakeOfficePWA(); auto cloud_open_task = base::WrapRefCounted( - new CloudOpenTask(profile(), files_, CloudProvider::kOneDrive, nullptr, + new CloudOpenTask(profile(), files_, CloudProvider::kOneDrive, std::make_unique<CloudOpenMetrics>( CloudProvider::kOneDrive, /*file_count=*/1))); mojom::DialogArgsPtr args = @@ -1531,7 +1485,7 @@ upload_task_ = base::WrapRefCounted(new ash::cloud_upload::CloudOpenTask( profile(), source_files_, - ash::cloud_upload::CloudProvider::kGoogleDrive, nullptr, + ash::cloud_upload::CloudProvider::kGoogleDrive, std::make_unique<CloudOpenMetrics>(CloudProvider::kGoogleDrive, /*file_count=*/1))); } @@ -1546,7 +1500,7 @@ upload_task_ = base::WrapRefCounted(new ash::cloud_upload::CloudOpenTask( profile(), source_files_, - ash::cloud_upload::CloudProvider::kGoogleDrive, nullptr, + ash::cloud_upload::CloudProvider::kGoogleDrive, std::make_unique<CloudOpenMetrics>(CloudProvider::kGoogleDrive, /*file_count=*/1))); } @@ -1561,7 +1515,7 @@ upload_task_ = base::WrapRefCounted(new ash::cloud_upload::CloudOpenTask( profile(), source_files_, - ash::cloud_upload::CloudProvider::kGoogleDrive, nullptr, + ash::cloud_upload::CloudProvider::kGoogleDrive, std::make_unique<CloudOpenMetrics>(CloudProvider::kGoogleDrive, /*file_count=*/1))); } @@ -1576,7 +1530,6 @@ upload_task_ = base::WrapRefCounted(new ash::cloud_upload::CloudOpenTask( profile(), source_files_, ash::cloud_upload::CloudProvider::kOneDrive, - nullptr, std::make_unique<CloudOpenMetrics>(CloudProvider::kOneDrive, /*file_count=*/1))); } @@ -1591,7 +1544,6 @@ upload_task_ = base::WrapRefCounted(new ash::cloud_upload::CloudOpenTask( profile(), source_files_, ash::cloud_upload::CloudProvider::kOneDrive, - nullptr, std::make_unique<CloudOpenMetrics>(CloudProvider::kOneDrive, /*file_count=*/1))); } @@ -1606,7 +1558,6 @@ upload_task_ = base::WrapRefCounted(new ash::cloud_upload::CloudOpenTask( profile(), source_files_, ash::cloud_upload::CloudProvider::kOneDrive, - nullptr, std::make_unique<CloudOpenMetrics>(CloudProvider::kOneDrive, /*file_count=*/1))); }
diff --git a/chrome/browser/ui/webui/compose/compose_ui.cc b/chrome/browser/ui/webui/compose/compose_ui.cc index b734ebd..8d6fe35 100644 --- a/chrome/browser/ui/webui/compose/compose_ui.cc +++ b/chrome/browser/ui/webui/compose/compose_ui.cc
@@ -54,6 +54,7 @@ {"inputFooter", IDS_COMPOSE_FOOTER_FISHFOOD}, {"submitButton", IDS_COMPOSE_SUBMIT_BUTTON}, {"resultFooter", IDS_COMPOSE_FOOTER_FISHFOOD}, + {"onDeviceUsedFooter", IDS_COMPOSE_FEEDBACK_PLACEHOLDER}, {"insertButton", IDS_COMPOSE_INSERT_BUTTON}, {"replaceButton", IDS_COMPOSE_REPLACE_BUTTON}, {"lengthMenuTitle", IDS_COMPOSE_MENU_LENGTH_TITLE},
diff --git a/chrome/browser/ui/webui/privacy_sandbox/privacy_sandbox_internals.mojom b/chrome/browser/ui/webui/privacy_sandbox/privacy_sandbox_internals.mojom index b62060e..adfcbc88 100644 --- a/chrome/browser/ui/webui/privacy_sandbox/privacy_sandbox_internals.mojom +++ b/chrome/browser/ui/webui/privacy_sandbox/privacy_sandbox_internals.mojom
@@ -33,9 +33,14 @@ GetTpcdSupport() => ( array<content_settings.mojom.ContentSettingPatternSource> content_settings); - // Convert PatternParts into a string representation. + // Convert ContentSettingsPattern into a string representation. ContentSettingsPatternToString( content_settings.mojom.ContentSettingsPattern pattern) => (string s); + + // Converts a string into a ContentSettingsPattern. + StringToContentSettingsPattern(string s) => ( + content_settings.mojom.ContentSettingsPattern pattern); + };
diff --git a/chrome/browser/ui/webui/privacy_sandbox/privacy_sandbox_internals_handler.cc b/chrome/browser/ui/webui/privacy_sandbox/privacy_sandbox_internals_handler.cc index 920e994..c7cc2940 100644 --- a/chrome/browser/ui/webui/privacy_sandbox/privacy_sandbox_internals_handler.cc +++ b/chrome/browser/ui/webui/privacy_sandbox/privacy_sandbox_internals_handler.cc
@@ -71,4 +71,10 @@ std::move(callback).Run(pattern.ToString()); } +void PrivacySandboxInternalsHandler::StringToContentSettingsPattern( + const std::string& s, + StringToContentSettingsPatternCallback callback) { + std::move(callback).Run(ContentSettingsPattern::FromString(s)); +} + } // namespace privacy_sandbox_internals
diff --git a/chrome/browser/ui/webui/privacy_sandbox/privacy_sandbox_internals_handler.h b/chrome/browser/ui/webui/privacy_sandbox/privacy_sandbox_internals_handler.h index 892fd5d..ae2329fb 100644 --- a/chrome/browser/ui/webui/privacy_sandbox/privacy_sandbox_internals_handler.h +++ b/chrome/browser/ui/webui/privacy_sandbox/privacy_sandbox_internals_handler.h
@@ -34,6 +34,11 @@ void ContentSettingsPatternToString( const ContentSettingsPattern& pattern, ContentSettingsPatternToStringCallback callback) override; + + void StringToContentSettingsPattern( + const std::string& s, + StringToContentSettingsPatternCallback callback) override; + void GetCookieSettings(GetCookieSettingsCallback callback) override; void GetTpcdMetadataGrants(GetTpcdMetadataGrantsCallback callback) override; void GetTpcdHeuristicsGrants(GetTpcdMetadataGrantsCallback callback) override;
diff --git a/chrome/browser/ui/webui/privacy_sandbox/privacy_sandbox_internals_handler_browsertest.cc b/chrome/browser/ui/webui/privacy_sandbox/privacy_sandbox_internals_handler_browsertest.cc index 84cc62e5..b9d77d1 100644 --- a/chrome/browser/ui/webui/privacy_sandbox/privacy_sandbox_internals_handler_browsertest.cc +++ b/chrome/browser/ui/webui/privacy_sandbox/privacy_sandbox_internals_handler_browsertest.cc
@@ -93,6 +93,11 @@ waiter_.Notify(); } + void ContentSettingsPatternCallback(const ContentSettingsPattern& pattern) { + content_settings_pattern_cb_data_ = pattern; + waiter_.Notify(); + } + protected: mojo::Remote<PageHandler> remote_; std::unique_ptr<PrivacySandboxInternalsHandler> handler_; @@ -103,6 +108,7 @@ std::vector<ContentSettingPatternSource> content_settings_cb_data_; std::string string_cb_data_; base::Value value_cb_data_; + ContentSettingsPattern content_settings_pattern_cb_data_; }; IN_PROC_BROWSER_TEST_F(PrivacySandboxInternalsMojoTest, ReadPref) { @@ -211,7 +217,8 @@ Field(&ContentSettingPatternSource::source, "preference"))))); } -IN_PROC_BROWSER_TEST_F(PrivacySandboxInternalsMojoTest, PatternPartsToString) { +IN_PROC_BROWSER_TEST_F(PrivacySandboxInternalsMojoTest, + ContentSettingsPatternToString) { for (const std::string& regex : {"[*.]example.com", "http://example.net", "example.org"}) { ContentSettingsPattern pattern = ContentSettingsPattern::FromString(regex); @@ -225,5 +232,21 @@ } } +IN_PROC_BROWSER_TEST_F(PrivacySandboxInternalsMojoTest, + StringToContentSettingsPattern) { + for (const std::string& regex : + {"[*.]example.com", "http://example.net", "example.org"}) { + remote_->StringToContentSettingsPattern( + regex, + base::BindOnce( + &PrivacySandboxInternalsMojoTest::ContentSettingsPatternCallback, + base::Unretained(this))); + ContentSettingsPattern expected_pattern = + ContentSettingsPattern::FromString(regex); + waiter_.Wait(); + waiter_.Reset(); + EXPECT_THAT(content_settings_pattern_cb_data_, Eq(expected_pattern)); + } +} } // namespace } // namespace privacy_sandbox_internals
diff --git a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc index dc92e65..e32ef16 100644 --- a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc +++ b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
@@ -184,62 +184,64 @@ void AddCommonStrings(content::WebUIDataSource* html_source, Profile* profile) { static constexpr webui::LocalizedString kLocalizedStrings[] = { - {"add", IDS_ADD}, - {"advancedPageTitle", IDS_SETTINGS_ADVANCED}, - {"back", IDS_ACCNAME_BACK}, - {"basicPageTitle", IDS_SETTINGS_BASIC}, - {"cancel", IDS_CANCEL}, - {"clear", IDS_SETTINGS_CLEAR}, - {"close", IDS_CLOSE}, - {"confirm", IDS_CONFIRM}, - {"continue", IDS_SETTINGS_CONTINUE}, - {"controlledByExtension", IDS_SETTINGS_CONTROLLED_BY_EXTENSION}, - {"custom", IDS_SETTINGS_CUSTOM}, - {"delete", IDS_SETTINGS_DELETE}, - {"disable", IDS_DISABLE}, - {"done", IDS_DONE}, - {"edit", IDS_SETTINGS_EDIT}, - {"extensionsLinkTooltip", IDS_SETTINGS_MENU_EXTENSIONS_LINK_TOOLTIP}, - {"fonts", IDS_SETTINGS_FONTS}, - {"learnMore", IDS_LEARN_MORE}, - {"manage", IDS_SETTINGS_MANAGE}, - {"menu", IDS_MENU}, - {"menuButtonLabel", IDS_SETTINGS_MENU_BUTTON_LABEL}, - {"moreActions", IDS_SETTINGS_MORE_ACTIONS}, - {"noThanks", IDS_NO_THANKS}, - {"ok", IDS_OK}, - {"opensInNewTab", IDS_SETTINGS_OPENS_IN_NEW_TAB}, - {"sendFeedbackButton", IDS_SETTINGS_SEND_FEEDBACK_ROLE_DESCRIPTION}, + {"add", IDS_ADD}, + {"advancedPageTitle", IDS_SETTINGS_ADVANCED}, + {"back", IDS_ACCNAME_BACK}, + {"basicPageTitle", IDS_SETTINGS_BASIC}, + {"cancel", IDS_CANCEL}, + {"clear", IDS_SETTINGS_CLEAR}, + {"close", IDS_CLOSE}, + {"confirm", IDS_CONFIRM}, + {"continue", IDS_SETTINGS_CONTINUE}, + {"controlledByExtension", IDS_SETTINGS_CONTROLLED_BY_EXTENSION}, + {"custom", IDS_SETTINGS_CUSTOM}, + {"delete", IDS_SETTINGS_DELETE}, + {"disable", IDS_DISABLE}, + {"done", IDS_DONE}, + {"edit", IDS_SETTINGS_EDIT}, + {"extensionsLinkTooltip", IDS_SETTINGS_MENU_EXTENSIONS_LINK_TOOLTIP}, + {"fonts", IDS_SETTINGS_FONTS}, + {"learnMore", IDS_LEARN_MORE}, + {"manage", IDS_SETTINGS_MANAGE}, + {"menu", IDS_MENU}, + {"menuButtonLabel", IDS_SETTINGS_MENU_BUTTON_LABEL}, + {"moreActions", IDS_SETTINGS_MORE_ACTIONS}, + {"noThanks", IDS_NO_THANKS}, + {"ok", IDS_OK}, + {"opensInNewTab", IDS_SETTINGS_OPENS_IN_NEW_TAB}, + {"sendFeedbackButton", IDS_SETTINGS_SEND_FEEDBACK_ROLE_DESCRIPTION}, #if !BUILDFLAG(IS_CHROMEOS_ASH) - {"relaunchConfirmationDialogTitle", IDS_RELAUNCH_CONFIRMATION_DIALOG_TITLE}, + {"relaunchConfirmationDialogTitle", + IDS_RELAUNCH_CONFIRMATION_DIALOG_TITLE}, #endif - {"remove", IDS_REMOVE}, - {"restart", IDS_SETTINGS_RESTART}, - {"restartToApplyChanges", IDS_SETTINGS_RESTART_TO_APPLY_CHANGES}, - {"retry", IDS_SETTINGS_RETRY}, - {"save", IDS_SAVE}, - {"searchResultBubbleText", IDS_SEARCH_RESULT_BUBBLE_TEXT}, - {"searchResultsBubbleText", IDS_SEARCH_RESULTS_BUBBLE_TEXT}, - {"sentenceEnd", IDS_SENTENCE_END}, - {"settings", IDS_SETTINGS_SETTINGS}, - {"settingsAltPageTitle", IDS_SETTINGS_ALT_PAGE_TITLE}, - {"subpageArrowRoleDescription", IDS_SETTINGS_SUBPAGE_BUTTON}, - {"subpageBackButtonAriaLabel", IDS_SETTINGS_SUBPAGE_BACK_BUTTON_ARIA_LABEL}, - {"subpageBackButtonAriaRoleDescription", - IDS_SETTINGS_SUBPAGE_BACK_BUTTON_ARIA_ROLE_DESCRIPTION}, - {"subpageLearnMoreAriaLabel", IDS_SETTINGS_SUBPAGE_LEARN_MORE_ARIA_LABEL}, - {"notValid", IDS_SETTINGS_NOT_VALID}, - {"notValidWebAddress", IDS_SETTINGS_NOT_VALID_WEB_ADDRESS}, - {"notValidWebAddressForContentType", - IDS_SETTINGS_NOT_VALID_WEB_ADDRESS_FOR_CONTENT_TYPE}, + {"remove", IDS_REMOVE}, + {"restart", IDS_SETTINGS_RESTART}, + {"restartToApplyChanges", IDS_SETTINGS_RESTART_TO_APPLY_CHANGES}, + {"retry", IDS_SETTINGS_RETRY}, + {"save", IDS_SAVE}, + {"searchResultBubbleText", IDS_SEARCH_RESULT_BUBBLE_TEXT}, + {"searchResultsBubbleText", IDS_SEARCH_RESULTS_BUBBLE_TEXT}, + {"sentenceEnd", IDS_SENTENCE_END}, + {"settings", IDS_SETTINGS_SETTINGS}, + {"settingsAltPageTitle", IDS_SETTINGS_ALT_PAGE_TITLE}, + {"subpageArrowRoleDescription", IDS_SETTINGS_SUBPAGE_BUTTON}, + {"subpageBackButtonAriaLabel", + IDS_SETTINGS_SUBPAGE_BACK_BUTTON_ARIA_LABEL}, + {"subpageBackButtonAriaRoleDescription", + IDS_SETTINGS_SUBPAGE_BACK_BUTTON_ARIA_ROLE_DESCRIPTION}, + {"subpageLearnMoreAriaLabel", IDS_SETTINGS_SUBPAGE_LEARN_MORE_ARIA_LABEL}, + {"notValid", IDS_SETTINGS_NOT_VALID}, + {"notValidWebAddress", IDS_SETTINGS_NOT_VALID_WEB_ADDRESS}, + {"notValidWebAddressForContentType", + IDS_SETTINGS_NOT_VALID_WEB_ADDRESS_FOR_CONTENT_TYPE}, - // Common font related strings shown in a11y and appearance sections. - {"quickBrownFox", IDS_SETTINGS_QUICK_BROWN_FOX}, - {"verySmall", IDS_SETTINGS_VERY_SMALL_FONT}, - {"small", IDS_SETTINGS_SMALL_FONT}, - {"medium", IDS_SETTINGS_MEDIUM_FONT}, - {"large", IDS_SETTINGS_LARGE_FONT}, - {"veryLarge", IDS_SETTINGS_VERY_LARGE_FONT}, + // Common font related strings shown in a11y and appearance sections. + {"quickBrownFox", IDS_SETTINGS_QUICK_BROWN_FOX}, + {"verySmall", IDS_SETTINGS_VERY_SMALL_FONT}, + {"small", IDS_SETTINGS_SMALL_FONT}, + {"medium", IDS_SETTINGS_MEDIUM_FONT}, + {"large", IDS_SETTINGS_LARGE_FONT}, + {"veryLarge", IDS_SETTINGS_VERY_LARGE_FONT}, }; html_source->AddLocalizedStrings(kLocalizedStrings); @@ -253,7 +255,7 @@ crosapi::mojom::SessionType::kPublicSession || profile->IsGuestSession()); #else - profile->IsGuestSession()); + profile->IsGuestSession()); #endif html_source->AddBoolean("isChildAccount", profile->IsChild()); @@ -273,36 +275,37 @@ void AddA11yStrings(content::WebUIDataSource* html_source) { static constexpr webui::LocalizedString kLocalizedStrings[] = { - {"moreFeaturesLink", IDS_SETTINGS_MORE_FEATURES_LINK}, - {"a11yPageTitle", IDS_SETTINGS_ACCESSIBILITY}, - {"a11yWebStore", IDS_SETTINGS_ACCESSIBILITY_WEB_STORE}, - {"moreFeaturesLinkDescription", - IDS_SETTINGS_MORE_FEATURES_LINK_DESCRIPTION}, - {"accessibleImageLabelsTitle", IDS_SETTINGS_ACCESSIBLE_IMAGE_LABELS_TITLE}, - {"accessibleImageLabelsSubtitle", - IDS_SETTINGS_ACCESSIBLE_IMAGE_LABELS_SUBTITLE}, - {"settingsSliderRoleDescription", - IDS_SETTINGS_SLIDER_MIN_MAX_ARIA_ROLE_DESCRIPTION}, - {"caretBrowsingTitle", IDS_SETTINGS_ENABLE_CARET_BROWSING_TITLE}, - {"caretBrowsingSubtitle", IDS_SETTINGS_ENABLE_CARET_BROWSING_SUBTITLE}, + {"moreFeaturesLink", IDS_SETTINGS_MORE_FEATURES_LINK}, + {"a11yPageTitle", IDS_SETTINGS_ACCESSIBILITY}, + {"a11yWebStore", IDS_SETTINGS_ACCESSIBILITY_WEB_STORE}, + {"moreFeaturesLinkDescription", + IDS_SETTINGS_MORE_FEATURES_LINK_DESCRIPTION}, + {"accessibleImageLabelsTitle", + IDS_SETTINGS_ACCESSIBLE_IMAGE_LABELS_TITLE}, + {"accessibleImageLabelsSubtitle", + IDS_SETTINGS_ACCESSIBLE_IMAGE_LABELS_SUBTITLE}, + {"settingsSliderRoleDescription", + IDS_SETTINGS_SLIDER_MIN_MAX_ARIA_ROLE_DESCRIPTION}, + {"caretBrowsingTitle", IDS_SETTINGS_ENABLE_CARET_BROWSING_TITLE}, + {"caretBrowsingSubtitle", IDS_SETTINGS_ENABLE_CARET_BROWSING_SUBTITLE}, #if BUILDFLAG(IS_CHROMEOS) - {"manageAccessibilityFeatures", - IDS_SETTINGS_ACCESSIBILITY_MANAGE_ACCESSIBILITY_FEATURES}, + {"manageAccessibilityFeatures", + IDS_SETTINGS_ACCESSIBILITY_MANAGE_ACCESSIBILITY_FEATURES}, #else // !BUILDFLAG(IS_CHROMEOS) - {"focusHighlightLabel", - IDS_SETTINGS_ACCESSIBILITY_FOCUS_HIGHLIGHT_DESCRIPTION}, + {"focusHighlightLabel", + IDS_SETTINGS_ACCESSIBILITY_FOCUS_HIGHLIGHT_DESCRIPTION}, #endif #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) - {"overscrollHistoryNavigationTitle", - IDS_SETTINGS_OVERSCROLL_HISTORY_NAVIGATION_TITLE}, - {"overscrollHistoryNavigationSubtitle", - IDS_SETTINGS_OVERSCROLL_HISTORY_NAVIGATION_SUBTITLE}, - {"pdfOcrDownloadCompleteLabel", IDS_SETTINGS_PDF_OCR_DOWNLOAD_COMPLETE}, - {"pdfOcrDownloadErrorLabel", IDS_SETTINGS_PDF_OCR_DOWNLOAD_ERROR}, - {"pdfOcrDownloadProgressLabel", IDS_SETTINGS_PDF_OCR_DOWNLOAD_PROGRESS}, - {"pdfOcrDownloadingLabel", IDS_SETTINGS_PDF_OCR_DOWNLOADING}, - {"pdfOcrTitle", IDS_SETTINGS_PDF_OCR_TITLE}, - {"pdfOcrSubtitle", IDS_SETTINGS_PDF_OCR_SUBTITLE}, + {"overscrollHistoryNavigationTitle", + IDS_SETTINGS_OVERSCROLL_HISTORY_NAVIGATION_TITLE}, + {"overscrollHistoryNavigationSubtitle", + IDS_SETTINGS_OVERSCROLL_HISTORY_NAVIGATION_SUBTITLE}, + {"pdfOcrDownloadCompleteLabel", IDS_SETTINGS_PDF_OCR_DOWNLOAD_COMPLETE}, + {"pdfOcrDownloadErrorLabel", IDS_SETTINGS_PDF_OCR_DOWNLOAD_ERROR}, + {"pdfOcrDownloadProgressLabel", IDS_SETTINGS_PDF_OCR_DOWNLOAD_PROGRESS}, + {"pdfOcrDownloadingLabel", IDS_SETTINGS_PDF_OCR_DOWNLOADING}, + {"pdfOcrTitle", IDS_SETTINGS_PDF_OCR_TITLE}, + {"pdfOcrSubtitle", IDS_SETTINGS_PDF_OCR_SUBTITLE}, #endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) }; html_source->AddLocalizedStrings(kLocalizedStrings); @@ -330,25 +333,25 @@ void AddAboutStrings(content::WebUIDataSource* html_source, Profile* profile) { // Top level About Page strings. static constexpr webui::LocalizedString kLocalizedStrings[] = { - {"aboutProductLogoAlt", IDS_SHORT_PRODUCT_LOGO_ALT_TEXT}, + {"aboutProductLogoAlt", IDS_SHORT_PRODUCT_LOGO_ALT_TEXT}, #if BUILDFLAG(GOOGLE_CHROME_BRANDING) - {"aboutReportAnIssue", IDS_SETTINGS_ABOUT_PAGE_REPORT_AN_ISSUE}, - {"aboutPrivacyPolicy", IDS_SETTINGS_ABOUT_PAGE_PRIVACY_POLICY}, + {"aboutReportAnIssue", IDS_SETTINGS_ABOUT_PAGE_REPORT_AN_ISSUE}, + {"aboutPrivacyPolicy", IDS_SETTINGS_ABOUT_PAGE_PRIVACY_POLICY}, #endif - {"aboutRelaunch", IDS_SETTINGS_ABOUT_PAGE_RELAUNCH}, - {"aboutUpgradeCheckStarted", IDS_SETTINGS_ABOUT_UPGRADE_CHECK_STARTED}, - {"aboutUpgradeRelaunch", IDS_SETTINGS_UPGRADE_SUCCESSFUL_RELAUNCH}, - {"aboutUpgradeUpdating", IDS_SETTINGS_UPGRADE_UPDATING}, - {"aboutUpgradeUpdatingPercent", IDS_SETTINGS_UPGRADE_UPDATING_PERCENT}, - {"aboutGetHelpUsingChrome", IDS_SETTINGS_GET_HELP_USING_CHROME}, - {"aboutPageTitle", IDS_SETTINGS_ABOUT_PROGRAM}, - {"aboutProductTitle", IDS_PRODUCT_NAME}, - {"aboutLearnMoreUpdatingErrors", - IDS_SETTINGS_ABOUT_PAGE_LEARN_MORE_UPDATE_ERRORS}, - {"aboutLearnMoreSystemRequirements", - IDS_SETTINGS_ABOUT_PAGE_LEARN_MORE_SYSTEM_REQUIREMENTS}, + {"aboutRelaunch", IDS_SETTINGS_ABOUT_PAGE_RELAUNCH}, + {"aboutUpgradeCheckStarted", IDS_SETTINGS_ABOUT_UPGRADE_CHECK_STARTED}, + {"aboutUpgradeRelaunch", IDS_SETTINGS_UPGRADE_SUCCESSFUL_RELAUNCH}, + {"aboutUpgradeUpdating", IDS_SETTINGS_UPGRADE_UPDATING}, + {"aboutUpgradeUpdatingPercent", IDS_SETTINGS_UPGRADE_UPDATING_PERCENT}, + {"aboutGetHelpUsingChrome", IDS_SETTINGS_GET_HELP_USING_CHROME}, + {"aboutPageTitle", IDS_SETTINGS_ABOUT_PROGRAM}, + {"aboutProductTitle", IDS_PRODUCT_NAME}, + {"aboutLearnMoreUpdatingErrors", + IDS_SETTINGS_ABOUT_PAGE_LEARN_MORE_UPDATE_ERRORS}, + {"aboutLearnMoreSystemRequirements", + IDS_SETTINGS_ABOUT_PAGE_LEARN_MORE_SYSTEM_REQUIREMENTS}, #if BUILDFLAG(IS_MAC) - {"aboutLearnMoreUpdating", IDS_SETTINGS_ABOUT_PAGE_LEARN_MORE_UPDATING}, + {"aboutLearnMoreUpdating", IDS_SETTINGS_ABOUT_PAGE_LEARN_MORE_UPDATING}, #endif }; html_source->AddLocalizedStrings(kLocalizedStrings); @@ -406,58 +409,58 @@ void AddAppearanceStrings(content::WebUIDataSource* html_source, Profile* profile) { static constexpr webui::LocalizedString kLocalizedStrings[] = { - {"appearancePageTitle", IDS_SETTINGS_APPEARANCE}, - {"customWebAddress", IDS_SETTINGS_CUSTOM_WEB_ADDRESS}, - {"enterCustomWebAddress", IDS_SETTINGS_ENTER_CUSTOM_WEB_ADDRESS}, - {"homeButtonDisabled", IDS_SETTINGS_HOME_BUTTON_DISABLED}, - {"themes", IDS_SETTINGS_THEMES}, - {"chromeColors", IDS_SETTINGS_CHROME_COLORS}, - {"colorSchemeMode", IDS_SETTINGS_COLOR_SCHEME_MODE}, - {"lightMode", IDS_NTP_CUSTOMIZE_CHROME_COLOR_SCHEME_MODE_LIGHT_LABEL}, - {"darkMode", IDS_NTP_CUSTOMIZE_CHROME_COLOR_SCHEME_MODE_DARK_LABEL}, - {"systemMode", IDS_NTP_CUSTOMIZE_CHROME_COLOR_SCHEME_MODE_SYSTEM_LABEL}, - {"showHomeButton", IDS_SETTINGS_SHOW_HOME_BUTTON}, - {"showBookmarksBar", IDS_SETTINGS_SHOW_BOOKMARKS_BAR}, - {"showHoverCardImages", IDS_SETTINGS_SHOW_HOVER_CARD_IMAGES}, - {"sidePanel", IDS_SETTINGS_SIDE_PANEL}, - {"homePageNtp", IDS_SETTINGS_HOME_PAGE_NTP}, - {"changeHomePage", IDS_SETTINGS_CHANGE_HOME_PAGE}, - {"themesGalleryUrl", IDS_THEMES_GALLERY_URL}, - {"chooseFromWebStore", IDS_SETTINGS_WEB_STORE}, - {"pageZoom", IDS_SETTINGS_PAGE_ZOOM_LABEL}, - {"fontSize", IDS_SETTINGS_FONT_SIZE_LABEL}, - {"customizeFonts", IDS_SETTINGS_CUSTOMIZE_FONTS}, - {"standardFont", IDS_SETTINGS_STANDARD_FONT_LABEL}, - {"serifFont", IDS_SETTINGS_SERIF_FONT_LABEL}, - {"sansSerifFont", IDS_SETTINGS_SANS_SERIF_FONT_LABEL}, - {"fixedWidthFont", IDS_SETTINGS_FIXED_WIDTH_FONT_LABEL}, - {"mathFont", IDS_SETTINGS_MATH_FONT_LABEL}, - {"minimumFont", IDS_SETTINGS_MINIMUM_FONT_SIZE_LABEL}, - {"tiny", IDS_SETTINGS_TINY_FONT_SIZE}, - {"huge", IDS_SETTINGS_HUGE_FONT_SIZE}, - {"sidePanelAlignLeft", IDS_SETTINGS_SIDE_PANEL_ALIGN_LEFT}, - {"sidePanelAlignRight", IDS_SETTINGS_SIDE_PANEL_ALIGN_RIGHT}, + {"appearancePageTitle", IDS_SETTINGS_APPEARANCE}, + {"customWebAddress", IDS_SETTINGS_CUSTOM_WEB_ADDRESS}, + {"enterCustomWebAddress", IDS_SETTINGS_ENTER_CUSTOM_WEB_ADDRESS}, + {"homeButtonDisabled", IDS_SETTINGS_HOME_BUTTON_DISABLED}, + {"themes", IDS_SETTINGS_THEMES}, + {"chromeColors", IDS_SETTINGS_CHROME_COLORS}, + {"colorSchemeMode", IDS_SETTINGS_COLOR_SCHEME_MODE}, + {"lightMode", IDS_NTP_CUSTOMIZE_CHROME_COLOR_SCHEME_MODE_LIGHT_LABEL}, + {"darkMode", IDS_NTP_CUSTOMIZE_CHROME_COLOR_SCHEME_MODE_DARK_LABEL}, + {"systemMode", IDS_NTP_CUSTOMIZE_CHROME_COLOR_SCHEME_MODE_SYSTEM_LABEL}, + {"showHomeButton", IDS_SETTINGS_SHOW_HOME_BUTTON}, + {"showBookmarksBar", IDS_SETTINGS_SHOW_BOOKMARKS_BAR}, + {"showHoverCardImages", IDS_SETTINGS_SHOW_HOVER_CARD_IMAGES}, + {"sidePanel", IDS_SETTINGS_SIDE_PANEL}, + {"homePageNtp", IDS_SETTINGS_HOME_PAGE_NTP}, + {"changeHomePage", IDS_SETTINGS_CHANGE_HOME_PAGE}, + {"themesGalleryUrl", IDS_THEMES_GALLERY_URL}, + {"chooseFromWebStore", IDS_SETTINGS_WEB_STORE}, + {"pageZoom", IDS_SETTINGS_PAGE_ZOOM_LABEL}, + {"fontSize", IDS_SETTINGS_FONT_SIZE_LABEL}, + {"customizeFonts", IDS_SETTINGS_CUSTOMIZE_FONTS}, + {"standardFont", IDS_SETTINGS_STANDARD_FONT_LABEL}, + {"serifFont", IDS_SETTINGS_SERIF_FONT_LABEL}, + {"sansSerifFont", IDS_SETTINGS_SANS_SERIF_FONT_LABEL}, + {"fixedWidthFont", IDS_SETTINGS_FIXED_WIDTH_FONT_LABEL}, + {"mathFont", IDS_SETTINGS_MATH_FONT_LABEL}, + {"minimumFont", IDS_SETTINGS_MINIMUM_FONT_SIZE_LABEL}, + {"tiny", IDS_SETTINGS_TINY_FONT_SIZE}, + {"huge", IDS_SETTINGS_HUGE_FONT_SIZE}, + {"sidePanelAlignLeft", IDS_SETTINGS_SIDE_PANEL_ALIGN_LEFT}, + {"sidePanelAlignRight", IDS_SETTINGS_SIDE_PANEL_ALIGN_RIGHT}, #if BUILDFLAG(IS_LINUX) - {"gtkTheme", IDS_SETTINGS_GTK_THEME}, - {"useGtkTheme", IDS_SETTINGS_USE_GTK_THEME}, - {"qtTheme", IDS_SETTINGS_QT_THEME}, - {"useQtTheme", IDS_SETTINGS_USE_QT_THEME}, - {"classicTheme", IDS_SETTINGS_CLASSIC_THEME}, - {"useClassicTheme", IDS_SETTINGS_USE_CLASSIC_THEME}, + {"gtkTheme", IDS_SETTINGS_GTK_THEME}, + {"useGtkTheme", IDS_SETTINGS_USE_GTK_THEME}, + {"qtTheme", IDS_SETTINGS_QT_THEME}, + {"useQtTheme", IDS_SETTINGS_USE_QT_THEME}, + {"classicTheme", IDS_SETTINGS_CLASSIC_THEME}, + {"useClassicTheme", IDS_SETTINGS_USE_CLASSIC_THEME}, #else - {"resetToDefaultTheme", IDS_SETTINGS_RESET_TO_DEFAULT_THEME}, + {"resetToDefaultTheme", IDS_SETTINGS_RESET_TO_DEFAULT_THEME}, #endif #if BUILDFLAG(IS_LINUX) && !BUILDFLAG(IS_CHROMEOS_LACROS) - {"showWindowDecorations", IDS_SHOW_WINDOW_DECORATIONS}, + {"showWindowDecorations", IDS_SHOW_WINDOW_DECORATIONS}, #endif #if BUILDFLAG(IS_MAC) - {"tabsToLinks", IDS_SETTINGS_TABS_TO_LINKS_PREF}, - {"warnBeforeQuitting", IDS_SETTINGS_WARN_BEFORE_QUITTING_PREF}, + {"tabsToLinks", IDS_SETTINGS_TABS_TO_LINKS_PREF}, + {"warnBeforeQuitting", IDS_SETTINGS_WARN_BEFORE_QUITTING_PREF}, #endif - {"readerMode", IDS_SETTINGS_READER_MODE}, - {"readerModeDescription", IDS_SETTINGS_READER_MODE_DESCRIPTION}, - {"themeManagedDialogTitle", IDS_NTP_THEME_MANAGED_DIALOG_TITLE}, - {"themeManagedDialogBody", IDS_NTP_THEME_MANAGED_DIALOG_BODY}, + {"readerMode", IDS_SETTINGS_READER_MODE}, + {"readerModeDescription", IDS_SETTINGS_READER_MODE_DESCRIPTION}, + {"themeManagedDialogTitle", IDS_NTP_THEME_MANAGED_DIALOG_TITLE}, + {"themeManagedDialogBody", IDS_NTP_THEME_MANAGED_DIALOG_BODY}, }; html_source->AddLocalizedStrings(kLocalizedStrings); @@ -831,83 +834,87 @@ void AddLanguagesStrings(content::WebUIDataSource* html_source, Profile* profile) { static constexpr webui::LocalizedString kLocalizedStrings[] = { - {"languagesPageTitle", IDS_SETTINGS_LANGUAGES_PAGE_TITLE}, + {"languagesPageTitle", IDS_SETTINGS_LANGUAGES_PAGE_TITLE}, #if !BUILDFLAG(IS_CHROMEOS_ASH) - {"languagesCardTitle", IDS_SETTINGS_LANGUAGES_CARD_TITLE}, - {"searchLanguages", IDS_SETTINGS_LANGUAGE_SEARCH}, - {"languagesExpandA11yLabel", - IDS_SETTINGS_LANGUAGES_EXPAND_ACCESSIBILITY_LABEL}, - {"preferredLanguagesDesc", IDS_SETTINGS_LANGUAGES_PREFERRED_LANGUAGES_DESC}, - {"moveToTop", IDS_SETTINGS_LANGUAGES_LANGUAGES_LIST_MOVE_TO_TOP}, - {"moveUp", IDS_SETTINGS_LANGUAGES_LANGUAGES_LIST_MOVE_UP}, - {"moveDown", IDS_SETTINGS_LANGUAGES_LANGUAGES_LIST_MOVE_DOWN}, - {"removeLanguage", IDS_SETTINGS_LANGUAGES_LANGUAGES_LIST_REMOVE}, - {"addLanguages", IDS_SETTINGS_LANGUAGES_LANGUAGES_ADD}, - {"addLanguagesDialogTitle", IDS_SETTINGS_LANGUAGES_MANAGE_LANGUAGES_TITLE}, + {"languagesCardTitle", IDS_SETTINGS_LANGUAGES_CARD_TITLE}, + {"searchLanguages", IDS_SETTINGS_LANGUAGE_SEARCH}, + {"languagesExpandA11yLabel", + IDS_SETTINGS_LANGUAGES_EXPAND_ACCESSIBILITY_LABEL}, + {"preferredLanguagesDesc", + IDS_SETTINGS_LANGUAGES_PREFERRED_LANGUAGES_DESC}, + {"moveToTop", IDS_SETTINGS_LANGUAGES_LANGUAGES_LIST_MOVE_TO_TOP}, + {"moveUp", IDS_SETTINGS_LANGUAGES_LANGUAGES_LIST_MOVE_UP}, + {"moveDown", IDS_SETTINGS_LANGUAGES_LANGUAGES_LIST_MOVE_DOWN}, + {"removeLanguage", IDS_SETTINGS_LANGUAGES_LANGUAGES_LIST_REMOVE}, + {"addLanguages", IDS_SETTINGS_LANGUAGES_LANGUAGES_ADD}, + {"addLanguagesDialogTitle", + IDS_SETTINGS_LANGUAGES_MANAGE_LANGUAGES_TITLE}, #if BUILDFLAG(IS_WIN) - {"isDisplayedInThisLanguage", - IDS_SETTINGS_LANGUAGES_IS_DISPLAYED_IN_THIS_LANGUAGE}, - {"displayInThisLanguage", IDS_SETTINGS_LANGUAGES_DISPLAY_IN_THIS_LANGUAGE}, + {"isDisplayedInThisLanguage", + IDS_SETTINGS_LANGUAGES_IS_DISPLAYED_IN_THIS_LANGUAGE}, + {"displayInThisLanguage", + IDS_SETTINGS_LANGUAGES_DISPLAY_IN_THIS_LANGUAGE}, #endif - {"offerToEnableTranslate", - IDS_SETTINGS_LANGUAGES_OFFER_TO_ENABLE_TRANSLATE}, - {"offerToEnableTranslateSublabel", - IDS_SETTINGS_LANGUAGES_OFFER_TO_ENABLE_TRANSLATE_SUBLABEL}, - {"noLanguagesAdded", IDS_SETTINGS_LANGUAGES_NO_LANGUAGES_ADDED}, - {"addLanguageAriaLabel", IDS_SETTINGS_LANGUAGES_ADD_ARIA_LABEL}, - {"removeAutomaticLanguageAriaLabel", - IDS_SETTINGS_LANGUAGES_REMOVE_AUTOMATIC_ARIA_LABEL}, - {"removeNeverLanguageAriaLabel", - IDS_SETTINGS_LANGUAGES_REMOVE_NEVER_ARIA_LABEL}, - {"translatePageTitle", IDS_SETTINGS_TRANSLATE_PAGE_TITLE}, - {"targetLanguageLabel", IDS_SETTINGS_TARGET_TRANSLATE_LABEL}, - {"automaticallyTranslateLanguages", - IDS_SETTINGS_LANGUAGES_AUTOMATIC_TRANSLATE}, - {"addAutomaticallyTranslateLanguagesAriaLabel", - IDS_SETTINGS_LANGUAGES_AUTOMATIC_TRANSLATE_ADD_ARIA_LABEL}, - {"neverTranslateLanguages", IDS_SETTINGS_LANGUAGES_NEVER_LANGUAGES}, - {"addNeverTranslateLanguagesAriaLabel", - IDS_SETTINGS_LANGUAGES_NEVER_TRANSLATE_ADD_ARIA_LABEL}, - {"translateTargetLabel", IDS_SETTINGS_LANGUAGES_TRANSLATE_TARGET}, - {"spellCheckTitle", IDS_SETTINGS_LANGUAGES_SPELL_CHECK_TITLE}, - {"spellCheckBasicLabel", IDS_SETTINGS_LANGUAGES_SPELL_CHECK_BASIC_LABEL}, - {"spellCheckEnhancedLabel", - IDS_SETTINGS_LANGUAGES_SPELL_CHECK_ENHANCED_LABEL}, - {"spellCheckEnhancedDescription", - IDS_SETTINGS_LANGUAGES_SPELL_CHECK_ENHANCED_DESCRIPTION}, - {"offerToEnableSpellCheck", - IDS_SETTINGS_LANGUAGES_OFFER_TO_ENABLE_SPELL_CHECK}, - // Managed dialog strings: - {"languageManagedDialogTitle", IDS_SETTINGS_LANGUAGES_MANAGED_DIALOG_TITLE}, - {"languageManagedDialogBody", IDS_SETTINGS_LANGUAGES_MANAGED_DIALOG_BODY}, + {"offerToEnableTranslate", + IDS_SETTINGS_LANGUAGES_OFFER_TO_ENABLE_TRANSLATE}, + {"offerToEnableTranslateSublabel", + IDS_SETTINGS_LANGUAGES_OFFER_TO_ENABLE_TRANSLATE_SUBLABEL}, + {"noLanguagesAdded", IDS_SETTINGS_LANGUAGES_NO_LANGUAGES_ADDED}, + {"addLanguageAriaLabel", IDS_SETTINGS_LANGUAGES_ADD_ARIA_LABEL}, + {"removeAutomaticLanguageAriaLabel", + IDS_SETTINGS_LANGUAGES_REMOVE_AUTOMATIC_ARIA_LABEL}, + {"removeNeverLanguageAriaLabel", + IDS_SETTINGS_LANGUAGES_REMOVE_NEVER_ARIA_LABEL}, + {"translatePageTitle", IDS_SETTINGS_TRANSLATE_PAGE_TITLE}, + {"targetLanguageLabel", IDS_SETTINGS_TARGET_TRANSLATE_LABEL}, + {"automaticallyTranslateLanguages", + IDS_SETTINGS_LANGUAGES_AUTOMATIC_TRANSLATE}, + {"addAutomaticallyTranslateLanguagesAriaLabel", + IDS_SETTINGS_LANGUAGES_AUTOMATIC_TRANSLATE_ADD_ARIA_LABEL}, + {"neverTranslateLanguages", IDS_SETTINGS_LANGUAGES_NEVER_LANGUAGES}, + {"addNeverTranslateLanguagesAriaLabel", + IDS_SETTINGS_LANGUAGES_NEVER_TRANSLATE_ADD_ARIA_LABEL}, + {"translateTargetLabel", IDS_SETTINGS_LANGUAGES_TRANSLATE_TARGET}, + {"spellCheckTitle", IDS_SETTINGS_LANGUAGES_SPELL_CHECK_TITLE}, + {"spellCheckBasicLabel", IDS_SETTINGS_LANGUAGES_SPELL_CHECK_BASIC_LABEL}, + {"spellCheckEnhancedLabel", + IDS_SETTINGS_LANGUAGES_SPELL_CHECK_ENHANCED_LABEL}, + {"spellCheckEnhancedDescription", + IDS_SETTINGS_LANGUAGES_SPELL_CHECK_ENHANCED_DESCRIPTION}, + {"offerToEnableSpellCheck", + IDS_SETTINGS_LANGUAGES_OFFER_TO_ENABLE_SPELL_CHECK}, + // Managed dialog strings: + {"languageManagedDialogTitle", + IDS_SETTINGS_LANGUAGES_MANAGED_DIALOG_TITLE}, + {"languageManagedDialogBody", IDS_SETTINGS_LANGUAGES_MANAGED_DIALOG_BODY}, #if !BUILDFLAG(IS_MAC) - {"spellCheckDisabledReason", - IDS_SETTING_LANGUAGES_SPELL_CHECK_DISABLED_REASON}, - {"spellCheckLanguagesListTitle", - IDS_SETTINGS_LANGUAGES_SPELL_CHECK_LANGUAGES_LIST_TITLE}, - {"manageSpellCheck", IDS_SETTINGS_LANGUAGES_SPELL_CHECK_MANAGE}, - {"editDictionaryPageTitle", IDS_SETTINGS_LANGUAGES_EDIT_DICTIONARY_TITLE}, - {"addDictionaryWordLabel", IDS_SETTINGS_LANGUAGES_ADD_DICTIONARY_WORD}, - {"addDictionaryWordButton", - IDS_SETTINGS_LANGUAGES_ADD_DICTIONARY_WORD_BUTTON}, - {"addDictionaryWordDuplicateError", - IDS_SETTINGS_LANGUAGES_ADD_DICTIONARY_WORD_DUPLICATE_ERROR}, - {"addDictionaryWordLengthError", - IDS_SETTINGS_LANGUAGES_ADD_DICTIONARY_WORD_LENGTH_ERROR}, - {"deleteDictionaryWordButton", - IDS_SETTINGS_LANGUAGES_DELETE_DICTIONARY_WORD_BUTTON}, - {"customDictionaryWords", IDS_SETTINGS_LANGUAGES_DICTIONARY_WORDS}, - {"noCustomDictionaryWordsFound", - IDS_SETTINGS_LANGUAGES_DICTIONARY_WORDS_NONE}, - {"languagesDictionaryDownloadError", - IDS_SETTINGS_LANGUAGES_DICTIONARY_DOWNLOAD_FAILED}, - {"languagesDictionaryDownloadErrorHelp", - IDS_SETTINGS_LANGUAGES_DICTIONARY_DOWNLOAD_FAILED_HELP}, + {"spellCheckDisabledReason", + IDS_SETTING_LANGUAGES_SPELL_CHECK_DISABLED_REASON}, + {"spellCheckLanguagesListTitle", + IDS_SETTINGS_LANGUAGES_SPELL_CHECK_LANGUAGES_LIST_TITLE}, + {"manageSpellCheck", IDS_SETTINGS_LANGUAGES_SPELL_CHECK_MANAGE}, + {"editDictionaryPageTitle", IDS_SETTINGS_LANGUAGES_EDIT_DICTIONARY_TITLE}, + {"addDictionaryWordLabel", IDS_SETTINGS_LANGUAGES_ADD_DICTIONARY_WORD}, + {"addDictionaryWordButton", + IDS_SETTINGS_LANGUAGES_ADD_DICTIONARY_WORD_BUTTON}, + {"addDictionaryWordDuplicateError", + IDS_SETTINGS_LANGUAGES_ADD_DICTIONARY_WORD_DUPLICATE_ERROR}, + {"addDictionaryWordLengthError", + IDS_SETTINGS_LANGUAGES_ADD_DICTIONARY_WORD_LENGTH_ERROR}, + {"deleteDictionaryWordButton", + IDS_SETTINGS_LANGUAGES_DELETE_DICTIONARY_WORD_BUTTON}, + {"customDictionaryWords", IDS_SETTINGS_LANGUAGES_DICTIONARY_WORDS}, + {"noCustomDictionaryWordsFound", + IDS_SETTINGS_LANGUAGES_DICTIONARY_WORDS_NONE}, + {"languagesDictionaryDownloadError", + IDS_SETTINGS_LANGUAGES_DICTIONARY_DOWNLOAD_FAILED}, + {"languagesDictionaryDownloadErrorHelp", + IDS_SETTINGS_LANGUAGES_DICTIONARY_DOWNLOAD_FAILED_HELP}, #endif #endif // !BUILDFLAG(IS_CHROMEOS_ASH) #if BUILDFLAG(IS_CHROMEOS_ASH) - {"openChromeOSLanguagesSettingsLabel", - IDS_SETTINGS_LANGUAGES_OPEN_CHROME_OS_SETTINGS_LABEL}, + {"openChromeOSLanguagesSettingsLabel", + IDS_SETTINGS_LANGUAGES_OPEN_CHROME_OS_SETTINGS_LABEL}, #endif }; html_source->AddLocalizedStrings(kLocalizedStrings); @@ -950,13 +957,15 @@ // If |autofill_manager| is not available, then don't show toggle switch. autofill::ContentAutofillDriverFactory* autofill_driver_factory = autofill::ContentAutofillDriverFactory::FromWebContents(web_contents); - if (!autofill_driver_factory) + if (!autofill_driver_factory) { return false; + } autofill::ContentAutofillDriver* autofill_driver = autofill_driver_factory->DriverForFrame( web_contents->GetPrimaryMainFrame()); - if (!autofill_driver) + if (!autofill_driver) { return false; + } // Show the toggle switch only if FIDO authentication is available. Once // returned, this decision may be overridden (from true to false) by the @@ -1186,7 +1195,8 @@ "manageCreditCardsLabel", l10n_util::GetStringFUTF16( IDS_SETTINGS_PAYMENTS_MANAGE_CREDIT_CARDS, - base::UTF8ToUTF16(autofill::payments::GetManageInstrumentsUrl().spec()))); + base::UTF8ToUTF16( + autofill::payments::GetManageInstrumentsUrl().spec()))); html_source->AddString("managePaymentMethodsUrl", autofill::payments::GetManageInstrumentsUrl().spec()); html_source->AddString("addressesAndPaymentMethodsLearnMoreURL", @@ -1372,62 +1382,64 @@ void AddPersonalizationOptionsStrings(content::WebUIDataSource* html_source) { static constexpr webui::LocalizedString kLocalizedStrings[] = { - {"urlKeyedAnonymizedDataCollection", - IDS_SETTINGS_ENABLE_URL_KEYED_ANONYMIZED_DATA_COLLECTION}, - {"urlKeyedAnonymizedDataCollectionDesc", - IDS_SETTINGS_ENABLE_URL_KEYED_ANONYMIZED_DATA_COLLECTION_DESC}, - {"spellingPref", IDS_SETTINGS_SPELLING_PREF}, + {"urlKeyedAnonymizedDataCollection", + IDS_SETTINGS_ENABLE_URL_KEYED_ANONYMIZED_DATA_COLLECTION}, + {"urlKeyedAnonymizedDataCollectionDesc", + IDS_SETTINGS_ENABLE_URL_KEYED_ANONYMIZED_DATA_COLLECTION_DESC}, + {"spellingPref", IDS_SETTINGS_SPELLING_PREF}, #if !BUILDFLAG(IS_CHROMEOS) - {"signinAllowedTitle", IDS_SETTINGS_SIGNIN_ALLOWED}, - {"signinAllowedDescription", IDS_SETTINGS_SIGNIN_ALLOWED_DESC}, + {"signinAllowedTitle", IDS_SETTINGS_SIGNIN_ALLOWED}, + {"signinAllowedDescription", IDS_SETTINGS_SIGNIN_ALLOWED_DESC}, #endif - {"enablePersonalizationLogging", IDS_SETTINGS_ENABLE_LOGGING_PREF}, - {"enablePersonalizationLoggingDesc", IDS_SETTINGS_ENABLE_LOGGING_PREF_DESC}, - {"spellingDescription", IDS_SETTINGS_SPELLING_PREF_DESC}, - {"searchSuggestPrefDesc", IDS_SETTINGS_SUGGEST_PREF_DESC}, - {"linkDoctorPref", IDS_SETTINGS_LINKDOCTOR_PREF}, - {"linkDoctorPrefDesc", IDS_SETTINGS_LINKDOCTOR_PREF_DESC}, - {"searchSuggestPref", IDS_SETTINGS_SUGGEST_PREF}, - {"driveSuggestPref", IDS_SETTINGS_DRIVE_SUGGEST_PREF}, - {"driveSuggestPrefDesc", IDS_SETTINGS_DRIVE_SUGGEST_PREF_DESC}, - {"priceEmailNotificationsPref", IDS_PRICE_TRACKING_SETTINGS_TITLE}, - {"priceEmailNotificationsPrefDesc", - IDS_PRICE_TRACKING_SETTINGS_EMAIL_DESCRIPTION}, - {"pageContentLinkRowSublabelOn", - IDS_SETTINGS_PAGE_CONTENT_LINK_ROW_SUBLABEL_ON}, - {"pageContentLinkRowSublabelOff", - IDS_SETTINGS_PAGE_CONTENT_LINK_ROW_SUBLABEL_OFF}, - {"pageContentPageTitle", IDS_SETTINGS_PAGE_CONTENT_PAGE_TITLE}, - {"pageContentToggleLabel", IDS_SETTINGS_PAGE_CONTENT_TOGGLE_LABEL}, - {"pageContentToggleSublabel", IDS_SETTINGS_PAGE_CONTENT_TOGGLE_SUBLABEL}, - {"pageContentWhenOnBulletOne", - IDS_SETTINGS_PAGE_CONTENT_WHEN_ON_BULLET_ONE}, - {"pageContentThingsToConsiderBulletOne", - IDS_SETTINGS_PAGE_CONTENT_THINGS_TO_CONSIDER_BULLET_ONE}, - {"pageContentThingsToConsiderBulletTwo", - IDS_SETTINGS_PAGE_CONTENT_THINGS_TO_CONSIDER_BULLET_TWO}, - {"pageContentThingsToConsiderBulletThree", - IDS_SETTINGS_PAGE_CONTENT_THINGS_TO_CONSIDER_BULLET_THREE}, + {"enablePersonalizationLogging", IDS_SETTINGS_ENABLE_LOGGING_PREF}, + {"enablePersonalizationLoggingDesc", + IDS_SETTINGS_ENABLE_LOGGING_PREF_DESC}, + {"spellingDescription", IDS_SETTINGS_SPELLING_PREF_DESC}, + {"searchSuggestPrefDesc", IDS_SETTINGS_SUGGEST_PREF_DESC}, + {"linkDoctorPref", IDS_SETTINGS_LINKDOCTOR_PREF}, + {"linkDoctorPrefDesc", IDS_SETTINGS_LINKDOCTOR_PREF_DESC}, + {"searchSuggestPref", IDS_SETTINGS_SUGGEST_PREF}, + {"driveSuggestPref", IDS_SETTINGS_DRIVE_SUGGEST_PREF}, + {"driveSuggestPrefDesc", IDS_SETTINGS_DRIVE_SUGGEST_PREF_DESC}, + {"priceEmailNotificationsPref", IDS_PRICE_TRACKING_SETTINGS_TITLE}, + {"priceEmailNotificationsPrefDesc", + IDS_PRICE_TRACKING_SETTINGS_EMAIL_DESCRIPTION}, + {"pageContentLinkRowSublabelOn", + IDS_SETTINGS_PAGE_CONTENT_LINK_ROW_SUBLABEL_ON}, + {"pageContentLinkRowSublabelOff", + IDS_SETTINGS_PAGE_CONTENT_LINK_ROW_SUBLABEL_OFF}, + {"pageContentPageTitle", IDS_SETTINGS_PAGE_CONTENT_PAGE_TITLE}, + {"pageContentToggleLabel", IDS_SETTINGS_PAGE_CONTENT_TOGGLE_LABEL}, + {"pageContentToggleSublabel", IDS_SETTINGS_PAGE_CONTENT_TOGGLE_SUBLABEL}, + {"pageContentWhenOnBulletOne", + IDS_SETTINGS_PAGE_CONTENT_WHEN_ON_BULLET_ONE}, + {"pageContentThingsToConsiderBulletOne", + IDS_SETTINGS_PAGE_CONTENT_THINGS_TO_CONSIDER_BULLET_ONE}, + {"pageContentThingsToConsiderBulletTwo", + IDS_SETTINGS_PAGE_CONTENT_THINGS_TO_CONSIDER_BULLET_TWO}, + {"pageContentThingsToConsiderBulletThree", + IDS_SETTINGS_PAGE_CONTENT_THINGS_TO_CONSIDER_BULLET_THREE}, }; html_source->AddLocalizedStrings(kLocalizedStrings); } void AddBrowserSyncPageStrings(content::WebUIDataSource* html_source) { static constexpr webui::LocalizedString kLocalizedStrings[] = { - {"peopleSignInSyncPagePromptSecondaryWithAccount", - IDS_SETTINGS_PEOPLE_SIGN_IN_PROMPT_SECONDARY_WITH_ACCOUNT}, - {"peopleSignInSyncPagePromptSecondaryWithNoAccount", - IDS_SETTINGS_PEOPLE_SIGN_IN_PROMPT_SECONDARY_WITH_ACCOUNT}, - {"bookmarksCheckboxLabel", IDS_SETTINGS_BOOKMARKS_CHECKBOX_LABEL}, - {"readingListCheckboxLabel", IDS_SETTINGS_READING_LIST_CHECKBOX_LABEL}, - {"cancelSync", IDS_SETTINGS_SYNC_SETTINGS_CANCEL_SYNC}, - {"syncSetupCancelDialogTitle", IDS_SETTINGS_SYNC_SETUP_CANCEL_DIALOG_TITLE}, - {"syncSetupCancelDialogBody", IDS_SETTINGS_SYNC_SETUP_CANCEL_DIALOG_BODY}, - {"personalizeGoogleServicesTitle", - IDS_SETTINGS_PERSONALIZE_GOOGLE_SERVICES_TITLE}, - {"themeCheckboxLabel", IDS_SETTINGS_THEME_CHECKBOX_LABEL}, + {"peopleSignInSyncPagePromptSecondaryWithAccount", + IDS_SETTINGS_PEOPLE_SIGN_IN_PROMPT_SECONDARY_WITH_ACCOUNT}, + {"peopleSignInSyncPagePromptSecondaryWithNoAccount", + IDS_SETTINGS_PEOPLE_SIGN_IN_PROMPT_SECONDARY_WITH_ACCOUNT}, + {"bookmarksCheckboxLabel", IDS_SETTINGS_BOOKMARKS_CHECKBOX_LABEL}, + {"readingListCheckboxLabel", IDS_SETTINGS_READING_LIST_CHECKBOX_LABEL}, + {"cancelSync", IDS_SETTINGS_SYNC_SETTINGS_CANCEL_SYNC}, + {"syncSetupCancelDialogTitle", + IDS_SETTINGS_SYNC_SETUP_CANCEL_DIALOG_TITLE}, + {"syncSetupCancelDialogBody", IDS_SETTINGS_SYNC_SETUP_CANCEL_DIALOG_BODY}, + {"personalizeGoogleServicesTitle", + IDS_SETTINGS_PERSONALIZE_GOOGLE_SERVICES_TITLE}, + {"themeCheckboxLabel", IDS_SETTINGS_THEME_CHECKBOX_LABEL}, #if BUILDFLAG(IS_CHROMEOS) - {"browserSyncFeatureLabel", IDS_BROWSER_SETTINGS_SYNC_FEATURE_LABEL}, + {"browserSyncFeatureLabel", IDS_BROWSER_SETTINGS_SYNC_FEATURE_LABEL}, #endif }; html_source->AddLocalizedStrings(kLocalizedStrings); @@ -1470,85 +1482,86 @@ void AddSyncControlsStrings(content::WebUIDataSource* html_source) { static constexpr webui::LocalizedString kLocalizedStrings[] = { - {"autofillCheckboxLabel", IDS_SETTINGS_AUTOFILL_CHECKBOX_LABEL}, - {"historyCheckboxLabel", IDS_SETTINGS_HISTORY_CHECKBOX_LABEL}, - {"extensionsCheckboxLabel", IDS_SETTINGS_EXTENSIONS_CHECKBOX_LABEL}, - {"openTabsCheckboxLabel", IDS_SETTINGS_OPEN_TABS_CHECKBOX_LABEL}, - {"savedTabGroupsCheckboxLabel", - IDS_SETTINGS_SAVED_TAB_GROUPS_CHECKBOX_LABEL}, - {"wifiConfigurationsCheckboxLabel", - IDS_SETTINGS_WIFI_CONFIGURATIONS_CHECKBOX_LABEL}, - {"syncEverythingCheckboxLabel", - IDS_SETTINGS_SYNC_EVERYTHING_CHECKBOX_LABEL}, - {"appCheckboxLabel", IDS_SETTINGS_APPS_CHECKBOX_LABEL}, + {"autofillCheckboxLabel", IDS_SETTINGS_AUTOFILL_CHECKBOX_LABEL}, + {"historyCheckboxLabel", IDS_SETTINGS_HISTORY_CHECKBOX_LABEL}, + {"extensionsCheckboxLabel", IDS_SETTINGS_EXTENSIONS_CHECKBOX_LABEL}, + {"openTabsCheckboxLabel", IDS_SETTINGS_OPEN_TABS_CHECKBOX_LABEL}, + {"savedTabGroupsCheckboxLabel", + IDS_SETTINGS_SAVED_TAB_GROUPS_CHECKBOX_LABEL}, + {"wifiConfigurationsCheckboxLabel", + IDS_SETTINGS_WIFI_CONFIGURATIONS_CHECKBOX_LABEL}, + {"syncEverythingCheckboxLabel", + IDS_SETTINGS_SYNC_EVERYTHING_CHECKBOX_LABEL}, + {"appCheckboxLabel", IDS_SETTINGS_APPS_CHECKBOX_LABEL}, #if BUILDFLAG(IS_CHROMEOS_LACROS) - {"appCheckboxSublabel", IDS_SETTINGS_APPS_CHECKBOX_SUBLABEL}, + {"appCheckboxSublabel", IDS_SETTINGS_APPS_CHECKBOX_SUBLABEL}, #endif - {"paymentsCheckboxLabel", IDS_SYNC_DATATYPE_PAYMENTS}, - {"nonPersonalizedServicesSectionLabel", - IDS_SETTINGS_NON_PERSONALIZED_SERVICES_SECTION_LABEL}, - {"customizeSyncLabel", IDS_SETTINGS_CUSTOMIZE_SYNC}, - {"syncData", IDS_SETTINGS_SYNC_DATA}, + {"paymentsCheckboxLabel", IDS_SYNC_DATATYPE_PAYMENTS}, + {"nonPersonalizedServicesSectionLabel", + IDS_SETTINGS_NON_PERSONALIZED_SERVICES_SECTION_LABEL}, + {"customizeSyncLabel", IDS_SETTINGS_CUSTOMIZE_SYNC}, + {"syncData", IDS_SETTINGS_SYNC_DATA}, }; html_source->AddLocalizedStrings(kLocalizedStrings); } void AddPeopleStrings(content::WebUIDataSource* html_source, Profile* profile) { static constexpr webui::LocalizedString kLocalizedStrings[] = { - // Top level people strings: - {"peopleSignInPromptSecondaryWithAccount", - IDS_SETTINGS_PEOPLE_SIGN_IN_PROMPT_SECONDARY_WITH_ACCOUNT}, - {"peopleSignInPromptSecondaryWithNoAccount", - IDS_SETTINGS_PEOPLE_SIGN_IN_PROMPT_SECONDARY_WITH_ACCOUNT}, - {"peoplePageTitle", IDS_SETTINGS_PEOPLE}, - {"syncSettingsSavedToast", IDS_SETTINGS_SYNC_SETTINGS_SAVED_TOAST_LABEL}, - {"peopleSignInPrompt", IDS_SETTINGS_PEOPLE_SIGN_IN_PROMPT}, - {"manageGoogleAccount", IDS_SETTINGS_MANAGE_GOOGLE_ACCOUNT}, - {"syncAndNonPersonalizedServices", - IDS_SETTINGS_SYNC_SYNC_AND_NON_PERSONALIZED_SERVICES}, + // Top level people strings: + {"peopleSignInPromptSecondaryWithAccount", + IDS_SETTINGS_PEOPLE_SIGN_IN_PROMPT_SECONDARY_WITH_ACCOUNT}, + {"peopleSignInPromptSecondaryWithNoAccount", + IDS_SETTINGS_PEOPLE_SIGN_IN_PROMPT_SECONDARY_WITH_ACCOUNT}, + {"peoplePageTitle", IDS_SETTINGS_PEOPLE}, + {"syncSettingsSavedToast", IDS_SETTINGS_SYNC_SETTINGS_SAVED_TOAST_LABEL}, + {"peopleSignInPrompt", IDS_SETTINGS_PEOPLE_SIGN_IN_PROMPT}, + {"manageGoogleAccount", IDS_SETTINGS_MANAGE_GOOGLE_ACCOUNT}, + {"syncAndNonPersonalizedServices", + IDS_SETTINGS_SYNC_SYNC_AND_NON_PERSONALIZED_SERVICES}, #if BUILDFLAG(IS_CHROMEOS_ASH) - {"accountManagerSubMenuLabel", IDS_SETTINGS_ACCOUNT_MANAGER_SUBMENU_LABEL}, + {"accountManagerSubMenuLabel", + IDS_SETTINGS_ACCOUNT_MANAGER_SUBMENU_LABEL}, #else - {"editPerson", IDS_SETTINGS_CUSTOMIZE_PROFILE}, - {"profileNameAndPicture", IDS_SETTINGS_CUSTOMIZE_YOUR_CHROME_PROFILE}, + {"editPerson", IDS_SETTINGS_CUSTOMIZE_PROFILE}, + {"profileNameAndPicture", IDS_SETTINGS_CUSTOMIZE_YOUR_CHROME_PROFILE}, #endif // Manage profile strings: #if !BUILDFLAG(IS_CHROMEOS_ASH) - {"showShortcutLabel", IDS_SETTINGS_PROFILE_SHORTCUT_TOGGLE_LABEL}, - {"nameInputLabel", IDS_SETTINGS_PROFILE_NAME_INPUT_LABEL}, - {"nameYourProfile", IDS_SETTING_NAME_YOUR_PROFILE}, - {"pickThemeColor", IDS_SETTINGS_PICK_A_THEME_COLOR}, - {"pickAvatar", IDS_SETTINGS_PICK_AN_AVATAR}, - {"createShortcutTitle", IDS_SETTINGS_CREATE_SHORTCUT}, - {"createShortcutSubtitle", IDS_SETTINGS_CREATE_SHORTCUT_SUBTITLE}, + {"showShortcutLabel", IDS_SETTINGS_PROFILE_SHORTCUT_TOGGLE_LABEL}, + {"nameInputLabel", IDS_SETTINGS_PROFILE_NAME_INPUT_LABEL}, + {"nameYourProfile", IDS_SETTING_NAME_YOUR_PROFILE}, + {"pickThemeColor", IDS_SETTINGS_PICK_A_THEME_COLOR}, + {"pickAvatar", IDS_SETTINGS_PICK_AN_AVATAR}, + {"createShortcutTitle", IDS_SETTINGS_CREATE_SHORTCUT}, + {"createShortcutSubtitle", IDS_SETTINGS_CREATE_SHORTCUT_SUBTITLE}, - // Color picker strings: - {"colorsContainerLabel", IDS_NTP_THEMES_CONTAINER_LABEL}, - {"colorPickerLabel", IDS_NTP_CUSTOMIZE_COLOR_PICKER_LABEL}, - {"defaultColorName", IDS_NTP_CUSTOMIZE_DEFAULT_LABEL}, - {"defaultThemeLabel", IDS_NTP_CUSTOMIZE_DEFAULT_LABEL}, - {"greyDefaultColorName", IDS_NTP_CUSTOMIZE_GREY_DEFAULT_LABEL}, - {"hueSliderTitle", IDS_NTP_CUSTOMIZE_COLOR_HUE_SLIDER_TITLE}, - {"mainColorName", IDS_NTP_CUSTOMIZE_MAIN_COLOR_LABEL}, - {"managedColorsBody", IDS_NTP_THEME_MANAGED_DIALOG_BODY}, - {"managedColorsTitle", IDS_NTP_THEME_MANAGED_DIALOG_TITLE}, - {"themesContainerLabel", IDS_SETTINGS_PICK_A_THEME_COLOR}, - {"thirdPartyThemeDescription", IDS_NTP_CUSTOMIZE_3PT_THEME_DESC}, - {"uninstallThirdPartyThemeButton", IDS_NTP_CUSTOMIZE_3PT_THEME_UNINSTALL}, + // Color picker strings: + {"colorsContainerLabel", IDS_NTP_THEMES_CONTAINER_LABEL}, + {"colorPickerLabel", IDS_NTP_CUSTOMIZE_COLOR_PICKER_LABEL}, + {"defaultColorName", IDS_NTP_CUSTOMIZE_DEFAULT_LABEL}, + {"defaultThemeLabel", IDS_NTP_CUSTOMIZE_DEFAULT_LABEL}, + {"greyDefaultColorName", IDS_NTP_CUSTOMIZE_GREY_DEFAULT_LABEL}, + {"hueSliderTitle", IDS_NTP_CUSTOMIZE_COLOR_HUE_SLIDER_TITLE}, + {"mainColorName", IDS_NTP_CUSTOMIZE_MAIN_COLOR_LABEL}, + {"managedColorsBody", IDS_NTP_THEME_MANAGED_DIALOG_BODY}, + {"managedColorsTitle", IDS_NTP_THEME_MANAGED_DIALOG_TITLE}, + {"themesContainerLabel", IDS_SETTINGS_PICK_A_THEME_COLOR}, + {"thirdPartyThemeDescription", IDS_NTP_CUSTOMIZE_3PT_THEME_DESC}, + {"uninstallThirdPartyThemeButton", IDS_NTP_CUSTOMIZE_3PT_THEME_UNINSTALL}, - // Managed theme dialog strings: - {"themeManagedDialogTitle", IDS_NTP_THEME_MANAGED_DIALOG_TITLE}, - {"themeManagedDialogBody", IDS_NTP_THEME_MANAGED_DIALOG_BODY}, + // Managed theme dialog strings: + {"themeManagedDialogTitle", IDS_NTP_THEME_MANAGED_DIALOG_TITLE}, + {"themeManagedDialogBody", IDS_NTP_THEME_MANAGED_DIALOG_BODY}, #endif - {"deleteProfileWarningExpandA11yLabel", - IDS_SETTINGS_SYNC_DISCONNECT_EXPAND_ACCESSIBILITY_LABEL}, - {"deleteProfileWarningWithCountsSingular", - IDS_SETTINGS_SYNC_DISCONNECT_DELETE_PROFILE_WARNING_WITH_COUNTS_SINGULAR}, - {"deleteProfileWarningWithCountsPlural", - IDS_SETTINGS_SYNC_DISCONNECT_DELETE_PROFILE_WARNING_WITH_COUNTS_PLURAL}, - {"deleteProfileWarningWithoutCounts", - IDS_SETTINGS_SYNC_DISCONNECT_DELETE_PROFILE_WARNING_WITHOUT_COUNTS}, + {"deleteProfileWarningExpandA11yLabel", + IDS_SETTINGS_SYNC_DISCONNECT_EXPAND_ACCESSIBILITY_LABEL}, + {"deleteProfileWarningWithCountsSingular", + IDS_SETTINGS_SYNC_DISCONNECT_DELETE_PROFILE_WARNING_WITH_COUNTS_SINGULAR}, + {"deleteProfileWarningWithCountsPlural", + IDS_SETTINGS_SYNC_DISCONNECT_DELETE_PROFILE_WARNING_WITH_COUNTS_PLURAL}, + {"deleteProfileWarningWithoutCounts", + IDS_SETTINGS_SYNC_DISCONNECT_DELETE_PROFILE_WARNING_WITHOUT_COUNTS}, }; html_source->AddLocalizedStrings(kLocalizedStrings); @@ -2123,116 +2136,117 @@ void AddPrivacyGuideStrings(content::WebUIDataSource* html_source) { static constexpr webui::LocalizedString kLocalizedStrings[] = { - {"privacyGuideLabel", IDS_SETTINGS_PRIVACY_GUIDE_LABEL}, - {"privacyGuideSublabel", IDS_SETTINGS_PRIVACY_GUIDE_SUBLABEL}, - {"privacyGuidePromoHeader", IDS_SETTINGS_PRIVACY_GUIDE_PROMO_HEADER}, - {"privacyGuidePromoBody", IDS_SETTINGS_PRIVACY_GUIDE_PROMO_BODY}, - {"privacyGuidePromoStartButton", - IDS_SETTINGS_PRIVACY_GUIDE_PROMO_START_BUTTON}, - {"privacyGuideBackToSettingsAriaLabel", - IDS_SETTINGS_PRIVACY_GUIDE_BACK_TO_SETTINGS_ARIA_LABEL}, - {"privacyGuideBackToSettingsAriaRoleDescription", - IDS_SETTINGS_PRIVACY_GUIDE_BACK_TO_SETTINGS_ARIA_ROLE_DESC}, - {"privacyGuideBackButton", IDS_SETTINGS_PRIVACY_GUIDE_BACK_BUTTON}, - {"privacyGuideSteps", IDS_SETTINGS_PRIVACY_GUIDE_STEPS}, - {"privacyGuideNextButton", IDS_SETTINGS_PRIVACY_GUIDE_NEXT_BUTTON}, - {"privacyGuideFeatureDescriptionHeader", - IDS_SETTINGS_PRIVACY_GUIDE_FEATURE_DESCRIPTION_HEADER}, - {"privacyGuideThingsToConsider", - IDS_SETTINGS_PRIVACY_GUIDE_THINGS_TO_CONSIDER}, - {"privacyGuideWelcomeCardHeader", - IDS_SETTINGS_PRIVACY_GUIDE_WELCOME_CARD_HEADER}, - {"privacyGuideWelcomeCardSubHeader", - IDS_SETTINGS_PRIVACY_GUIDE_WELCOME_CARD_SUB_HEADER}, - {"privacyGuideCompletionCardHeader", - IDS_SETTINGS_PRIVACY_GUIDE_COMPLETION_CARD_HEADER}, - {"privacyGuideCompletionCardSubHeader", - IDS_SETTINGS_PRIVACY_GUIDE_COMPLETION_CARD_SUB_HEADER}, - {"privacyGuideCompletionCardSubHeaderNoLinks", - IDS_SETTINGS_PRIVACY_GUIDE_COMPLETION_CARD_SUB_HEADER_NO_LINKS}, - {"privacyGuideCompletionCardLeaveButton", - IDS_SETTINGS_PRIVACY_GUIDE_COMPLETION_CARD_LEAVE_BUTTON}, - {"privacyGuideCompletionCardPrivacySandboxLabel", - IDS_SETTINGS_PRIVACY_GUIDE_COMPLETION_CARD_PRIVACY_SANDBOX_LABEL}, - {"privacyGuideCompletionCardPrivacySandboxSubLabel", - IDS_SETTINGS_PRIVACY_GUIDE_COMPLETION_CARD_PRIVACY_SANDBOX_SUB_LABEL}, - {"privacyGuideCompletionCardWaaLabel", - IDS_SETTINGS_PRIVACY_GUIDE_COMPLETION_CARD_WAA_LABEL}, - {"privacyGuideCompletionCardWaaSubLabel", - IDS_SETTINGS_PRIVACY_GUIDE_COMPLETION_CARD_WAA_SUB_LABEL}, - {"privacyGuideMsbbCardHeader", IDS_SETTINGS_PRIVACY_GUIDE_MSBB_CARD_HEADER}, - {"privacyGuideMsbbFeatureDescription1", - IDS_SETTINGS_PRIVACY_GUIDE_MSBB_FEATURE_DESCRIPTION1}, - {"privacyGuideMsbbFeatureDescription2", - IDS_SETTINGS_PRIVACY_GUIDE_MSBB_FEATURE_DESCRIPTION2}, - {"privacyGuideMsbbFeatureDescription3", - IDS_SETTINGS_PRIVACY_GUIDE_MSBB_FEATURE_DESCRIPTION3}, - {"privacyGuideMsbbPrivacyDescription1", - IDS_SETTINGS_PRIVACY_GUIDE_MSBB_PRIVACY_DESCRIPTION1}, - {"privacyGuideMsbbPrivacyDescription2", - IDS_SETTINGS_PRIVACY_GUIDE_MSBB_PRIVACY_DESCRIPTION2}, - {"privacyGuideHistorySyncCardHeader", - IDS_SETTINGS_PRIVACY_GUIDE_HISTORY_SYNC_CARD_HEADER}, - {"privacyGuideHistorySyncSettingLabel", - IDS_SETTINGS_PRIVACY_GUIDE_HISTORY_SYNC_SETTING_LABEL}, - {"privacyGuideHistorySyncFeatureDescription1", - IDS_SETTINGS_PRIVACY_GUIDE_HISTORY_SYNC_FEATURE_DESCRIPTION1}, - {"privacyGuideHistorySyncFeatureDescription2", - IDS_SETTINGS_PRIVACY_GUIDE_HISTORY_SYNC_FEATURE_DESCRIPTION2}, - {"privacyGuideHistorySyncPrivacyDescription1", - IDS_SETTINGS_PRIVACY_GUIDE_HISTORY_SYNC_PRIVACY_DESCRIPTION1}, - {"privacyGuideCookiesCardHeader", - IDS_SETTINGS_PRIVACY_GUIDE_COOKIES_CARD_HEADER}, - {"privacyGuideCookiesCardBlockTpcIncognitoSubheader", - IDS_SETTINGS_PRIVACY_GUIDE_COOKIES_CARD_BLOCK_TPC_INCOGNITO_SUBHEADER}, - {"privacyGuideCookiesCardBlockTpcIncognitoFeatureDescription1", - IDS_SETTINGS_PRIVACY_GUIDE_COOKIES_CARD_BLOCK_TPC_INCOGNITO_FEATURE_DESCRIPTION1}, - {"privacyGuideCookiesCardBlockTpcIncognitoFeatureDescription2", - IDS_SETTINGS_PRIVACY_GUIDE_COOKIES_CARD_BLOCK_TPC_INCOGNITO_FEATURE_DESCRIPTION2}, - {"privacyGuideCookiesCardBlockTpcIncognitoPrivacyDescription1", - IDS_SETTINGS_PRIVACY_GUIDE_COOKIES_CARD_BLOCK_TPC_INCOGNITO_PRIVACY_DESCRIPTION1}, - {"privacyGuideCookiesCardBlockTpcIncognitoPrivacyDescription2", - IDS_SETTINGS_PRIVACY_GUIDE_COOKIES_CARD_BLOCK_TPC_INCOGNITO_PRIVACY_DESCRIPTION2}, - {"privacyGuideCookiesCardBlockTpcSubheader", - IDS_SETTINGS_PRIVACY_GUIDE_COOKIES_CARD_BLOCK_TPC_SUBHEADER}, - {"privacyGuideCookiesCardBlockTpcFeatureDescription1", - IDS_SETTINGS_PRIVACY_GUIDE_COOKIES_CARD_BLOCK_TPC_FEATURE_DESCRIPTION1}, - {"privacyGuideCookiesCardBlockTpcFeatureDescription2", - IDS_SETTINGS_PRIVACY_GUIDE_COOKIES_CARD_BLOCK_TPC_FEATURE_DESCRIPTION2}, - {"privacyGuideCookiesCardBlockTpcPrivacyDescription1", - IDS_SETTINGS_PRIVACY_GUIDE_COOKIES_CARD_BLOCK_TPC_PRIVACY_DESCRIPTION1}, - {"privacyGuideSafeBrowsingCardHeader", - IDS_SETTINGS_PRIVACY_GUIDE_SAFE_BROWSING_CARD_HEADER}, - {"privacyGuideSafeBrowsingCardEnhancedProtectionPrivacyDescription1", - IDS_SETTINGS_PRIVACY_GUIDE_SAFE_BROWSING_CARD_ENHANCED_PROTECTION_PRIVACY_DESCRIPTION1}, - {"privacyGuideSafeBrowsingCardEnhancedProtectionPrivacyDescription2", - IDS_SETTINGS_PRIVACY_GUIDE_SAFE_BROWSING_CARD_ENHANCED_PROTECTION_PRIVACY_DESCRIPTION2}, - {"privacyGuideSafeBrowsingCardEnhancedProtectionPrivacyDescription3", - IDS_SETTINGS_PRIVACY_GUIDE_SAFE_BROWSING_CARD_ENHANCED_PROTECTION_PRIVACY_DESCRIPTION3}, - {"privacyGuideSafeBrowsingCardStandardProtectionFeatureDescription1", - IDS_SETTINGS_PRIVACY_GUIDE_SAFE_BROWSING_CARD_STANDARD_PROTECTION_FEATURE_DESCRIPTION1}, - {"privacyGuideSafeBrowsingCardStandardProtectionFeatureDescription2", - IDS_SETTINGS_PRIVACY_GUIDE_SAFE_BROWSING_CARD_STANDARD_PROTECTION_FEATURE_DESCRIPTION2}, + {"privacyGuideLabel", IDS_SETTINGS_PRIVACY_GUIDE_LABEL}, + {"privacyGuideSublabel", IDS_SETTINGS_PRIVACY_GUIDE_SUBLABEL}, + {"privacyGuidePromoHeader", IDS_SETTINGS_PRIVACY_GUIDE_PROMO_HEADER}, + {"privacyGuidePromoBody", IDS_SETTINGS_PRIVACY_GUIDE_PROMO_BODY}, + {"privacyGuidePromoStartButton", + IDS_SETTINGS_PRIVACY_GUIDE_PROMO_START_BUTTON}, + {"privacyGuideBackToSettingsAriaLabel", + IDS_SETTINGS_PRIVACY_GUIDE_BACK_TO_SETTINGS_ARIA_LABEL}, + {"privacyGuideBackToSettingsAriaRoleDescription", + IDS_SETTINGS_PRIVACY_GUIDE_BACK_TO_SETTINGS_ARIA_ROLE_DESC}, + {"privacyGuideBackButton", IDS_SETTINGS_PRIVACY_GUIDE_BACK_BUTTON}, + {"privacyGuideSteps", IDS_SETTINGS_PRIVACY_GUIDE_STEPS}, + {"privacyGuideNextButton", IDS_SETTINGS_PRIVACY_GUIDE_NEXT_BUTTON}, + {"privacyGuideFeatureDescriptionHeader", + IDS_SETTINGS_PRIVACY_GUIDE_FEATURE_DESCRIPTION_HEADER}, + {"privacyGuideThingsToConsider", + IDS_SETTINGS_PRIVACY_GUIDE_THINGS_TO_CONSIDER}, + {"privacyGuideWelcomeCardHeader", + IDS_SETTINGS_PRIVACY_GUIDE_WELCOME_CARD_HEADER}, + {"privacyGuideWelcomeCardSubHeader", + IDS_SETTINGS_PRIVACY_GUIDE_WELCOME_CARD_SUB_HEADER}, + {"privacyGuideCompletionCardHeader", + IDS_SETTINGS_PRIVACY_GUIDE_COMPLETION_CARD_HEADER}, + {"privacyGuideCompletionCardSubHeader", + IDS_SETTINGS_PRIVACY_GUIDE_COMPLETION_CARD_SUB_HEADER}, + {"privacyGuideCompletionCardSubHeaderNoLinks", + IDS_SETTINGS_PRIVACY_GUIDE_COMPLETION_CARD_SUB_HEADER_NO_LINKS}, + {"privacyGuideCompletionCardLeaveButton", + IDS_SETTINGS_PRIVACY_GUIDE_COMPLETION_CARD_LEAVE_BUTTON}, + {"privacyGuideCompletionCardPrivacySandboxLabel", + IDS_SETTINGS_PRIVACY_GUIDE_COMPLETION_CARD_PRIVACY_SANDBOX_LABEL}, + {"privacyGuideCompletionCardPrivacySandboxSubLabel", + IDS_SETTINGS_PRIVACY_GUIDE_COMPLETION_CARD_PRIVACY_SANDBOX_SUB_LABEL}, + {"privacyGuideCompletionCardWaaLabel", + IDS_SETTINGS_PRIVACY_GUIDE_COMPLETION_CARD_WAA_LABEL}, + {"privacyGuideCompletionCardWaaSubLabel", + IDS_SETTINGS_PRIVACY_GUIDE_COMPLETION_CARD_WAA_SUB_LABEL}, + {"privacyGuideMsbbCardHeader", + IDS_SETTINGS_PRIVACY_GUIDE_MSBB_CARD_HEADER}, + {"privacyGuideMsbbFeatureDescription1", + IDS_SETTINGS_PRIVACY_GUIDE_MSBB_FEATURE_DESCRIPTION1}, + {"privacyGuideMsbbFeatureDescription2", + IDS_SETTINGS_PRIVACY_GUIDE_MSBB_FEATURE_DESCRIPTION2}, + {"privacyGuideMsbbFeatureDescription3", + IDS_SETTINGS_PRIVACY_GUIDE_MSBB_FEATURE_DESCRIPTION3}, + {"privacyGuideMsbbPrivacyDescription1", + IDS_SETTINGS_PRIVACY_GUIDE_MSBB_PRIVACY_DESCRIPTION1}, + {"privacyGuideMsbbPrivacyDescription2", + IDS_SETTINGS_PRIVACY_GUIDE_MSBB_PRIVACY_DESCRIPTION2}, + {"privacyGuideHistorySyncCardHeader", + IDS_SETTINGS_PRIVACY_GUIDE_HISTORY_SYNC_CARD_HEADER}, + {"privacyGuideHistorySyncSettingLabel", + IDS_SETTINGS_PRIVACY_GUIDE_HISTORY_SYNC_SETTING_LABEL}, + {"privacyGuideHistorySyncFeatureDescription1", + IDS_SETTINGS_PRIVACY_GUIDE_HISTORY_SYNC_FEATURE_DESCRIPTION1}, + {"privacyGuideHistorySyncFeatureDescription2", + IDS_SETTINGS_PRIVACY_GUIDE_HISTORY_SYNC_FEATURE_DESCRIPTION2}, + {"privacyGuideHistorySyncPrivacyDescription1", + IDS_SETTINGS_PRIVACY_GUIDE_HISTORY_SYNC_PRIVACY_DESCRIPTION1}, + {"privacyGuideCookiesCardHeader", + IDS_SETTINGS_PRIVACY_GUIDE_COOKIES_CARD_HEADER}, + {"privacyGuideCookiesCardBlockTpcIncognitoSubheader", + IDS_SETTINGS_PRIVACY_GUIDE_COOKIES_CARD_BLOCK_TPC_INCOGNITO_SUBHEADER}, + {"privacyGuideCookiesCardBlockTpcIncognitoFeatureDescription1", + IDS_SETTINGS_PRIVACY_GUIDE_COOKIES_CARD_BLOCK_TPC_INCOGNITO_FEATURE_DESCRIPTION1}, + {"privacyGuideCookiesCardBlockTpcIncognitoFeatureDescription2", + IDS_SETTINGS_PRIVACY_GUIDE_COOKIES_CARD_BLOCK_TPC_INCOGNITO_FEATURE_DESCRIPTION2}, + {"privacyGuideCookiesCardBlockTpcIncognitoPrivacyDescription1", + IDS_SETTINGS_PRIVACY_GUIDE_COOKIES_CARD_BLOCK_TPC_INCOGNITO_PRIVACY_DESCRIPTION1}, + {"privacyGuideCookiesCardBlockTpcIncognitoPrivacyDescription2", + IDS_SETTINGS_PRIVACY_GUIDE_COOKIES_CARD_BLOCK_TPC_INCOGNITO_PRIVACY_DESCRIPTION2}, + {"privacyGuideCookiesCardBlockTpcSubheader", + IDS_SETTINGS_PRIVACY_GUIDE_COOKIES_CARD_BLOCK_TPC_SUBHEADER}, + {"privacyGuideCookiesCardBlockTpcFeatureDescription1", + IDS_SETTINGS_PRIVACY_GUIDE_COOKIES_CARD_BLOCK_TPC_FEATURE_DESCRIPTION1}, + {"privacyGuideCookiesCardBlockTpcFeatureDescription2", + IDS_SETTINGS_PRIVACY_GUIDE_COOKIES_CARD_BLOCK_TPC_FEATURE_DESCRIPTION2}, + {"privacyGuideCookiesCardBlockTpcPrivacyDescription1", + IDS_SETTINGS_PRIVACY_GUIDE_COOKIES_CARD_BLOCK_TPC_PRIVACY_DESCRIPTION1}, + {"privacyGuideSafeBrowsingCardHeader", + IDS_SETTINGS_PRIVACY_GUIDE_SAFE_BROWSING_CARD_HEADER}, + {"privacyGuideSafeBrowsingCardEnhancedProtectionPrivacyDescription1", + IDS_SETTINGS_PRIVACY_GUIDE_SAFE_BROWSING_CARD_ENHANCED_PROTECTION_PRIVACY_DESCRIPTION1}, + {"privacyGuideSafeBrowsingCardEnhancedProtectionPrivacyDescription2", + IDS_SETTINGS_PRIVACY_GUIDE_SAFE_BROWSING_CARD_ENHANCED_PROTECTION_PRIVACY_DESCRIPTION2}, + {"privacyGuideSafeBrowsingCardEnhancedProtectionPrivacyDescription3", + IDS_SETTINGS_PRIVACY_GUIDE_SAFE_BROWSING_CARD_ENHANCED_PROTECTION_PRIVACY_DESCRIPTION3}, + {"privacyGuideSafeBrowsingCardStandardProtectionFeatureDescription1", + IDS_SETTINGS_PRIVACY_GUIDE_SAFE_BROWSING_CARD_STANDARD_PROTECTION_FEATURE_DESCRIPTION1}, + {"privacyGuideSafeBrowsingCardStandardProtectionFeatureDescription2", + IDS_SETTINGS_PRIVACY_GUIDE_SAFE_BROWSING_CARD_STANDARD_PROTECTION_FEATURE_DESCRIPTION2}, #if BUILDFLAG(GOOGLE_CHROME_BRANDING) - {"privacyGuideSafeBrowsingCardStandardProtectionFeatureDescription2Proxy", - IDS_SETTINGS_PRIVACY_GUIDE_SAFE_BROWSING_CARD_STANDARD_PROTECTION_FEATURE_DESCRIPTION2_PROXY}, + {"privacyGuideSafeBrowsingCardStandardProtectionFeatureDescription2Proxy", + IDS_SETTINGS_PRIVACY_GUIDE_SAFE_BROWSING_CARD_STANDARD_PROTECTION_FEATURE_DESCRIPTION2_PROXY}, #endif - {"privacyGuideSafeBrowsingCardStandardProtectionPrivacyDescription1", - IDS_SETTINGS_PRIVACY_GUIDE_SAFE_BROWSING_CARD_STANDARD_PROTECTION_PRIVACY_DESCRIPTION1}, + {"privacyGuideSafeBrowsingCardStandardProtectionPrivacyDescription1", + IDS_SETTINGS_PRIVACY_GUIDE_SAFE_BROWSING_CARD_STANDARD_PROTECTION_PRIVACY_DESCRIPTION1}, #if BUILDFLAG(GOOGLE_CHROME_BRANDING) - {"privacyGuideSafeBrowsingCardStandardProtectionPrivacyDescription1Proxy", - IDS_SETTINGS_PRIVACY_GUIDE_SAFE_BROWSING_CARD_STANDARD_PROTECTION_PRIVACY_DESCRIPTION1_PROXY}, + {"privacyGuideSafeBrowsingCardStandardProtectionPrivacyDescription1Proxy", + IDS_SETTINGS_PRIVACY_GUIDE_SAFE_BROWSING_CARD_STANDARD_PROTECTION_PRIVACY_DESCRIPTION1_PROXY}, #endif - {"privacyGuideSearchSuggestionsCardHeader", - IDS_SETTINGS_PRIVACY_GUIDE_SEARCH_SUGGESTIONS_CARD_HEADER}, - {"privacyGuideSearchSuggestionsFeatureDescription1", - IDS_SETTINGS_PRIVACY_GUIDE_SEARCH_SUGGESTIONS_FEATURE_DESCRIPTION1}, - {"privacyGuideSearchSuggestionsPrivacyDescription1", - IDS_SETTINGS_PRIVACY_GUIDE_SEARCH_SUGGESTIONS_PRIVACY_DESCRIPTION1}, - {"privacyGuideSearchSuggestionsPrivacyDescription2", - IDS_SETTINGS_PRIVACY_GUIDE_SEARCH_SUGGESTIONS_PRIVACY_DESCRIPTION2}, - {"privacyGuideSearchSuggestionsPrivacyDescription3", - IDS_SETTINGS_PRIVACY_GUIDE_SEARCH_SUGGESTIONS_PRIVACY_DESCRIPTION3}, + {"privacyGuideSearchSuggestionsCardHeader", + IDS_SETTINGS_PRIVACY_GUIDE_SEARCH_SUGGESTIONS_CARD_HEADER}, + {"privacyGuideSearchSuggestionsFeatureDescription1", + IDS_SETTINGS_PRIVACY_GUIDE_SEARCH_SUGGESTIONS_FEATURE_DESCRIPTION1}, + {"privacyGuideSearchSuggestionsPrivacyDescription1", + IDS_SETTINGS_PRIVACY_GUIDE_SEARCH_SUGGESTIONS_PRIVACY_DESCRIPTION1}, + {"privacyGuideSearchSuggestionsPrivacyDescription2", + IDS_SETTINGS_PRIVACY_GUIDE_SEARCH_SUGGESTIONS_PRIVACY_DESCRIPTION2}, + {"privacyGuideSearchSuggestionsPrivacyDescription3", + IDS_SETTINGS_PRIVACY_GUIDE_SEARCH_SUGGESTIONS_PRIVACY_DESCRIPTION3}, }; html_source->AddLocalizedStrings(kLocalizedStrings); } @@ -2397,21 +2411,22 @@ void AddSearchStrings(content::WebUIDataSource* html_source) { static constexpr webui::LocalizedString kLocalizedStrings[] = { - {"searchEnginesManage", IDS_SETTINGS_SEARCH_MANAGE_SEARCH_ENGINES}, - {"searchEnginesManageSiteSearch", - IDS_SETTINGS_SEARCH_MANAGE_SEARCH_ENGINES_AND_SITE_SEARCH}, - {"searchPageTitle", IDS_SETTINGS_SEARCH}, - {"searchExplanation", IDS_SETTINGS_SEARCH_EXPLANATION}, - {"searchExplanationLearnMoreA11yLabel", - IDS_SETTINGS_SEARCH_EXPLANATION_ACCESSIBILITY_LABEL}, - {"searchEngineChoiceEntryPointSubtitle", - IDS_SEARCH_ENGINE_CHOICE_SETTINGS_ENTRY_POINT_SUBTITLE}, - {"searchEnginesChange", - IDS_SEARCH_ENGINE_CHOICE_SETTINGS_CHANGE_DEFAULT_ENGINE}, - {"searchEnginesSettingsDialogSubtitle", - IDS_SEARCH_ENGINE_CHOICE_SETTINGS_SUBTITLE}, - {"searchEnginesSetAsDefaultButton", IDS_SEARCH_ENGINE_CHOICE_BUTTON_TITLE}, - {"searchEnginesCancelButton", IDS_CANCEL}, + {"searchEnginesManage", IDS_SETTINGS_SEARCH_MANAGE_SEARCH_ENGINES}, + {"searchEnginesManageSiteSearch", + IDS_SETTINGS_SEARCH_MANAGE_SEARCH_ENGINES_AND_SITE_SEARCH}, + {"searchPageTitle", IDS_SETTINGS_SEARCH}, + {"searchExplanation", IDS_SETTINGS_SEARCH_EXPLANATION}, + {"searchExplanationLearnMoreA11yLabel", + IDS_SETTINGS_SEARCH_EXPLANATION_ACCESSIBILITY_LABEL}, + {"searchEngineChoiceEntryPointSubtitle", + IDS_SEARCH_ENGINE_CHOICE_SETTINGS_ENTRY_POINT_SUBTITLE}, + {"searchEnginesChange", + IDS_SEARCH_ENGINE_CHOICE_SETTINGS_CHANGE_DEFAULT_ENGINE}, + {"searchEnginesSettingsDialogSubtitle", + IDS_SEARCH_ENGINE_CHOICE_SETTINGS_SUBTITLE}, + {"searchEnginesSetAsDefaultButton", + IDS_SEARCH_ENGINE_CHOICE_BUTTON_TITLE}, + {"searchEnginesCancelButton", IDS_CANCEL}, }; html_source->AddLocalizedStrings(kLocalizedStrings); @@ -3423,18 +3438,18 @@ #if !BUILDFLAG(IS_CHROMEOS_ASH) void AddSystemStrings(content::WebUIDataSource* html_source) { static constexpr webui::LocalizedString kLocalizedStrings[] = { - {"systemPageTitle", IDS_SETTINGS_SYSTEM}, + {"systemPageTitle", IDS_SETTINGS_SYSTEM}, #if !BUILDFLAG(IS_MAC) && !BUILDFLAG(IS_CHROMEOS_LACROS) - {"backgroundAppsLabel", IDS_SETTINGS_SYSTEM_BACKGROUND_APPS_LABEL}, + {"backgroundAppsLabel", IDS_SETTINGS_SYSTEM_BACKGROUND_APPS_LABEL}, #endif #if !BUILDFLAG(IS_CHROMEOS_LACROS) - {"hardwareAccelerationLabel", - IDS_SETTINGS_SYSTEM_HARDWARE_ACCELERATION_LABEL}, - {"proxySettingsLabel", IDS_SETTINGS_SYSTEM_PROXY_SETTINGS_LABEL}, + {"hardwareAccelerationLabel", + IDS_SETTINGS_SYSTEM_HARDWARE_ACCELERATION_LABEL}, + {"proxySettingsLabel", IDS_SETTINGS_SYSTEM_PROXY_SETTINGS_LABEL}, #endif #if BUILDFLAG(IS_CHROMEOS_LACROS) - {"useAshProxyLabel", IDS_SETTINGS_SYSTEM_USE_ASH_PROXY_LABEL}, - {"usesAshProxyLabel", IDS_SETTINGS_SYSTEM_USES_ASH_PROXY_LABEL}, + {"useAshProxyLabel", IDS_SETTINGS_SYSTEM_USE_ASH_PROXY_LABEL}, + {"usesAshProxyLabel", IDS_SETTINGS_SYSTEM_USES_ASH_PROXY_LABEL}, #endif }; html_source->AddLocalizedStrings(kLocalizedStrings);
diff --git a/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_ui.cc b/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_ui.cc index f41ec4e..d0e0b5f8 100644 --- a/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_ui.cc +++ b/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_ui.cc
@@ -108,6 +108,9 @@ {"defaultColorName", IDS_NTP_CUSTOMIZE_DEFAULT_LABEL}, {"greyDefaultColorName", IDS_NTP_CUSTOMIZE_GREY_DEFAULT_LABEL}, {"hueSliderTitle", IDS_NTP_CUSTOMIZE_COLOR_HUE_SLIDER_TITLE}, + {"hueSliderDeleteTitle", IDS_NTP_CUSTOMIZE_COLOR_HUE_SLIDER_DELETE_TITLE}, + {"hueSliderDeleteA11yLabel", + IDS_NTP_CUSTOMIZE_COLOR_HUE_SLIDER_DELETE_A11Y_LABEL}, {"mainColorName", IDS_NTP_CUSTOMIZE_MAIN_COLOR_LABEL}, {"managedColorsTitle", IDS_NTP_THEME_MANAGED_DIALOG_TITLE}, {"managedColorsBody", IDS_NTP_THEME_MANAGED_DIALOG_BODY}, @@ -162,8 +165,6 @@ IDS_NTP_WALLPAPER_SEARCH_REQUEST_THROTTLED_TITLE}, {"tryAgain", IDS_NTP_WALLPAPER_SEARCH_TRY_AGAIN_CTA}, {"wallpaperSearchHistoryHeader", IDS_NTP_WALLPAPER_SEARCH_HISTORY_HEADER}, - {"wallpaperSearchHistoryTileTitle", - IDS_NTP_WALLPAPER_SEARCH_HISTORY_TILE_TITLE}, {"wallpaperSearchMoodLabel", IDS_NTP_WALLPAPER_SEARCH_MOOD_LABEL}, {"wallpaperSearchMoodDefaultOptionLabel", IDS_NTP_WALLPAPER_SEARCH_MOOD_DEFAULT_OPTION_LABEL}, @@ -194,7 +195,17 @@ {"wallpaperSearchLoadingA11yMessage", IDS_NTP_WALLPAPER_SEARCH_LOADING_A11Y_MESSAGE}, {"wallpaperSearchSuccessA11yMessage", - IDS_NTP_WALLPAPER_SEARCH_SUCCESS_A11Y_MESSAGE}}; + IDS_NTP_WALLPAPER_SEARCH_SUCCESS_A11Y_MESSAGE}, + {"wallpaperSearchHistoryResultLabelNoDescriptor", + IDS_NTP_WALLPAPER_SEARCH_HISTORY_RESULT_LABEL_NO_DESCRIPTOR}, + {"wallpaperSearchHistoryResultLabel", + IDS_NTP_WALLPAPER_SEARCH_HISTORY_RESULT_LABEL}, + {"wallpaperSearchHistoryResultLabelB", + IDS_NTP_WALLPAPER_SEARCH_HISTORY_RESULT_LABEL_WITH_DESCRIPTOR_B}, + {"wallpaperSearchHistoryResultLabelC", + IDS_NTP_WALLPAPER_SEARCH_HISTORY_RESULT_LABEL_WITH_DESCRIPTOR_C}, + {"wallpaperSearchHistoryResultLabelBC", + IDS_NTP_WALLPAPER_SEARCH_HISTORY_RESULT_LABEL_WITH_DESCRIPTORS_B_AND_C}}; source->AddLocalizedStrings(kLocalizedStrings); source->AddBoolean(
diff --git a/chrome/browser/ui/webui/side_panel/customize_chrome/wallpaper_search/wallpaper_search.mojom b/chrome/browser/ui/webui/side_panel/customize_chrome/wallpaper_search/wallpaper_search.mojom index 80165cb..58c5144 100644 --- a/chrome/browser/ui/webui/side_panel/customize_chrome/wallpaper_search/wallpaper_search.mojom +++ b/chrome/browser/ui/webui/side_panel/customize_chrome/wallpaper_search/wallpaper_search.mojom
@@ -7,21 +7,28 @@ import "mojo/public/mojom/base/token.mojom"; import "skia/public/mojom/skcolor.mojom"; +// Subject descriptor. Each one is a category of subjects and its +// list of possible values. struct DescriptorA { string category; array<string> labels; }; +// Style descriptor value, which includes a label and an image. struct DescriptorB { string label; string image_path; }; +// Color descriptor value of either SkColor or hue. +// Hue is for custom colors and SkColor is for default colors. union DescriptorDValue { skia.mojom.SkColor color; float hue; }; +// Full list of possible subject, style, and mood descriptors for the +// dropdowns in the Wallpaper Search UI. struct Descriptors { array<DescriptorA> descriptor_a; array<DescriptorB> descriptor_b; @@ -31,6 +38,16 @@ struct WallpaperSearchResult { mojo_base.mojom.Token id; string image; + ResultDescriptors? descriptors; +}; + +// A set of descriptors related to a single wallpaper search result or A +// set of wallpaper search results. +struct ResultDescriptors { + string? subject; + string? style; + string? mood; + DescriptorDValue? color; }; // Must match |NtpWallpaperSearchError| in enums.xml, since this is used @@ -78,13 +95,14 @@ // Sets the history image identified by `result_id` as the current background // image. - SetBackgroundToHistoryImage(mojo_base.mojom.Token result_id); + SetBackgroundToHistoryImage(mojo_base.mojom.Token result_id, + ResultDescriptors descriptors); // Sets wallpaper search result identified by `result_id` to background image. // `time` is Unix epoch time stamp of when the user selected the respective // preview. SetBackgroundToWallpaperSearchResult(mojo_base.mojom.Token result_id, - double time); + double time, ResultDescriptors descriptors); // Triggers a call to |WallpaperSearchClient.SetHistory|. UpdateHistory();
diff --git a/chrome/browser/ui/webui/side_panel/customize_chrome/wallpaper_search/wallpaper_search_handler.cc b/chrome/browser/ui/webui/side_panel/customize_chrome/wallpaper_search/wallpaper_search_handler.cc index 93fd617..f3c89c3 100644 --- a/chrome/browser/ui/webui/side_panel/customize_chrome/wallpaper_search/wallpaper_search_handler.cc +++ b/chrome/browser/ui/webui/side_panel/customize_chrome/wallpaper_search/wallpaper_search_handler.cc
@@ -275,7 +275,8 @@ } void WallpaperSearchHandler::SetBackgroundToHistoryImage( - const base::Token& result_id) { + const base::Token& result_id, + side_panel::customize_chrome::mojom::ResultDescriptorsPtr descriptors) { base::ThreadPool::PostTaskAndReplyWithResult( FROM_HERE, {base::TaskPriority::USER_VISIBLE, base::MayBlock()}, base::BindOnce( @@ -283,16 +284,18 @@ profile_->GetPath().AppendASCII( result_id.ToString() + chrome::kChromeUIUntrustedNewTabPageBackgroundFilename)), - base::BindOnce(&WallpaperSearchHandler::DecodeHistoryImage, - weak_ptr_factory_.GetWeakPtr(), - base::BindOnce(&WallpaperSearchHandler::SelectHistoryImage, - weak_ptr_factory_.GetWeakPtr(), result_id, - base::ElapsedTimer()))); + base::BindOnce( + &WallpaperSearchHandler::DecodeHistoryImage, + weak_ptr_factory_.GetWeakPtr(), + base::BindOnce(&WallpaperSearchHandler::SelectHistoryImage, + weak_ptr_factory_.GetWeakPtr(), result_id, + base::ElapsedTimer(), std::move(descriptors)))); } void WallpaperSearchHandler::SetBackgroundToWallpaperSearchResult( const base::Token& result_id, - double time) { + double time, + side_panel::customize_chrome::mojom::ResultDescriptorsPtr descriptors) { CHECK(base::Contains(wallpaper_search_results_, result_id)); auto& [image_quality, render_time, bitmap] = wallpaper_search_results_[result_id]; @@ -305,6 +308,13 @@ } } history_entry_ = std::make_unique<HistoryEntry>(result_id); + history_entry_->subject = descriptors->subject; + if (descriptors->style) { + history_entry_->style = descriptors->style; + } + if (descriptors->mood) { + history_entry_->mood = descriptors->mood; + } wallpaper_search_background_manager_->SelectLocalBackgroundImage( result_id, bitmap, base::ElapsedTimer()); } @@ -324,7 +334,7 @@ base::BindOnce( &ReadFile, profile_->GetPath().AppendASCII( - entry.ToString() + + entry.id.ToString() + chrome::kChromeUIUntrustedNewTabPageBackgroundFilename)), base::BindOnce(&WallpaperSearchHandler::DecodeHistoryImage, weak_ptr_factory_.GetWeakPtr(), @@ -335,7 +345,7 @@ std::move(barrier).Run( std::pair(image.AsBitmap(), id)); }, - barrier, entry))); + barrier, entry.id))); } } @@ -509,7 +519,7 @@ } void WallpaperSearchHandler::OnHistoryDecoded( - std::vector<base::Token> history, + std::vector<HistoryEntry> history, std::vector<std::pair<SkBitmap, base::Token>> results) { std::vector<side_panel::customize_chrome::mojom::WallpaperSearchResultPtr> thumbnails; @@ -518,7 +528,7 @@ // O(n^2) but there should never be more than 6 in each vector. for (const auto& entry : history) { for (auto& [bitmap, id] : results) { - if (entry == id) { + if (entry.id == id) { auto dimensions = CalculateResizeDimensions(bitmap.width(), bitmap.height(), 100); SkBitmap small_bitmap = skia::ImageOperations::Resize( @@ -533,6 +543,17 @@ side_panel::customize_chrome::mojom::WallpaperSearchResult::New(); thumbnail->image = base::Base64Encode(encoded); thumbnail->id = std::move(id); + if (entry.subject) { + thumbnail->descriptors = + side_panel::customize_chrome::mojom::ResultDescriptors::New(); + thumbnail->descriptors->subject = *entry.subject; + if (entry.style) { + thumbnail->descriptors->style = *entry.style; + } + if (entry.mood) { + thumbnail->descriptors->mood = *entry.mood; + } + } thumbnails.push_back(std::move(thumbnail)); } break; @@ -542,10 +563,21 @@ client_->SetHistory(std::move(thumbnails)); } -void WallpaperSearchHandler::SelectHistoryImage(const base::Token& id, - base::ElapsedTimer timer, - const gfx::Image& image) { +void WallpaperSearchHandler::SelectHistoryImage( + const base::Token& id, + base::ElapsedTimer timer, + side_panel::customize_chrome::mojom::ResultDescriptorsPtr descriptors, + const gfx::Image& image) { history_entry_ = std::make_unique<HistoryEntry>(id); + if (descriptors->subject) { + history_entry_->subject = descriptors->subject; + } + if (descriptors->style) { + history_entry_->style = descriptors->style; + } + if (descriptors->mood) { + history_entry_->mood = descriptors->mood; + } wallpaper_search_background_manager_->SelectHistoryImage(id, image, std::move(timer)); }
diff --git a/chrome/browser/ui/webui/side_panel/customize_chrome/wallpaper_search/wallpaper_search_handler.h b/chrome/browser/ui/webui/side_panel/customize_chrome/wallpaper_search/wallpaper_search_handler.h index 7affb55..04c4ade2 100644 --- a/chrome/browser/ui/webui/side_panel/customize_chrome/wallpaper_search/wallpaper_search_handler.h +++ b/chrome/browser/ui/webui/side_panel/customize_chrome/wallpaper_search/wallpaper_search_handler.h
@@ -75,9 +75,15 @@ GetWallpaperSearchResultsCallback callback) override; void SetResultRenderTime(const std::vector<base::Token>& result_ids, double time) override; - void SetBackgroundToHistoryImage(const base::Token& result_id) override; - void SetBackgroundToWallpaperSearchResult(const base::Token& result_id, - double time) override; + void SetBackgroundToHistoryImage( + const base::Token& result_id, + side_panel::customize_chrome::mojom::ResultDescriptorsPtr descriptors) + override; + void SetBackgroundToWallpaperSearchResult( + const base::Token& result_id, + double time, + side_panel::customize_chrome::mojom::ResultDescriptorsPtr descriptors) + override; void UpdateHistory() override; void SetUserFeedback(side_panel::customize_chrome::mojom::UserFeedback selected_option) override; @@ -96,7 +102,7 @@ std::unique_ptr<std::string> response_body); void OnDescriptorsJsonParsed(GetDescriptorsCallback callback, data_decoder::DataDecoder::ValueOrError result); - void OnHistoryDecoded(std::vector<base::Token> history, + void OnHistoryDecoded(std::vector<HistoryEntry> history, std::vector<std::pair<SkBitmap, base::Token>> results); void OnWallpaperSearchResultsRetrieved( GetWallpaperSearchResultsCallback callback, @@ -109,9 +115,11 @@ std::vector< std::pair<optimization_guide::proto::WallpaperSearchImageQuality*, SkBitmap>> bitmaps); - void SelectHistoryImage(const base::Token& id, - base::ElapsedTimer timer, - const gfx::Image& image); + void SelectHistoryImage( + const base::Token& id, + base::ElapsedTimer timer, + side_panel::customize_chrome::mojom::ResultDescriptorsPtr descriptors, + const gfx::Image& image); raw_ptr<Profile> profile_; PrefChangeRegistrar pref_change_registrar_;
diff --git a/chrome/browser/ui/webui/side_panel/customize_chrome/wallpaper_search/wallpaper_search_handler_unittest.cc b/chrome/browser/ui/webui/side_panel/customize_chrome/wallpaper_search/wallpaper_search_handler_unittest.cc index e93b24f..f11dc221 100644 --- a/chrome/browser/ui/webui/side_panel/customize_chrome/wallpaper_search/wallpaper_search_handler_unittest.cc +++ b/chrome/browser/ui/webui/side_panel/customize_chrome/wallpaper_search/wallpaper_search_handler_unittest.cc
@@ -89,7 +89,7 @@ public: explicit MockWallpaperSearchBackgroundManager(Profile* profile) : WallpaperSearchBackgroundManager(profile) {} - MOCK_METHOD0(GetHistory, std::vector<base::Token>()); + MOCK_METHOD0(GetHistory, std::vector<HistoryEntry>()); MOCK_METHOD3(SelectHistoryImage, void(const base::Token&, const gfx::Image&, @@ -246,8 +246,12 @@ std::string(encoded.begin(), encoded.end())))); // Return test image from WallpaperSearchBackgroundManager::GetHistory(). - std::vector<base::Token> history; - history.push_back(token); + std::vector<HistoryEntry> history; + HistoryEntry history_entry = HistoryEntry(token); + history_entry.subject = "foo"; + history_entry.mood = "bar"; + history_entry.style = "foobar"; + history.push_back(history_entry); ON_CALL(mock_wallpaper_search_background_manager(), GetHistory()) .WillByDefault(testing::Return(history)); @@ -270,6 +274,9 @@ resized_bitmap, /*discard_transparency=*/false, &resized_encoded); EXPECT_EQ(history_images[0]->image, base::Base64Encode(resized_encoded)); EXPECT_EQ(history_images[0]->id.ToString(), token.ToString()); + EXPECT_EQ(history_images[0]->descriptors->subject, history_entry.subject); + EXPECT_EQ(history_images[0]->descriptors->mood, history_entry.mood); + EXPECT_EQ(history_images[0]->descriptors->style, history_entry.style); } TEST_F(WallpaperSearchHandlerTest, @@ -1100,7 +1107,12 @@ SaveCurrentBackgroundToHistory(_)) .WillOnce(MoveArgAndReturn<0>(&history_entry_arg, token)); - handler->SetBackgroundToHistoryImage(token); + side_panel::customize_chrome::mojom::ResultDescriptorsPtr result_descriptors = + side_panel::customize_chrome::mojom::ResultDescriptors::New(); + result_descriptors->subject = "foo"; + result_descriptors->mood = "bar"; + result_descriptors->style = "foobar"; + handler->SetBackgroundToHistoryImage(token, std::move(result_descriptors)); task_environment().RunUntilIdle(); task_environment().AdvanceClock(base::Milliseconds(321)); @@ -1121,6 +1133,9 @@ // Check that the set theme is saved to history on destruction. handler.reset(); EXPECT_EQ(token_arg.ToString(), history_entry_arg.id.ToString()); + EXPECT_EQ("foo", history_entry_arg.subject); + EXPECT_EQ("bar", history_entry_arg.mood); + EXPECT_EQ("foobar", history_entry_arg.style); } TEST_F(WallpaperSearchHandlerTest, SetBackgroundToWallpaperSearchResult) { @@ -1228,9 +1243,14 @@ .WillOnce( DoAll(SaveArg<0>(&token), SaveArg<1>(&bitmap), MoveArg<2>(&timer))); + auto descriptors = + side_panel::customize_chrome::mojom::ResultDescriptors::New(); + descriptors->subject = "foo"; handler->SetBackgroundToWallpaperSearchResult( - images[1]->id, (base::Time::Now() + base::Milliseconds(123)) - .InMillisecondsFSinceUnixEpoch()); + images[1]->id, + (base::Time::Now() + base::Milliseconds(123)) + .InMillisecondsFSinceUnixEpoch(), + std::move(descriptors)); task_environment().AdvanceClock(base::Milliseconds(123)); // Check that the 2nd bitmap was selected by comparing color, since the @@ -1287,6 +1307,7 @@ // Set background saves on destruction. EXPECT_EQ(history_entry_arg.id, token); + EXPECT_EQ("foo", history_entry_arg.subject); } TEST_F(WallpaperSearchHandlerTest, SetUserFeedback) {
diff --git a/chrome/build/android-arm32.pgo.txt b/chrome/build/android-arm32.pgo.txt index 77685c41..548bd99 100644 --- a/chrome/build/android-arm32.pgo.txt +++ b/chrome/build/android-arm32.pgo.txt
@@ -1 +1 @@ -chrome-android32-main-1704801529-f6c8b28e53af17c7f2dbfd7fbc3324dad225b301.profdata +chrome-android32-main-1704823116-46d9da59cab6c9fdc8f6fee5cdeed4b052215860.profdata
diff --git a/chrome/build/android-arm64.pgo.txt b/chrome/build/android-arm64.pgo.txt index a281cfb..ae365138 100644 --- a/chrome/build/android-arm64.pgo.txt +++ b/chrome/build/android-arm64.pgo.txt
@@ -1 +1 @@ -chrome-android64-main-1704801529-aefc601a2f1a203e6a09da3a50367a3e9e3435d1.profdata +chrome-android64-main-1704823116-4da12fdff8cc333a33be8dc1a830de6500f3c09e.profdata
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt index c59db36..10592b9 100644 --- a/chrome/build/linux.pgo.txt +++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@ -chrome-linux-main-1704801529-64e88dc6c209b20543ac5caddeccd0c3861af5dc.profdata +chrome-linux-main-1704823116-d2339317f2327666a71246c36a03121a84c75e92.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt index a490179..53b859a 100644 --- a/chrome/build/win32.pgo.txt +++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@ -chrome-win32-main-1704801529-1d02c6daa1f25a791a9995cff24ca607d0da4164.profdata +chrome-win32-main-1704823116-248465c969595762dcf33890b5382929efff4a2f.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt index f486d91..222462d 100644 --- a/chrome/build/win64.pgo.txt +++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@ -chrome-win64-main-1704801529-fba7705f4788080d70b6b27203577bbee631905d.profdata +chrome-win64-main-1704823116-526eb7f4f62cc5ee2ad9864230ec58d07b6c3d77.profdata
diff --git a/chrome/common/compose/compose.mojom b/chrome/common/compose/compose.mojom index b37ee92..100daea3 100644 --- a/chrome/common/compose/compose.mojom +++ b/chrome/common/compose/compose.mojom
@@ -62,6 +62,8 @@ string result; // Whether undo is possible to a prior state before this response. bool undo_available; + // Whether the response was generated on-device. + bool on_device_evaluation_used; }; // An intermediate compose response, which is available before the final
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h index 5874f564..cd5f069 100644 --- a/chrome/common/pref_names.h +++ b/chrome/common/pref_names.h
@@ -377,6 +377,12 @@ "search.contextual_search_fully_opted_in"; #endif // BUILDFLAG(IS_ANDROID) +#if BUILDFLAG(IS_CHROMEOS) +// Boolean pref recording whether cookie and data would be used only for +// essential purposes. +inline constexpr char kEssentialSearchEnabled[] = "essential_search_enabled"; +#endif // BUILDFLAG(IS_CHROMEOS) + #if BUILDFLAG(IS_MAC) // Boolean that indicates whether the browser should put up a confirmation // window when the user is attempting to quit. Only on Mac.
diff --git a/chrome/renderer/chrome_content_renderer_client.cc b/chrome/renderer/chrome_content_renderer_client.cc index 8d65ad73..d244404 100644 --- a/chrome/renderer/chrome_content_renderer_client.cc +++ b/chrome/renderer/chrome_content_renderer_client.cc
@@ -6,6 +6,7 @@ #include <functional> #include <memory> +#include <string_view> #include <utility> #include "base/check_op.h" @@ -1476,10 +1477,10 @@ return prerender::NoStatePrefetchHelper::IsPrefetching(render_frame); } -uint64_t ChromeContentRendererClient::VisitedLinkHash(const char* canonical_url, - size_t length) { +uint64_t ChromeContentRendererClient::VisitedLinkHash( + std::string_view canonical_url) { return chrome_observer_->visited_link_reader()->ComputeURLFingerprint( - canonical_url, length); + canonical_url); } bool ChromeContentRendererClient::IsLinkVisited(uint64_t link_hash) {
diff --git a/chrome/renderer/chrome_content_renderer_client.h b/chrome/renderer/chrome_content_renderer_client.h index d5bc561..945cf55 100644 --- a/chrome/renderer/chrome_content_renderer_client.h +++ b/chrome/renderer/chrome_content_renderer_client.h
@@ -11,6 +11,7 @@ #include <memory> #include <set> #include <string> +#include <string_view> #include <vector> #include "base/gtest_prod_util.h" @@ -150,7 +151,7 @@ const url::Origin* initiator_origin, GURL* new_url) override; bool IsPrefetchOnly(content::RenderFrame* render_frame) override; - uint64_t VisitedLinkHash(const char* canonical_url, size_t length) override; + uint64_t VisitedLinkHash(std::string_view canonical_url) override; bool IsLinkVisited(uint64_t link_hash) override; std::unique_ptr<blink::WebPrescientNetworking> CreatePrescientNetworking( content::RenderFrame* render_frame) override;
diff --git a/chrome/renderer/safe_browsing/phishing_classifier_browsertest.cc b/chrome/renderer/safe_browsing/phishing_classifier_browsertest.cc index 7766bc3a..1a68f3c0 100644 --- a/chrome/renderer/safe_browsing/phishing_classifier_browsertest.cc +++ b/chrome/renderer/safe_browsing/phishing_classifier_browsertest.cc
@@ -6,6 +6,7 @@ #include <memory> #include <string> +#include <string_view> #include <utility> #include "base/functional/bind.h" @@ -44,7 +45,7 @@ ~TestChromeContentRendererClient() override {} // Since visited_link_reader_ in ChromeContentRenderClient never get // initiated, overrides VisitedLinkedHash() function to prevent crashing. - uint64_t VisitedLinkHash(const char* canonical_url, size_t length) override { + uint64_t VisitedLinkHash(std::string_view canonical_url) override { return 0; } };
diff --git a/chrome/renderer/safe_browsing/phishing_dom_feature_extractor_browsertest.cc b/chrome/renderer/safe_browsing/phishing_dom_feature_extractor_browsertest.cc index 4116066..0563ead5 100644 --- a/chrome/renderer/safe_browsing/phishing_dom_feature_extractor_browsertest.cc +++ b/chrome/renderer/safe_browsing/phishing_dom_feature_extractor_browsertest.cc
@@ -5,6 +5,7 @@ #include "components/safe_browsing/content/renderer/phishing_classifier/phishing_dom_feature_extractor.h" #include <memory> +#include <string_view> #include <unordered_map> #include "base/functional/bind.h" @@ -132,7 +133,7 @@ ~TestChromeContentRendererClient() override {} // Since visited_link_reader_ in ChromeContentRenderClient never get // initiated, overrides VisitedLinkedHash() function to prevent crashing. - uint64_t VisitedLinkHash(const char* canonical_url, size_t length) override { + uint64_t VisitedLinkHash(std::string_view canonical_url) override { return 0; } };
diff --git a/chrome/services/mac_notifications/mac_notification_provider_impl.mm b/chrome/services/mac_notifications/mac_notification_provider_impl.mm index ed54169..e4fd4e4 100644 --- a/chrome/services/mac_notifications/mac_notification_provider_impl.mm +++ b/chrome/services/mac_notifications/mac_notification_provider_impl.mm
@@ -38,9 +38,18 @@ return; } +// MacNotificationServiceNS implements the Chromium interface to the +// NSUserNotificationCenter deprecated API. It is in the process of being +// replaced by UNNotification, above, and warnings about its deprecation are not +// helpful. https://crbug.com/1127306 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + service_ = std::make_unique<MacNotificationServiceNS>( std::move(service), std::move(handler), [NSUserNotificationCenter defaultUserNotificationCenter]); + +#pragma clang diagnostic pop } } // namespace mac_notifications
diff --git a/chrome/services/sharing/nearby/platform/BUILD.gn b/chrome/services/sharing/nearby/platform/BUILD.gn index a546c96..9219a12 100644 --- a/chrome/services/sharing/nearby/platform/BUILD.gn +++ b/chrome/services/sharing/nearby/platform/BUILD.gn
@@ -148,6 +148,8 @@ "//components/prefs:test_support", "//components/sync_preferences:test_support", "//components/user_manager:test_support", + "//device/bluetooth:deprecated_experimental_mojo", + "//device/bluetooth:mocks", "//mojo/public/cpp/bindings", "//services/network/public/mojom", "//testing/gtest",
diff --git a/chrome/services/sharing/nearby/platform/DEPS b/chrome/services/sharing/nearby/platform/DEPS index 936d5a33..7b345370 100644 --- a/chrome/services/sharing/nearby/platform/DEPS +++ b/chrome/services/sharing/nearby/platform/DEPS
@@ -4,7 +4,7 @@ include_rules = [ '+ash/constants/ash_features.h', - '+device/bluetooth/public', + '+device/bluetooth', '+services/network/public', '+third_party/abseil-cpp/absl/strings/string_view.h', '+third_party/abseil-cpp/absl/time/time.h',
diff --git a/chrome/services/sharing/nearby/platform/ble_v2_gatt_client.cc b/chrome/services/sharing/nearby/platform/ble_v2_gatt_client.cc index 6ac7b29..6c5f6fe 100644 --- a/chrome/services/sharing/nearby/platform/ble_v2_gatt_client.cc +++ b/chrome/services/sharing/nearby/platform/ble_v2_gatt_client.cc
@@ -4,13 +4,22 @@ #include "chrome/services/sharing/nearby/platform/ble_v2_gatt_client.h" +#include "base/logging.h" #include "base/notreached.h" namespace nearby::chrome { -BleV2GattClient::BleV2GattClient() = default; +BleV2GattClient::BleV2GattClient( + mojo::PendingRemote<bluetooth::mojom::Device> device) + : remote_device_(std::move(device)) { + // TODO(b/311430390): For now, just tear down the connection on disconnect. In + // the future, this should call Disconnect. + remote_device_.reset_on_disconnect(); +} -BleV2GattClient::~BleV2GattClient() = default; +BleV2GattClient::~BleV2GattClient() { + Disconnect(); +} bool BleV2GattClient::DiscoverServiceAndCharacteristics( const Uuid& service_uuid, @@ -55,8 +64,9 @@ } void BleV2GattClient::Disconnect() { - // TODO(b/311430390): Implement this function. - NOTIMPLEMENTED(); + // TODO(b/311430390): For now, just tear down the connection when we call + // Disconnect. In the future this should clean up state. + remote_device_.reset(); } } // namespace nearby::chrome
diff --git a/chrome/services/sharing/nearby/platform/ble_v2_gatt_client.h b/chrome/services/sharing/nearby/platform/ble_v2_gatt_client.h index 951a9359..01aa40b 100644 --- a/chrome/services/sharing/nearby/platform/ble_v2_gatt_client.h +++ b/chrome/services/sharing/nearby/platform/ble_v2_gatt_client.h
@@ -5,13 +5,17 @@ #ifndef CHROME_SERVICES_SHARING_NEARBY_PLATFORM_BLE_V2_GATT_CLIENT_H_ #define CHROME_SERVICES_SHARING_NEARBY_PLATFORM_BLE_V2_GATT_CLIENT_H_ +#include "device/bluetooth/public/mojom/device.mojom.h" +#include "mojo/public/cpp/bindings/pending_remote.h" +#include "mojo/public/cpp/bindings/remote.h" #include "third_party/nearby/src/internal/platform/implementation/ble_v2.h" namespace nearby::chrome { class BleV2GattClient : public ::nearby::api::ble_v2::GattClient { public: - BleV2GattClient(); + explicit BleV2GattClient( + mojo::PendingRemote<bluetooth::mojom::Device> device); ~BleV2GattClient() override; BleV2GattClient(const BleV2GattClient&) = delete; @@ -36,6 +40,9 @@ absl::AnyInvocable<void(absl::string_view value)> on_characteristic_changed_cb) override; void Disconnect() override; + + private: + mojo::Remote<bluetooth::mojom::Device> remote_device_; }; } // namespace nearby::chrome
diff --git a/chrome/services/sharing/nearby/platform/ble_v2_gatt_client_unittest.cc b/chrome/services/sharing/nearby/platform/ble_v2_gatt_client_unittest.cc index 85c29a34..79a68863 100644 --- a/chrome/services/sharing/nearby/platform/ble_v2_gatt_client_unittest.cc +++ b/chrome/services/sharing/nearby/platform/ble_v2_gatt_client_unittest.cc
@@ -2,12 +2,42 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "chrome/services/sharing/nearby/platform/ble_v2_gatt_client.h" + #include <memory> +#include "base/run_loop.h" #include "base/test/task_environment.h" -#include "chrome/services/sharing/nearby/platform/ble_v2_gatt_client.h" +#include "device/bluetooth/device.h" +#include "device/bluetooth/test/mock_bluetooth_adapter.h" +#include "device/bluetooth/test/mock_bluetooth_device.h" +#include "device/bluetooth/test/mock_bluetooth_gatt_connection.h" +#include "mojo/public/cpp/bindings/pending_remote.h" +#include "mojo/public/cpp/bindings/self_owned_receiver.h" #include "testing/gtest/include/gtest/gtest.h" +namespace { + +const char kTestAddress[] = "11:22:33:44:55:66"; + +class FakeBluetoothDevice + : public testing::NiceMock<device::MockBluetoothDevice> { + public: + FakeBluetoothDevice(device::MockBluetoothAdapter* adapter, + const std::string& address) + : testing::NiceMock<device::MockBluetoothDevice>(adapter, + /*bluetooth_class=*/0u, + /*name=*/"Test Device", + address, + /*paired=*/true, + /*connected=*/true) {} + + FakeBluetoothDevice(const FakeBluetoothDevice&) = delete; + FakeBluetoothDevice& operator=(const FakeBluetoothDevice&) = delete; +}; + +} // namespace + namespace nearby::chrome { class BleV2GattClientTest : public testing::Test { @@ -18,12 +48,43 @@ BleV2GattClientTest& operator=(const BleV2GattClientTest&) = delete; void SetUp() override { - ble_v2_gatt_client_ = std::make_unique<BleV2GattClient>(); + adapter_ = + base::MakeRefCounted<testing::NiceMock<device::MockBluetoothAdapter>>(); + + fake_device_ = + std::make_unique<FakeBluetoothDevice>(adapter_.get(), kTestAddress); + + ON_CALL(*adapter_, GetDevice(kTestAddress)) + .WillByDefault(Return(fake_device_.get())); + + auto connection = std::make_unique< + testing::NiceMock<device::MockBluetoothGattConnection>>(adapter_, + kTestAddress); + + // TODO(b/316395226): We're creating a real Device object here, and relying + // on the underlying MockBluetoothDevice implementation to handle the test + // logic. This is likely to become unwieldy, and we should define and use a + // stubbed FakeDevice class instead. + mojo::PendingRemote<bluetooth::mojom::Device> pending_device; + bluetooth::Device::Create(adapter_, std::move(connection), + pending_device.InitWithNewPipeAndPassReceiver()); + + ble_v2_gatt_client_ = + std::make_unique<BleV2GattClient>(std::move(pending_device)); + } + + void TearDown() override { + ble_v2_gatt_client_->Disconnect(); + + // TODO(b/316395226): Rework to avoid RunUntilIdle(). + base::RunLoop().RunUntilIdle(); } protected: - std::unique_ptr<BleV2GattClient> ble_v2_gatt_client_; base::test::TaskEnvironment task_environment_; + scoped_refptr<testing::NiceMock<device::MockBluetoothAdapter>> adapter_; + std::unique_ptr<FakeBluetoothDevice> fake_device_; + std::unique_ptr<BleV2GattClient> ble_v2_gatt_client_; }; // TODO(b/311430390): Remove this skeleton test once other methods are
diff --git a/chrome/test/base/chromeos/crosier/demo_integration_test.cc b/chrome/test/base/chromeos/crosier/demo_integration_test.cc index 1ba42be..b7658fc6 100644 --- a/chrome/test/base/chromeos/crosier/demo_integration_test.cc +++ b/chrome/test/base/chromeos/crosier/demo_integration_test.cc
@@ -112,13 +112,7 @@ ChromeOSIntegrationTestMixin chromeos_integration_test_mixin_{&mixin_host_}; }; -// TODO(b/313557752): Fix the consistent failures on LACROS. -#if BUILDFLAG(IS_CHROMEOS_LACROS) -#define MAYBE_NewTab DISABLED_NewTab -#else -#define MAYBE_NewTab NewTab -#endif -IN_PROC_BROWSER_TEST_F(DemoIntegrationTest, MAYBE_NewTab) { +IN_PROC_BROWSER_TEST_F(DemoIntegrationTest, NewTab) { chrome_test_base_chromeos_crosier::TestInfo info; info.set_description(R"( This test verifies Chrome can launch and open version page.
diff --git a/chrome/test/data/extensions/api_test/declarative_net_request/dynamic_rules/background.js b/chrome/test/data/extensions/api_test/declarative_net_request/dynamic_rules/background.js index d172887..6625421 100644 --- a/chrome/test/data/extensions/api_test/declarative_net_request/dynamic_rules/background.js +++ b/chrome/test/data/extensions/api_test/declarative_net_request/dynamic_rules/background.js
@@ -116,8 +116,9 @@ async function largeRegexError() { await updateDynamicRules( {addRules: [createLargeRegexRuleWithID(5)]}, - 'Rule with id 5 specified a more complex regex than allowed as part ' + - 'of the "regexFilter" key.'); + 'Rule with id 5 was skipped as the "regexFilter" value exceeded the ' + + '2KB memory limit when compiled. Learn more: ' + + 'https://developer.chrome.com/docs/extensions/reference/api/declarativeNetRequest#regex-rules'); chrome.test.succeed(); },
diff --git a/chrome/test/data/web_apps/page_with_app_title.html b/chrome/test/data/web_apps/page_with_app_title.html new file mode 100644 index 0000000..4a0420706 --- /dev/null +++ b/chrome/test/data/web_apps/page_with_app_title.html
@@ -0,0 +1,10 @@ +<!DOCTYPE html> +<html> +<head> + <title>A Web App</title> + <meta name="app-title" content="AppTitle"> +</head> +<body> + <h1>Content</h1> +</body> +</html> \ No newline at end of file
diff --git a/chrome/test/data/web_apps/page_without_app_title.html b/chrome/test/data/web_apps/page_without_app_title.html new file mode 100644 index 0000000..5d25cda --- /dev/null +++ b/chrome/test/data/web_apps/page_without_app_title.html
@@ -0,0 +1,9 @@ +<!DOCTYPE html> +<html> +<head> + <title>A Web App</title> +</head> +<body> + <h1>Content</h1> +</body> +</html> \ No newline at end of file
diff --git a/chrome/test/data/webui/chromeos/personalization_app/personalization_app_browsertest.cc b/chrome/test/data/webui/chromeos/personalization_app/personalization_app_browsertest.cc index 01fa93f..63ade66 100644 --- a/chrome/test/data/webui/chromeos/personalization_app/personalization_app_browsertest.cc +++ b/chrome/test/data/webui/chromeos/personalization_app/personalization_app_browsertest.cc
@@ -220,7 +220,13 @@ // implementations but with mocked out network handler helper classes. using PersonalizationAppBrowserTest = PersonalizationAppMochaTestBase; -IN_PROC_BROWSER_TEST_F(PersonalizationAppBrowserTest, Main) { +// TODO(crbug.com/1517028): Re-enable this test flakily failing on dbg builds. +#if !defined(NDEBUG) +#define MAYBE_Main DISABLED_Main +#else +#define MAYBE_Main Main +#endif +IN_PROC_BROWSER_TEST_F(PersonalizationAppBrowserTest, MAYBE_Main) { RunTestWithoutTestLoader( "chromeos/personalization_app/personalization_app_test.js", "runMochaSuite('main page')");
diff --git a/chrome/test/data/webui/chromeos/personalization_app/personalization_breadcrumb_element_test.ts b/chrome/test/data/webui/chromeos/personalization_app/personalization_breadcrumb_element_test.ts index b10e9451..3704271 100644 --- a/chrome/test/data/webui/chromeos/personalization_app/personalization_breadcrumb_element_test.ts +++ b/chrome/test/data/webui/chromeos/personalization_app/personalization_breadcrumb_element_test.ts
@@ -437,7 +437,7 @@ assertBreadcrumbs(breadcrumbContainer, [ breadcrumbElement.i18n('wallpaperLabel'), breadcrumbElement.i18n('seaPenLabel'), - 'Airbrushed', + 'Airbrush', ]); const original = PersonalizationRouterElement.instance; @@ -506,7 +506,7 @@ const selectedElement = dropdownMenu.querySelectorAll('button[aria-selected=\'true\']'); assertEquals(1, selectedElement.length); - assertEquals('Airbrushed', (selectedElement[0] as HTMLElement)!.innerText); + assertEquals('Airbrush', (selectedElement[0] as HTMLElement)!.innerText); }); test('navigates with SeaPen dropdown', async () => {
diff --git a/chrome/test/data/webui/compose/compose_app_focus_test.ts b/chrome/test/data/webui/compose/compose_app_focus_test.ts index ec1fb62..2e39f13 100644 --- a/chrome/test/data/webui/compose/compose_app_focus_test.ts +++ b/chrome/test/data/webui/compose/compose_app_focus_test.ts
@@ -33,8 +33,12 @@ function mockResponse( result: string = 'some response', status: ComposeStatus = ComposeStatus.kOk): Promise<void> { - testProxy.remote.responseReceived( - {status: status, undoAvailable: false, result}); + testProxy.remote.responseReceived({ + status: status, + undoAvailable: false, + result, + onDeviceEvaluationUsed: false, + }); return testProxy.remote.$.flushForTesting(); } @@ -122,6 +126,7 @@ status: ComposeStatus.kOk, undoAvailable: true, result: 'here is a result', + onDeviceEvaluationUsed: false, }, }); testProxy.setUndoResponse({ @@ -130,6 +135,7 @@ status: ComposeStatus.kOk, undoAvailable: false, result: 'some undone result', + onDeviceEvaluationUsed: false, }, webuiState: JSON.stringify({ input: 'my old input',
diff --git a/chrome/test/data/webui/compose/compose_app_test.ts b/chrome/test/data/webui/compose/compose_app_test.ts index 4949c12..f5f1bf4 100644 --- a/chrome/test/data/webui/compose/compose_app_test.ts +++ b/chrome/test/data/webui/compose/compose_app_test.ts
@@ -38,9 +38,10 @@ function mockResponse( result: string = 'some response', - status: ComposeStatus = ComposeStatus.kOk): Promise<void> { + status: ComposeStatus = ComposeStatus.kOk, + onDeviceEvaluationUsed = false): Promise<void> { testProxy.remote.responseReceived( - {status: status, undoAvailable: false, result}); + {status: status, undoAvailable: false, result, onDeviceEvaluationUsed}); return testProxy.remote.$.flushForTesting(); } @@ -102,12 +103,21 @@ assertFalse(isVisible(app.$.submitButton)); assertTrue(app.$.textarea.readonly); assertTrue(isVisible(app.$.acceptButton)); + assertFalse(isVisible(app.$.onDeviceUsedFooter)); // Clicking on accept button calls acceptComposeResult. app.$.acceptButton.click(); await testProxy.whenCalled('acceptComposeResult'); }); + test('OnlyOneErrorShows', async () => { + mockInput('x'.repeat(2501)); + app.$.submitButton.click(); + assertTrue(app.$.submitButton.disabled); + assertTrue(isVisible(app.$.textarea.$.tooLongError)); + assertFalse(isVisible(app.$.textarea.$.tooShortError)); + }); + test('AcceptButtonText', async () => { async function initializeNewAppWithTextSelectedState(textSelected: boolean): Promise<ComposeAppElement> { @@ -281,6 +291,7 @@ status: ComposeStatus.kOk, undoAvailable: false, result: 'here is a result', + onDeviceEvaluationUsed: false, }, }); assertTrue(isVisible(appWithResult.$.resultContainer)); @@ -296,6 +307,7 @@ status: ComposeStatus.kOk, undoAvailable: true, result: 'here is a result', + onDeviceEvaluationUsed: false, }, }); assertFalse(appWithUndo.$.undoButton.disabled); @@ -308,6 +320,7 @@ status: ComposeStatus.kOk, undoAvailable: false, result: 'here is a result', + onDeviceEvaluationUsed: false, }, }); assertTrue(isVisible(appWithResultAndLoading.$.loading)); @@ -325,6 +338,7 @@ status: ComposeStatus.kOk, undoAvailable: false, result: 'here is a result', + onDeviceEvaluationUsed: false, }, }); assertTrue(isVisible(appEditingPrompt.$.editTextarea)); @@ -543,6 +557,7 @@ status: ComposeStatus.kOk, undoAvailable: true, result: 'here is a result', + onDeviceEvaluationUsed: false, }, }); testProxy.setUndoResponse({ @@ -551,6 +566,7 @@ status: ComposeStatus.kOk, undoAvailable: false, result: 'some undone result', + onDeviceEvaluationUsed: false, }, webuiState: JSON.stringify({ input: 'my old input', @@ -599,7 +615,9 @@ assertEquals(app.$.partialResultText.innerText.trim(), 'partial response'); // The final response hides the partial response text. - await mockResponse(); + await mockResponse( + 'some response', ComposeStatus.kOk, /*onDeviceEvaluationUsed=*/ true); assertFalse(isVisible(app.$.partialResultText)); + assertTrue(isVisible(app.$.onDeviceUsedFooter)); }); });
diff --git a/chrome/test/data/webui/privacy_sandbox/internals/BUILD.gn b/chrome/test/data/webui/privacy_sandbox/internals/BUILD.gn index d9c33c7..621a485 100644 --- a/chrome/test/data/webui/privacy_sandbox/internals/BUILD.gn +++ b/chrome/test/data/webui/privacy_sandbox/internals/BUILD.gn
@@ -5,7 +5,10 @@ import("../../build_webui_tests.gni") build_webui_tests("build") { - files = [ "privacy_sandbox_internals_test.ts" ] + files = [ + "privacy_sandbox_internals_test.ts", + "content_settings_test.ts", + ] ts_path_mappings = [ "chrome://privacy-sandbox-internals/*|" + rebase_path( "$root_gen_dir/chrome/browser/resources/privacy_sandbox/internals/tsc/*", target_gen_dir) ]
diff --git a/chrome/test/data/webui/privacy_sandbox/internals/content_settings_test.ts b/chrome/test/data/webui/privacy_sandbox/internals/content_settings_test.ts new file mode 100644 index 0000000..4f06a55e --- /dev/null +++ b/chrome/test/data/webui/privacy_sandbox/internals/content_settings_test.ts
@@ -0,0 +1,103 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +import 'chrome://privacy-sandbox-internals/content_setting_pattern_source.js'; + +import {ContentSettingPatternSourceElement} from 'chrome://privacy-sandbox-internals/content_setting_pattern_source.js'; +import {ContentSettingPatternSource, RuleMetaData, SessionModel} from 'chrome://privacy-sandbox-internals/content_settings.mojom-webui.js'; +import {PageHandler, PageHandlerInterface} from 'chrome://privacy-sandbox-internals/privacy_sandbox_internals.mojom-webui.js'; +import {Value} from 'chrome://resources/mojo/mojo/public/mojom/base/values.mojom-webui.js'; +import {assertEquals, assertTrue} from 'chrome://webui-test/chai_assert.js'; + +suite('ContentSettingsElementTest', function() { + let pageHandler: PageHandlerInterface; + + let element: ContentSettingPatternSourceElement; + + suiteSetup(async function() { + await customElements.whenDefined('content-setting-pattern-source'); + }); + + setup(function() { + pageHandler = PageHandler.getRemote(); + document.body.innerHTML = window.trustedTypes!.emptyHTML; + element = document.createElement('content-setting-pattern-source'); + document.body.appendChild(element); + }); + + const buildContentSettingPattern = async( + primaryPattern: string, + secondaryPattern: string): Promise<ContentSettingPatternSource> => { + const cs: ContentSettingPatternSource = {} as ContentSettingPatternSource; + const value: Value = {} as Value; + value.intValue = 0; + cs.settingValue = value; + cs.incognito = true; + + cs.primaryPattern = + (await pageHandler.stringToContentSettingsPattern(primaryPattern)) + .pattern; + cs.secondaryPattern = + (await pageHandler.stringToContentSettingsPattern(secondaryPattern)) + .pattern; + + // TODO(b/308167671): expand test coverage to these fields + const metadata: RuleMetaData = {} as RuleMetaData; + metadata.sessionModel = SessionModel.DURABLE; + metadata.lastModified = { + internalValue: BigInt(0), + }; + metadata.lastUsed = { + internalValue: BigInt(0), + }; + metadata.lastVisited = { + internalValue: BigInt(0), + }; + metadata.expiration = { + internalValue: BigInt(0), + }; + metadata.lifetime = { + microseconds: BigInt(0), + }; + + cs.metadata = metadata; + return cs; + }; + + const getField = (selector: string): Element => { + const field = element.shadowRoot!.querySelector(selector); + assertTrue(!!field); + return field; + }; + + const assertValue = (valueContainer: Element, s: string) => { + const valueElement = valueContainer.children[0]; + assertTrue(!!valueElement); + const span = valueElement.shadowRoot!.querySelector('#value'); + assertTrue(!!span); + assertEquals(span.textContent, s); + }; + + const assertTimestamp = (container: Element, s: string) => { + const mojoTs = container.querySelector('mojo-timestamp'); + assertTrue(!!mojoTs); + assertEquals(mojoTs.getAttribute('ts'), s); + }; + + test('foo', async () => { + const cs = await buildContentSettingPattern( + 'http://google.com', 'https://[*.]example.com:102'); + await element.configure(pageHandler, cs); + assertEquals( + getField('.id-primary-pattern').textContent, 'http://google.com'); + assertEquals( + getField('.id-secondary-pattern').textContent, + 'https://[*.]example.com:102'); + assertValue(getField('.id-incognito'), 'true'); + assertValue(getField('.id-session-model'), '0'); + assertTimestamp(getField('.id-last-modified'), '0'); + assertTimestamp(getField('.id-last-used'), '0'); + assertTimestamp(getField('.id-last-visited'), '0'); + assertTimestamp(getField('.id-expiration'), '0'); + }); +});
diff --git a/chrome/test/data/webui/privacy_sandbox/internals/privacy_sandbox_internals_browsertest.cc b/chrome/test/data/webui/privacy_sandbox/internals/privacy_sandbox_internals_browsertest.cc index 853e29f..87a8264 100644 --- a/chrome/test/data/webui/privacy_sandbox/internals/privacy_sandbox_internals_browsertest.cc +++ b/chrome/test/data/webui/privacy_sandbox/internals/privacy_sandbox_internals_browsertest.cc
@@ -31,4 +31,9 @@ "mocha.run();"); } +IN_PROC_BROWSER_TEST_F(PrivacySandboxInternalsMochaTest, + ContentSettingsCustomElement) { + RunTest("privacy_sandbox/internals/content_settings_test.js", "mocha.run();"); +} + } // namespace
diff --git a/chrome/test/data/webui/side_panel/customize_chrome/wallpaper_search/wallpaper_search_test.ts b/chrome/test/data/webui/side_panel/customize_chrome/wallpaper_search/wallpaper_search_test.ts index 98a0de3..20e1f12a 100644 --- a/chrome/test/data/webui/side_panel/customize_chrome/wallpaper_search/wallpaper_search_test.ts +++ b/chrome/test/data/webui/side_panel/customize_chrome/wallpaper_search/wallpaper_search_test.ts
@@ -171,6 +171,36 @@ checkedMarkedColors[0]!.parentElement!.getAttribute('aria-current'), 'true'); }); + + test('unselects hue', async () => { + createWallpaperSearchElementWithDescriptors(); + await flushTasks(); + assertTrue(wallpaperSearchElement.$.deleteSelectedHueButton.hidden); + + // Select a hue and verify delete button becomes visible. + wallpaperSearchElement.$.hueSlider.selectedHue = 10; + wallpaperSearchElement.$.hueSlider.dispatchEvent( + new Event('selected-hue-changed')); + await flushTasks(); + assertFalse(wallpaperSearchElement.$.deleteSelectedHueButton.hidden); + + // Click on delete button. + wallpaperSearchElement.$.deleteSelectedHueButton.click(); + await flushTasks(); + + // Verify there are no checked colors. + assertEquals( + 0, + wallpaperSearchElement.shadowRoot! + .querySelectorAll('#descriptorMenuD button [checked]') + .length); + + // Verify submitting does not send a hue. + wallpaperSearchElement.$.submitButton.click(); + await flushTasks(); + assertEquals(1, handler.getCallCount('getWallpaperSearchResults')); + assertEquals(null, handler.getArgs('getWallpaperSearchResults')[0][3]); + }); }); suite('Search', () => { @@ -630,7 +660,15 @@ createWallpaperSearchElement(); wallpaperSearchCallbackRouterRemote.setHistory([ - {image: '123', id: {high: BigInt(10), low: BigInt(1)}}, + { + image: '123', + id: {high: BigInt(10), low: BigInt(1)}, + descriptors: { + subject: 'foo', + mood: 'bar', + style: 'foobar', + }, + }, {image: '456', id: {high: BigInt(8), low: BigInt(2)}}, ]); await wallpaperSearchCallbackRouterRemote.$.flushForTesting(); @@ -641,10 +679,12 @@ (historyTile as HTMLElement).click(); assertEquals(1, handler.getCallCount('setBackgroundToHistoryImage')); - assertEquals( - BigInt(10), handler.getArgs('setBackgroundToHistoryImage')[0].high); - assertEquals( - BigInt(1), handler.getArgs('setBackgroundToHistoryImage')[0].low); + const args = handler.getArgs('setBackgroundToHistoryImage'); + assertEquals(BigInt(10), args[0][0].high); + assertEquals(BigInt(1), args[0][0].low); + assertEquals('foo', args[0][1].subject); + assertEquals('bar', args[0][1].mood); + assertEquals('foobar', args[0][1].style); }); test('current history theme is checked', async () => { @@ -687,6 +727,64 @@ checkedResults[0]!.parentElement!.getAttribute('aria-current'), 'true'); }); + + test('labels history', async () => { + loadTimeData.overrideValues({ + 'wallpaperSearchHistoryResultLabelNoDescriptor': 'Image $1', + 'wallpaperSearchHistoryResultLabel': 'Image $1 of $2', + 'wallpaperSearchHistoryResultLabelB': 'Image $1 of $2, $3', + 'wallpaperSearchHistoryResultLabelC': 'Image $1 of $2, $3', + 'wallpaperSearchHistoryResultLabelBC': 'Image $1 of $2, $3, $4', + }); + createWallpaperSearchElement(); + + wallpaperSearchCallbackRouterRemote.setHistory([ + {image: '123', id: {high: BigInt(10), low: BigInt(1)}}, + { + image: '456', + id: {high: BigInt(8), low: BigInt(2)}, + descriptors: { + subject: 'foo', + }, + }, + { + image: '789', + id: {high: BigInt(8), low: BigInt(3)}, + descriptors: { + subject: 'foo', + mood: 'bar', + }, + }, + { + image: '012', + id: {high: BigInt(8), low: BigInt(4)}, + descriptors: { + subject: 'foo', + style: 'foobar', + }, + }, + { + image: '345', + id: {high: BigInt(10), low: BigInt(5)}, + descriptors: { + subject: 'foo', + mood: 'bar', + style: 'foobar', + }, + }, + ]); + await wallpaperSearchCallbackRouterRemote.$.flushForTesting(); + + const historyTiles = + wallpaperSearchElement.$.historyCard.querySelectorAll('.tile.result'); + + assertEquals(historyTiles.length, 5); + assertEquals('Image 1', historyTiles[0]!.ariaLabel); + assertEquals('Image 2 of foo', historyTiles[1]!.ariaLabel); + assertEquals('Image 3 of foo, bar', historyTiles[2]!.ariaLabel); + assertEquals('Image 4 of foo, foobar', historyTiles[3]!.ariaLabel); + assertEquals('Image 5 of foo, foobar, bar', historyTiles[4]!.ariaLabel); + }); }); suite('Error', () => {
diff --git a/chrome/test/variations/test_utils/downloader.py b/chrome/test/variations/test_utils/downloader.py index 464d514a..eec3426 100644 --- a/chrome/test/variations/test_utils/downloader.py +++ b/chrome/test/variations/test_utils/downloader.py
@@ -111,22 +111,6 @@ return chromedriver_path -def download_chromedriver_linux_host(channel: str, version: str) -> str: - """Download the chromedriver that works with the given channel/version.""" - - # Find the same or next version of the given channel and version whose - # chromedriver is compatible with. - # Linux doesn't distribute canary, use dev instead. - if channel == 'canary': - channel = 'dev' - closest_version = find_closest_version( - release_os='linux', channel=channel, version=version) - downloaded_dir = _download_files_from_gcs( - str(closest_version), ['linux64/chromedriver_linux64.zip']) - - return os.path.join(downloaded_dir, "chromedriver_linux64") - - def download_chrome_mac(version: str) -> str: files = ['mac-universal/chrome-mac.zip'] downloaded_dir = _download_files_from_gcs(version, files)
diff --git a/chrome/updater/ipc/update_service_proxy_win.cc b/chrome/updater/ipc/update_service_proxy_win.cc index a59bd31..7ba18e3 100644 --- a/chrome/updater/ipc/update_service_proxy_win.cc +++ b/chrome/updater/ipc/update_service_proxy_win.cc
@@ -318,7 +318,7 @@ static UpdateService::AppState IUpdaterAppStateToAppState( Microsoft::WRL::ComPtr<IUpdaterAppState> updater_app_state) { - DCHECK(updater_app_state); + CHECK(updater_app_state); UpdateService::AppState app_state; {
diff --git a/chrome/updater/test/integration_tests.cc b/chrome/updater/test/integration_tests.cc index e007f61..e142dd69 100644 --- a/chrome/updater/test/integration_tests.cc +++ b/chrome/updater/test/integration_tests.cc
@@ -547,16 +547,15 @@ std::wstring pv; EXPECT_EQ( ERROR_SUCCESS, - base::win::RegKey(UpdaterScopeToHKeyRoot(UpdaterScope::kSystem), + base::win::RegKey(UpdaterScopeToHKeyRoot(GetTestScope()), GetAppClientsKey(appid).c_str(), Wow6432(KEY_READ)) .ReadValue(kRegValuePV, &pv)); EXPECT_EQ(pv, base::ASCIIToWide(expected_version.GetString())); #else - const base::FilePath app_json_path = - GetInstallDirectory(UpdaterScope::kSystem) - ->DirName() - .AppendASCII(appid) - .AppendASCII("app.json"); + const base::FilePath app_json_path = GetInstallDirectory(GetTestScope()) + ->DirName() + .AppendASCII(appid) + .AppendASCII("app.json"); JSONFileValueDeserializer parser(app_json_path, base::JSON_ALLOW_TRAILING_COMMAS); int error_code = 0; @@ -581,8 +580,9 @@ ASSERT_TRUE(base::PathService::Get(base::DIR_EXE, &exe_path)); const base::CommandLine command = app.GetInstallCommandLine(install_v1); VLOG(2) << "Launch app setup command: " << command.GetCommandLineString(); - const base::Process process = - base::LaunchProcess(MakeElevated(command), {}); + const base::Process process = base::LaunchProcess( + IsSystemInstall(GetTestScope()) ? MakeElevated(command) : command, + {}); if (!process.IsValid()) { VLOG(2) << "Failed to launch the app setup command."; } @@ -591,10 +591,9 @@ &exit_code)); EXPECT_EQ(0, exit_code); #if !BUILDFLAG(IS_WIN) - SetExistenceCheckerPath(app.appid, - GetInstallDirectory(UpdaterScope::kSystem) - ->DirName() - .AppendASCII(app.appid)); + SetExistenceCheckerPath(app.appid, GetInstallDirectory(GetTestScope()) + ->DirName() + .AppendASCII(app.appid)); #endif }); @@ -638,6 +637,29 @@ scoped_refptr<IntegrationTestCommands> test_commands_; +#if BUILDFLAG(IS_WIN) + static constexpr char kGlobalPolicyKey[] = ""; + const TestApp kApp1 = {"test1", base::Version("1.0.0.0"), + "Testapp2Setup.crx3", base::Version("2.0.0.0"), + "Testapp2Setup.crx3"}; + const TestApp kApp2 = {"test2", base::Version("100.0.0.0"), + "Testapp2Setup.crx3", base::Version("101.0.0.0"), + "Testapp2Setup.crx3"}; + const TestApp kApp3 = {"test3", base::Version("1.0"), "Testapp2Setup.crx3", + base::Version("1.1"), "Testapp2Setup.crx3"}; +#else + static constexpr char kGlobalPolicyKey[] = "global"; + const TestApp kApp1 = { + "test1", base::Version("1.0.0.0"), "test_installer_test1_v1.crx3", + base::Version("2.0.0.0"), "test_installer_test1_v2.crx3"}; + const TestApp kApp2 = { + "test2", base::Version("100.0.0.0"), "test_installer_test2_v1.crx3", + base::Version("101.0.0.0"), "test_installer_test2_v2.crx3"}; + const TestApp kApp3 = {"test3", base::Version("1.0"), + "test_installer_test3_v1.crx3", base::Version("1.1"), + "test_installer_test3_v2.crx3"}; +#endif // BUILDFLAG(IS_WIN) + private: base::test::TaskEnvironment environment_; ScopedIPCSupportWrapper ipc_support_; @@ -985,6 +1007,45 @@ ASSERT_NO_FATAL_FAILURE(Uninstall()); } +TEST_F(IntegrationTest, UpdateErrorStatus) { + ScopedServer test_server(test_commands_); + + ASSERT_NO_FATAL_FAILURE(Install()); + ASSERT_NO_FATAL_FAILURE(ExpectInstalled()); + ASSERT_NO_FATAL_FAILURE(InstallTestApp(kApp1, /*install_v1=*/true)); + + for (const char* app_response_status : + {"noupdate", "error-internal", "error-hash", "error-osnotsupported", + "error-hwnotsupported", "error-unsupportedprotocol"}) { + ExpectAppsUpdateSequence( + GetTestScope(), &test_server, {}, + { + AppUpdateExpectation( + kApp1.GetInstallCommandLineArgs(/*install_v1=*/false), + kApp1.appid, kApp1.v1, kApp1.v2, + /*is_install=*/false, + /*should_update=*/false, false, "", "", + GetInstallerPath(kApp1.v2_crx), + /*always_serve_crx=*/false, + /*error_category=*/UpdateService::ErrorCategory::kNone, + /*error_code=*/0, + /*event_type=*/0, + /*custom_app_response=*/{}, app_response_status), + }); + ASSERT_NO_FATAL_FAILURE(RunWake(0)); + ASSERT_TRUE(WaitForUpdaterExit()); + ASSERT_NO_FATAL_FAILURE(ExpectAppInstalled(kApp1.appid, kApp1.v1)) + << "App is unexpectedly updated with update check status: " + << app_response_status; + ASSERT_NO_FATAL_FAILURE(SetLastChecked(base::Time::Now() - base::Hours(9))) + << "Failed to set last-checked to force next update check."; + } + + ASSERT_NO_FATAL_FAILURE(ExpectUninstallPing(&test_server)); + ASSERT_NO_FATAL_FAILURE(UninstallApp(kApp1.appid)); + ASSERT_NO_FATAL_FAILURE(Uninstall()); +} + TEST_F(IntegrationTest, UpdateApp) { ScopedServer test_server(test_commands_); ASSERT_NO_FATAL_FAILURE(Install()); @@ -1570,7 +1631,7 @@ TEST_F(IntegrationTest, IdleServerExits) { #if BUILDFLAG(IS_WIN) - if (GetTestScope() == UpdaterScope::kSystem) { + if (IsSystemInstall(GetTestScope())) { GTEST_SKIP() << "System server startup is complicated on Windows."; } #endif @@ -1925,25 +1986,8 @@ #if BUILDFLAG(IS_WIN) static constexpr char kGlobalPolicyKey[] = ""; - const TestApp kApp1 = {"test1", base::Version("1.0.0.0"), - "Testapp2Setup.crx3", base::Version("2.0.0.0"), - "Testapp2Setup.crx3"}; - const TestApp kApp2 = {"test2", base::Version("100.0.0.0"), - "Testapp2Setup.crx3", base::Version("101.0.0.0"), - "Testapp2Setup.crx3"}; - const TestApp kApp3 = {"test3", base::Version("1.0"), "Testapp2Setup.crx3", - base::Version("1.1"), "Testapp2Setup.crx3"}; #else static constexpr char kGlobalPolicyKey[] = "global"; - const TestApp kApp1 = { - "test1", base::Version("1.0.0.0"), "test_installer_test1_v1.crx3", - base::Version("2.0.0.0"), "test_installer_test1_v2.crx3"}; - const TestApp kApp2 = { - "test2", base::Version("100.0.0.0"), "test_installer_test2_v1.crx3", - base::Version("101.0.0.0"), "test_installer_test2_v2.crx3"}; - const TestApp kApp3 = {"test3", base::Version("1.0"), - "test_installer_test3_v1.crx3", base::Version("1.1"), - "test_installer_test3_v2.crx3"}; #endif // BUILDFLAG(IS_WIN) };
diff --git a/chrome/updater/test/integration_tests_impl.cc b/chrome/updater/test/integration_tests_impl.cc index f5b0799..24ed48c 100644 --- a/chrome/updater/test/integration_tests_impl.cc +++ b/chrome/updater/test/integration_tests_impl.cc
@@ -119,11 +119,12 @@ const base::FilePath& update_file, const std::string& run_action, const std::string& arguments, - const std::optional<std::string>& file_hash = std::nullopt) { + const std::optional<std::string>& file_hash = std::nullopt, + const std::optional<std::string>& status = std::nullopt) { return base::StringPrintf( R"( {)" R"( "appid":"%s",)" - R"( "status":"ok",)" + R"( "status":"%s",)" R"(%s)" R"( "updatecheck":{)" R"( "status":"ok",)" @@ -140,7 +141,7 @@ R"( })" R"( })" R"( })", - base::ToLowerASCII(app_id).c_str(), + base::ToLowerASCII(app_id).c_str(), status ? status->c_str() : "ok", !install_data_index.empty() ? base::StringPrintf( R"( "data":[{ "status":"ok", "name":"install", )" @@ -337,7 +338,8 @@ const UpdateService::ErrorCategory error_category, const int error_code, const int event_type, - const std::string& custom_app_response) + const std::string& custom_app_response, + const std::string& response_status) : args(args), app_id(app_id), from_version(from_version), @@ -352,7 +354,8 @@ error_category(error_category), error_code(error_code), event_type(event_type), - custom_app_response(custom_app_response) {} + custom_app_response(custom_app_response), + response_status(response_status.empty() ? "ok" : response_status) {} AppUpdateExpectation::AppUpdateExpectation(const AppUpdateExpectation&) = default; AppUpdateExpectation::~AppUpdateExpectation() = default; @@ -570,7 +573,8 @@ : base_name; app_responses.push_back(GetUpdateResponseForApp( app.app_id, "", test_server->update_url().spec(), app.to_version, - crx_path, run_action.MaybeAsASCII().c_str(), app.args)); + crx_path, run_action.MaybeAsASCII().c_str(), app.args, std::nullopt, + app.response_status)); } test_server->ExpectOnce({request::GetPathMatcher(test_server->update_path()), request::GetUpdaterUserAgentMatcher(), @@ -606,7 +610,7 @@ app.from_version.GetString().c_str(), app.to_version.GetString().c_str())})}, ")]}'\n"); - } else if (app.custom_app_response.empty()) { + } else if (app.custom_app_response.empty() && app.response_status == "ok") { // Event ping for apps that doesn't update. test_server->ExpectOnce( {request::GetPathMatcher(test_server->update_path()),
diff --git a/chrome/updater/test/integration_tests_impl.h b/chrome/updater/test/integration_tests_impl.h index d2a90ff..c8a33609 100644 --- a/chrome/updater/test/integration_tests_impl.h +++ b/chrome/updater/test/integration_tests_impl.h
@@ -58,7 +58,8 @@ const int error_code = static_cast<int>( UpdateService::Result::kUpdateCanceled), const int event_type = /*EVENT_UPDATE_COMPLETE=*/3, - const std::string& custom_app_response = {}); + const std::string& custom_app_response = {}, + const std::string& response_status = {}); AppUpdateExpectation(const AppUpdateExpectation&); ~AppUpdateExpectation(); @@ -77,6 +78,7 @@ const int error_code; const int event_type; const std::string custom_app_response; + const std::string response_status; }; // Returns the path to the updater installer program (in the build output
diff --git a/chrome/updater/test/test_installer/test_app_setup.sh b/chrome/updater/test/test_installer/test_app_setup.sh index bf39549..3d15404 100755 --- a/chrome/updater/test/test_installer/test_app_setup.sh +++ b/chrome/updater/test/test_installer/test_app_setup.sh
@@ -7,6 +7,7 @@ # path. declare appid=MockApp +declare system=0 declare company="Chromium" declare product_version="1.0.0.0" declare install=1 @@ -15,6 +16,9 @@ --appid=*) appid="${i#*=}" ;; + --system) + system=1 + ;; --company=*) company="${i#*=}" ;; @@ -31,9 +35,19 @@ declare -r install_file="app.json" if [[ "${OSTYPE}" =~ ^"darwin" ]]; then - declare -r install_path="/Library/Application Support/${company}/${appid}" + if (( "${system}" == 1 )); then + declare -r install_path="/Library/Application Support/${company}/${appid}" + else + declare -r \ + install_path="${HOME}/Library/Application Support/${company}/${appid}" + fi else - declare -r install_path="/opt/${company}/${appid}" + declare install_path="/opt/${company}/${appid}" + if (( "${system}" == 1 )); then + declare -r install_path="/opt/${company}/${appid}" + else + declare -r install_path="${HOME}/.local/${company}/${appid}" + fi fi if (( "${install}" == 1 )); then @@ -50,4 +64,4 @@ else rm -rf "${install_path}" 2> /dev/null echo "Uninstall ${appid} at: ${install_path}." -fi \ No newline at end of file +fi
diff --git a/chromeos/crosapi/mojom/feedback.mojom b/chromeos/crosapi/mojom/feedback.mojom index 25e9541..2e003db3 100644 --- a/chromeos/crosapi/mojom/feedback.mojom +++ b/chromeos/crosapi/mojom/feedback.mojom
@@ -11,7 +11,7 @@ // Note: When you add a new value, please add a test case accordingly in: // chrome/browser/feedback/show_feedback_page_lacros_browertest.cc. // -// Next MinVersion: 5 +// Next MinVersion: 6 // Next ID: 9 // [Stable, Extensible] @@ -29,6 +29,7 @@ [MinVersion=5] kFeedbackSourceSettingsPerformancePage = 9, [MinVersion=5] kFeedbackSourceProfileErrorDialog = 10, [MinVersion=5] kFeedbackSourceQuickOffice=11, + [MinVersion=6] kFeedbackSourceAI=12, }; [Stable] @@ -54,6 +55,8 @@ // Autofill metadata (e.g. form signatures, last autofill event type, etc). [MinVersion=1] mojo_base.mojom.Value? autofill_metadata@6; + + [MinVersion=2] mojo_base.mojom.Value? ai_metadata@7; }; // This interface is implemented by ash-chrome. It allows lacros-chrome to
diff --git a/clank b/clank index 542d4f7..fd941d8 160000 --- a/clank +++ b/clank
@@ -1 +1 @@ -Subproject commit 542d4f710ed7446ff82fa80babd76cf24a5a83bd +Subproject commit fd941d8a913faebbdaddb132368e9eb723e0634d
diff --git a/components/BUILD.gn b/components/BUILD.gn index dbe1749e..a3400030 100644 --- a/components/BUILD.gn +++ b/components/BUILD.gn
@@ -280,6 +280,7 @@ "//components/prefs:unit_tests", "//components/profile_metrics:unit_tests", "//components/proxy_config:unit_tests", + "//components/push_notification:unit_tests", "//components/qr_code_generator:unit_tests", "//components/query_parser:unit_tests", "//components/reading_list/core:unit_tests",
diff --git a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/chips/ChipsCoordinator.java b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/chips/ChipsCoordinator.java index 62793d7c..1868f2d 100644 --- a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/chips/ChipsCoordinator.java +++ b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/chips/ChipsCoordinator.java
@@ -131,9 +131,15 @@ int position = parent.getChildAdapterPosition(view); boolean isFirst = position == 0; boolean isLast = position == parent.getAdapter().getItemCount() - 1; + // using 'parent' not 'view' since 'view' did not layout yet, so view's + // #getLayoutDirection() won't return correct value. + boolean isRtl = (parent.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL); - outRect.left = isFirst ? mSidePaddingPx : mChipSpacingPx; - outRect.right = isLast ? mSidePaddingPx : mChipSpacingPx; + @Px int startPadding = isFirst ? mSidePaddingPx : mChipSpacingPx; + @Px int endPadding = isLast ? mSidePaddingPx : mChipSpacingPx; + + outRect.left = isRtl ? endPadding : startPadding; + outRect.right = isRtl ? startPadding : endPadding; } } }
diff --git a/components/compose_strings.grdp b/components/compose_strings.grdp index 0b3fa41..60543697 100644 --- a/components/compose_strings.grdp +++ b/components/compose_strings.grdp
@@ -153,6 +153,10 @@ <ph name="BEGIN_SURVEY_LINK"><a href="#" id="surveyLink" role="button"></ph>survey<ph name="END_SURVEY_LINK"></a></ph> </message> + <message name="IDS_COMPOSE_FOOTER_FISHFOOD_ON_DEVICE_USED" desc="A footer indicating that on-device evaluation was used." translateable="false"> + On-device evaluation used. + </message> + <!-- Miscellaneous --> <message name="IDS_COMPOSE_FEEDBACK_PLACEHOLDER" desc="Placeholder text for feedback text field" translateable="false"> Send feedback for Help me write.
diff --git a/components/content_settings/core/browser/content_settings_default_provider.cc b/components/content_settings/core/browser/content_settings_default_provider.cc index b7b105e7..3da22d7 100644 --- a/components/content_settings/core/browser/content_settings_default_provider.cc +++ b/components/content_settings/core/browser/content_settings_default_provider.cc
@@ -231,6 +231,33 @@ return std::make_unique<DefaultRuleIterator>(it->second.Clone()); } +std::unique_ptr<OwnedRule> DefaultProvider::GetRule( + const GURL& primary_url, + const GURL& secondary_url, + ContentSettingsType content_type, + bool off_the_record, + const PartitionKey& partition_key) const { + // The default provider never has off-the-record-specific settings. + if (off_the_record) { + return nullptr; + } + + base::AutoLock lock(lock_); + const auto it = default_settings_.find(content_type); + if (it == default_settings_.end()) { + NOTREACHED(); + return nullptr; + } + + if (it->second.is_none()) { + return nullptr; + } + + return std::make_unique<OwnedRule>(ContentSettingsPattern::Wildcard(), + ContentSettingsPattern::Wildcard(), + it->second.Clone(), RuleMetaData{}); +} + void DefaultProvider::ClearAllContentSettingsRules( ContentSettingsType content_type, const PartitionKey& partition_key) {
diff --git a/components/content_settings/core/browser/content_settings_default_provider.h b/components/content_settings/core/browser/content_settings_default_provider.h index d660599..ef77206 100644 --- a/components/content_settings/core/browser/content_settings_default_provider.h +++ b/components/content_settings/core/browser/content_settings_default_provider.h
@@ -44,6 +44,13 @@ bool off_the_record, const PartitionKey& partition_key) const override; + std::unique_ptr<OwnedRule> GetRule( + const GURL& primary_url, + const GURL& secondary_url, + ContentSettingsType content_type, + bool off_the_record, + const PartitionKey& partition_key) const override; + bool SetWebsiteSetting(const ContentSettingsPattern& primary_pattern, const ContentSettingsPattern& secondary_pattern, ContentSettingsType content_type,
diff --git a/components/content_settings/core/common/features.cc b/components/content_settings/core/common/features.cc index 6455329..55304f9c 100644 --- a/components/content_settings/core/common/features.cc +++ b/components/content_settings/core/common/features.cc
@@ -74,6 +74,10 @@ "ImprovedSemanticsActivityIndicators", base::FEATURE_ENABLED_BY_DEFAULT); +BASE_FEATURE(kLeftHandSideActivityIndicators, + "LeftHandSideActivityIndicators", + base::FEATURE_DISABLED_BY_DEFAULT); + BASE_FEATURE(kTrackingProtection3pcd, "TrackingProtection3pcd", base::FEATURE_DISABLED_BY_DEFAULT);
diff --git a/components/content_settings/core/common/features.h b/components/content_settings/core/common/features.h index bcb8ed3..80575c7 100644 --- a/components/content_settings/core/common/features.h +++ b/components/content_settings/core/common/features.h
@@ -97,6 +97,10 @@ COMPONENT_EXPORT(CONTENT_SETTINGS_FEATURES) BASE_DECLARE_FEATURE(kImprovedSemanticsActivityIndicators); +// Move activity indicators to the left-hand side of Omnibox. +COMPONENT_EXPORT(CONTENT_SETTINGS_FEATURES) +BASE_DECLARE_FEATURE(kLeftHandSideActivityIndicators); + // Feature to enable redesigned tracking protection UX + prefs for 3PCD. COMPONENT_EXPORT(CONTENT_SETTINGS_FEATURES) BASE_DECLARE_FEATURE(kTrackingProtection3pcd);
diff --git a/components/external_intents/android/java/src/org/chromium/components/external_intents/ExternalNavigationHandler.java b/components/external_intents/android/java/src/org/chromium/components/external_intents/ExternalNavigationHandler.java index 96859a86..e99bd30c 100644 --- a/components/external_intents/android/java/src/org/chromium/components/external_intents/ExternalNavigationHandler.java +++ b/components/external_intents/android/java/src/org/chromium/components/external_intents/ExternalNavigationHandler.java
@@ -144,42 +144,6 @@ "com.google.android.instantapps.nmr1.VIEW" }; - /** - * Histogram for the result of an intent scheme navigation. - * This enum is used in UMA, do not reorder values. - */ - @IntDef({ - IntentUriNavigationResult.WITH_FALLBACK_LAUNCHED_INTENT, - IntentUriNavigationResult.WITH_FALLBACK_USED_FALLBACK, - IntentUriNavigationResult.WITH_FALLBACK_NO_OVERRIDE, - IntentUriNavigationResult.WITH_FALLBACK_ASYNC_RESULT, - IntentUriNavigationResult.NO_FALLBACK_LAUNCHED_INTENT, - IntentUriNavigationResult.NO_FALLBACK_NO_OVERRIDE, - IntentUriNavigationResult.NO_FALLBACK_ASYNC_RESULT, - IntentUriNavigationResult.NUM_ENTRIES - }) - @Retention(RetentionPolicy.SOURCE) - public @interface IntentUriNavigationResult { - /* Intent with an unused fallback URL was launched. */ - int WITH_FALLBACK_LAUNCHED_INTENT = 0; - /* Intent fallback URL was used. */ - int WITH_FALLBACK_USED_FALLBACK = 1; - /* Intent with an unused fallback URL was blocked. */ - int WITH_FALLBACK_NO_OVERRIDE = 2; - /* Intent with a fallback URL prompted the user. */ - int WITH_FALLBACK_ASYNC_RESULT = 3; - /* Intent without a fallback URL was launched. */ - int NO_FALLBACK_LAUNCHED_INTENT = 4; - /* Intent without a fallback URL was blocked. */ - int NO_FALLBACK_NO_OVERRIDE = 5; - /* Intent without a fallback URL prompted the user. */ - int NO_FALLBACK_ASYNC_RESULT = 6; - - int NUM_ENTRIES = 7; - } - - private static final String INTENT_URI_RESULT_NAME = "Android.Intent.IntentUriNavigationResult"; - // Helper class to return a boolean by reference. private static class MutableBoolean { private Boolean mValue; @@ -642,7 +606,6 @@ canLaunchExternalFallbackResult.get()); } if (debug()) printDebugShouldOverrideUrlLoadingResultType(result); - if (isIntentUrl) captureIntentSchemeMetrics(result, browserFallbackUrl); if (result.getResultType() == OverrideUrlLoadingResultType.OVERRIDE_WITH_ASYNC_ACTION) { params.onAsyncActionStarted(); @@ -736,57 +699,6 @@ Log.i(TAG, "shouldOverrideUrlLoading result: " + resultString); } - private void captureIntentSchemeMetrics( - OverrideUrlLoadingResult result, GURL browserFallbackUrl) { - @IntentUriNavigationResult int value = IntentUriNavigationResult.NO_FALLBACK_NO_OVERRIDE; - if (browserFallbackUrl.isEmpty()) { - switch (result.getResultType()) { - case OverrideUrlLoadingResultType.OVERRIDE_WITH_EXTERNAL_INTENT: - value = IntentUriNavigationResult.NO_FALLBACK_LAUNCHED_INTENT; - break; - case OverrideUrlLoadingResultType.OVERRIDE_WITH_ASYNC_ACTION: - value = IntentUriNavigationResult.NO_FALLBACK_ASYNC_RESULT; - break; - case OverrideUrlLoadingResultType.NO_OVERRIDE: - value = IntentUriNavigationResult.NO_FALLBACK_NO_OVERRIDE; - break; - case OverrideUrlLoadingResultType.OVERRIDE_WITH_NAVIGATE_TAB: - // Quirk of incognito intent scheme URLs synchronously clobbering the tab with - // the target URL when the dialog can't be shown. - value = IntentUriNavigationResult.NO_FALLBACK_NO_OVERRIDE; - break; - default: - assert false; - break; - } - } else { - switch (result.getResultType()) { - case OverrideUrlLoadingResultType.OVERRIDE_WITH_EXTERNAL_INTENT: - if (result.wasExternalFallbackUrlLaunch()) { - value = IntentUriNavigationResult.WITH_FALLBACK_USED_FALLBACK; - } else { - value = IntentUriNavigationResult.WITH_FALLBACK_LAUNCHED_INTENT; - } - break; - case OverrideUrlLoadingResultType.OVERRIDE_WITH_ASYNC_ACTION: - value = IntentUriNavigationResult.WITH_FALLBACK_ASYNC_RESULT; - break; - case OverrideUrlLoadingResultType.NO_OVERRIDE: - value = IntentUriNavigationResult.WITH_FALLBACK_NO_OVERRIDE; - break; - case OverrideUrlLoadingResultType.OVERRIDE_WITH_NAVIGATE_TAB: - value = IntentUriNavigationResult.WITH_FALLBACK_USED_FALLBACK; - break; - default: - assert false; - break; - } - } - - RecordHistogram.recordEnumeratedHistogram( - INTENT_URI_RESULT_NAME, value, IntentUriNavigationResult.NUM_ENTRIES); - } - private boolean resolversSubsetOf(List<ResolveInfo> infos, List<ResolveInfo> container) { if (container == null) return false; HashSet<ComponentName> containerSet = new HashSet<>();
diff --git a/components/eye_dropper/eye_dropper_view.cc b/components/eye_dropper/eye_dropper_view.cc index 12107fb..c537058f 100644 --- a/components/eye_dropper/eye_dropper_view.cc +++ b/components/eye_dropper/eye_dropper_view.cc
@@ -272,7 +272,7 @@ const gfx::Size padding((size().width() - diameter) / 2, (size().height() - diameter) / 2); - if (GetWidget()->IsTranslucentWindowOpacitySupported()) { + if (views::Widget::IsWindowCompositingSupported()) { // Clip circle for magnified projection only when the widget // supports translucency. SkPath clip_path; @@ -355,7 +355,7 @@ flags.setStrokeWidth(2); flags.setColor(color_provider->GetColor(color::kColorEyedropperBoundary)); flags.setAntiAlias(true); - if (GetWidget()->IsTranslucentWindowOpacitySupported()) { + if (views::Widget::IsWindowCompositingSupported()) { view_canvas->DrawCircle( gfx::PointF(size().width() / 2, size().height() / 2), diameter / 2, flags);
diff --git a/components/feature_engagement/public/feature_configurations.cc b/components/feature_engagement/public/feature_configurations.cc index f9641942..142bbb09 100644 --- a/components/feature_engagement/public/feature_configurations.cc +++ b/components/feature_engagement/public/feature_configurations.cc
@@ -548,7 +548,7 @@ if (kIPHComposeMenuNewBadgeFeature.name == feature->name) { // A config that allows the new badge attached to the Compose feature - // entrypoint in the right-click menu to be shown at most 4 times in a + // entrypoint in the right-click menu to be shown at most 10 times in a // 10-day window and only while the user has opened the Compose feature less // than 3 times. absl::optional<FeatureConfig> config = FeatureConfig(); @@ -556,7 +556,7 @@ config->availability = Comparator(ANY, 0); config->session_rate = Comparator(ANY, 0); config->trigger = EventConfig("compose_menu_new_badge_triggered", - Comparator(LESS_THAN, 4), 10, 360); + Comparator(LESS_THAN, 10), 10, 360); config->used = EventConfig("compose_menu_item_activated", Comparator(LESS_THAN, 3), 360, 360); return config;
diff --git a/components/feature_engagement/public/feature_constants.cc b/components/feature_engagement/public/feature_constants.cc index 050fe11..452da522 100644 --- a/components/feature_engagement/public/feature_constants.cc +++ b/components/feature_engagement/public/feature_constants.cc
@@ -57,7 +57,7 @@ base::FEATURE_ENABLED_BY_DEFAULT); BASE_FEATURE(kIPHExperimentalAIPromoFeature, "IPH_ExperimentalAIPromo", - base::FEATURE_ENABLED_BY_DEFAULT); + base::FEATURE_DISABLED_BY_DEFAULT); #if BUILDFLAG(ENABLE_EXTENSIONS) BASE_FEATURE(kIPHExtensionsMenuFeature, "IPH_ExtensionsMenu",
diff --git a/components/feedback/redaction_tool/inprocess_metrics_recorder.cc b/components/feedback/redaction_tool/inprocess_metrics_recorder.cc index b5cacbb..9fdcb75 100644 --- a/components/feedback/redaction_tool/inprocess_metrics_recorder.cc +++ b/components/feedback/redaction_tool/inprocess_metrics_recorder.cc
@@ -27,6 +27,11 @@ UMA_HISTOGRAM_ENUMERATION(kCreditCardRedactionHistogram, step); } +void InprocessMetricsRecorder::RecordRedactionToolCallerHistogram( + RedactionToolCaller step) { + UMA_HISTOGRAM_ENUMERATION(kRedactionToolCallerHistogram, step); +} + void InprocessMetricsRecorder::RecordTimeSpentRedactingHistogram( base::TimeDelta time_spent) { UMA_HISTOGRAM_MEDIUM_TIMES(kTimeSpentRedactingHistogram, time_spent);
diff --git a/components/feedback/redaction_tool/inprocess_metrics_recorder.h b/components/feedback/redaction_tool/inprocess_metrics_recorder.h index 2106bce..861a2f9 100644 --- a/components/feedback/redaction_tool/inprocess_metrics_recorder.h +++ b/components/feedback/redaction_tool/inprocess_metrics_recorder.h
@@ -22,6 +22,7 @@ // redaction::RedactionToolMetricsRecorder: void RecordPIIRedactedHistogram(PIIType pii_type) override; void RecordCreditCardRedactionHistogram(CreditCardDetection step) override; + void RecordRedactionToolCallerHistogram(RedactionToolCaller step) override; void RecordTimeSpentRedactingHistogram(base::TimeDelta time_spent) override; };
diff --git a/components/feedback/redaction_tool/redaction_tool.cc b/components/feedback/redaction_tool/redaction_tool.cc index a021e83..da14cd9 100644 --- a/components/feedback/redaction_tool/redaction_tool.cc +++ b/components/feedback/redaction_tool/redaction_tool.cc
@@ -610,17 +610,21 @@ return detected; } -std::string RedactionTool::Redact(const std::string& input) { +std::string RedactionTool::Redact(const std::string& input, + const base::Location& location) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - return RedactAndKeepSelected(input, /*pii_types_to_keep=*/{}); + return RedactAndKeepSelected(input, /*pii_types_to_keep=*/{}, location); } std::string RedactionTool::RedactAndKeepSelected( const std::string& input, - const std::set<PIIType>& pii_types_to_keep) { + const std::set<PIIType>& pii_types_to_keep, + const base::Location& location) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); base::AssertLongCPUWorkAllowed(); + RedactionToolCaller caller = GetCaller(location); + metrics_recorder_->RecordRedactionToolCallerHistogram(caller); const base::TimeTicks redaction_start = base::TimeTicks::Now(); // Copy |input| so we can modify it. @@ -1094,6 +1098,33 @@ } } +RedactionToolCaller RedactionTool::GetCaller(const base::Location& location) { + std::string filePath = location.file_name(); + if (filePath.empty() || filePath.c_str() == nullptr) { + return RedactionToolCaller::kUndetermined; + } + + std::string fileName = filePath.substr(filePath.find_last_of("/\\") + 1); + + if (fileName == "redaction_tool_unittest.cc") { + return RedactionToolCaller::kUnitTest; + } else if (fileName == "system_log_uploader.cc") { + return RedactionToolCaller::kSysLogUploader; + } else if (fileName == "system_logs_fetcher.cc") { + return RedactionToolCaller::kSysLogFetcher; + } else if (fileName == "log_source_access_manager.cc") { + return RedactionToolCaller::kBrowserSystemLogs; + } else if (fileName == "feedback_common.cc") { + return RedactionToolCaller::kFeedbackTool; + } else if (filePath.find("support_tool") != std::string::npos) { + return RedactionToolCaller::kSupportTool; + } else if (filePath.find("error_reporting") != std::string::npos) { + return RedactionToolCaller::kErrorReporting; + } else { + return RedactionToolCaller::kUnknown; + } +} + std::string RedactionTool::RedactCustomPatternWithContext( const std::string& input, const CustomPatternWithAlias& pattern,
diff --git a/components/feedback/redaction_tool/redaction_tool.h b/components/feedback/redaction_tool/redaction_tool.h index 5e59b51..1702af7 100644 --- a/components/feedback/redaction_tool/redaction_tool.h +++ b/components/feedback/redaction_tool/redaction_tool.h
@@ -12,6 +12,7 @@ #include "base/component_export.h" #include "base/feature_list.h" +#include "base/location.h" #include "base/memory/raw_ptr.h" #include "base/memory/ref_counted.h" #include "base/sequence_checker.h" @@ -72,7 +73,11 @@ // addresses) in |input| is replaced with unique identifiers. // This is an expensive operation. Make sure not to execute this on the UI // thread. - std::string Redact(const std::string& input); + // The |location| is automatically determined to be the caller of the function + // and is used for metrics. It's not passed by the caller. + std::string Redact( + const std::string& input, + const base::Location& location = base::Location::Current()); // Attempts to redact PII sensitive data from |input| except the data that // fits in one of the PII types in |pii_types_to_keep| and returns the @@ -81,8 +86,12 @@ // Android storage paths will be partially redacted (only hashes) if // |pii_types_to_keep| contains PIIType::kURL or // PIIType::kAndroidAppStoragePath and not PIIType::kHash. - std::string RedactAndKeepSelected(const std::string& input, - const std::set<PIIType>& pii_types_to_keep); + // The |location| is automatically determined to be the caller of the function + // and is used for metrics. + std::string RedactAndKeepSelected( + const std::string& input, + const std::set<PIIType>& pii_types_to_keep, + const base::Location& location = base::Location::Current()); // Setting `enabled` to `true` redacts credit card numbers in addition to // gathering UMA metrics. If not called or `enabled` set to `false` credit @@ -135,6 +144,9 @@ std::string input, const std::set<PIIType>& pii_types_to_keep); + // Gets the caller of the Redaction tool by looking at the |location|. + RedactionToolCaller GetCaller(const base::Location& location); + // Detects PII sensitive data in |input| using custom patterns. Adds the // detected PII sensitive data to corresponding PII type key in |detected|. void DetectWithCustomPatterns(
diff --git a/components/feedback/redaction_tool/redaction_tool_metrics_recorder.h b/components/feedback/redaction_tool/redaction_tool_metrics_recorder.h index be314ae2..3845a370 100644 --- a/components/feedback/redaction_tool/redaction_tool_metrics_recorder.h +++ b/components/feedback/redaction_tool/redaction_tool_metrics_recorder.h
@@ -25,9 +25,27 @@ kMaxValue = kValidated, }; +// These values are logged to UMA. Entries should not be renumbered and +// numeric values should never be reused. Please keep in sync with +// "RedactionToolCaller" in //tools/metrics/histograms/enums.xml. +enum class RedactionToolCaller { + kSysLogUploader = 1, + kSysLogFetcher = 2, + kSupportTool = 3, + kErrorReporting = 4, + kFeedbackTool = 5, + kBrowserSystemLogs = 6, + kUnitTest = 7, + kUndetermined = 8, + kUnknown = 9, + kMaxValue = kUnknown, +}; + inline constexpr char kPIIRedactedHistogram[] = "Feedback.RedactionTool"; inline constexpr char kCreditCardRedactionHistogram[] = "Feedback.RedactionTool.CreditCardMatch"; +inline constexpr char kRedactionToolCallerHistogram[] = + "Feedback.RedactionTool.Caller"; // This class is the platform independent interface to record histograms using // the platform specific libraries. @@ -50,6 +68,9 @@ // against credit card checks. virtual void RecordCreditCardRedactionHistogram(CreditCardDetection step) = 0; + // Records the caller who initiated the call to the Redaction Tool. + virtual void RecordRedactionToolCallerHistogram(RedactionToolCaller step) = 0; + // Records the `time_spent` in milliseconds for redacting an input text. virtual void RecordTimeSpentRedactingHistogram( base::TimeDelta time_spent) = 0;
diff --git a/components/feedback/redaction_tool/redaction_tool_unittest.cc b/components/feedback/redaction_tool/redaction_tool_unittest.cc index 32afa73..dbbd7a4 100644 --- a/components/feedback/redaction_tool/redaction_tool_unittest.cc +++ b/components/feedback/redaction_tool/redaction_tool_unittest.cc
@@ -683,6 +683,25 @@ redactor_.EnableCreditCardRedaction(true); std::string redaction_input; std::string redaction_output; + ExpectBucketCount(kRedactionToolCallerHistogram, + RedactionToolCaller::kUnitTest, 0); + ExpectBucketCount(kRedactionToolCallerHistogram, + RedactionToolCaller::kSysLogUploader, 0); + ExpectBucketCount(kRedactionToolCallerHistogram, + RedactionToolCaller::kSysLogFetcher, 0); + ExpectBucketCount(kRedactionToolCallerHistogram, + RedactionToolCaller::kSupportTool, 0); + ExpectBucketCount(kRedactionToolCallerHistogram, + RedactionToolCaller::kErrorReporting, 0); + ExpectBucketCount(kRedactionToolCallerHistogram, + RedactionToolCaller::kFeedbackTool, 0); + ExpectBucketCount(kRedactionToolCallerHistogram, + RedactionToolCaller::kBrowserSystemLogs, 0); + ExpectBucketCount(kRedactionToolCallerHistogram, + RedactionToolCaller::kUndetermined, 0); + ExpectBucketCount(kRedactionToolCallerHistogram, + RedactionToolCaller::kUnknown, 0); + using enum CreditCardDetection; ExpectBucketCount(kCreditCardRedactionHistogram, kRegexMatch, 0); ExpectBucketCount(kCreditCardRedactionHistogram, kTimestamp, 0); @@ -723,6 +742,24 @@ // This isn't handled by the redaction tool but rather in Shill. It's part of // the enum for historical reasons. ExpectBucketCount(kPIIRedactedHistogram, PIIType::kEAP, 0); + ExpectBucketCount(kRedactionToolCallerHistogram, + RedactionToolCaller::kUnitTest, 1); + ExpectBucketCount(kRedactionToolCallerHistogram, + RedactionToolCaller::kSysLogUploader, 0); + ExpectBucketCount(kRedactionToolCallerHistogram, + RedactionToolCaller::kSysLogFetcher, 0); + ExpectBucketCount(kRedactionToolCallerHistogram, + RedactionToolCaller::kSupportTool, 0); + ExpectBucketCount(kRedactionToolCallerHistogram, + RedactionToolCaller::kErrorReporting, 0); + ExpectBucketCount(kRedactionToolCallerHistogram, + RedactionToolCaller::kFeedbackTool, 0); + ExpectBucketCount(kRedactionToolCallerHistogram, + RedactionToolCaller::kBrowserSystemLogs, 0); + ExpectBucketCount(kRedactionToolCallerHistogram, + RedactionToolCaller::kUndetermined, 0); + ExpectBucketCount(kRedactionToolCallerHistogram, + RedactionToolCaller::kUnknown, 0); ExpectBucketCount(kCreditCardRedactionHistogram, kRegexMatch, 16); ExpectBucketCount(kCreditCardRedactionHistogram, kTimestamp, 2);
diff --git a/components/history/core/browser/features.cc b/components/history/core/browser/features.cc index 77990c1..e61f66c 100644 --- a/components/history/core/browser/features.cc +++ b/components/history/core/browser/features.cc
@@ -84,6 +84,13 @@ "SyncSegmentsData", base::FEATURE_ENABLED_BY_DEFAULT); +// When enabled, prefer to use the new recovery module to recover the +// `TopSitesDatabase` database. See https://crbug.com/1385500 for details. +// This is a kill switch and is not intended to be used in a field trial. +BASE_FEATURE(kTopSitesDatabaseUseBuiltInRecoveryIfSupported, + "TopSitesDatabaseUseBuiltInRecoveryIfSupported", + base::FEATURE_ENABLED_BY_DEFAULT); + // The maximum number of New Tab Page displays to show with synced segments // data. const base::FeatureParam<int> kMaxNumNewTabPageDisplays(
diff --git a/components/history/core/browser/features.h b/components/history/core/browser/features.h index 08c5ac1..7b3b151 100644 --- a/components/history/core/browser/features.h +++ b/components/history/core/browser/features.h
@@ -29,6 +29,9 @@ // is enabled; do not check `kSyncSegmentsData` directly. BASE_DECLARE_FEATURE(kSyncSegmentsData); +// Kill switch for use of the new SQL recovery module in `TopSitesDatabase`. +BASE_DECLARE_FEATURE(kTopSitesDatabaseUseBuiltInRecoveryIfSupported); + // Returns true when both full history sync and synced segments data are // enabled. bool IsSyncSegmentsDataEnabled();
diff --git a/components/history/core/browser/top_sites_database.cc b/components/history/core/browser/top_sites_database.cc index 5ab50d3..433e8f4 100644 --- a/components/history/core/browser/top_sites_database.cc +++ b/components/history/core/browser/top_sites_database.cc
@@ -12,10 +12,13 @@ #include "base/check.h" #include "base/check_op.h" +#include "base/debug/dump_without_crashing.h" +#include "base/feature_list.h" #include "base/files/file_util.h" #include "base/functional/bind.h" #include "base/logging.h" #include "base/sequence_checker.h" +#include "components/history/core/browser/features.h" #include "components/history/core/browser/history_types.h" #include "components/history/core/browser/top_sites.h" #include "sql/database.h" @@ -72,7 +75,7 @@ // depending on the operation broken. This table has large rows, which will use // overflow pages, so it is possible (though unlikely) that a chain could fit // together and yield a row with errors. -void FixTopSitesTable(sql::Database* db, int version) { +void FixTopSitesTable(sql::Database& db) { // Enforce invariant that url_rank>=0 forms a contiguous series. // TODO(shess): I have not found an UPDATE+SUBSELECT method of managing this. // It can be done with a temporary table and a subselect, but doing it @@ -82,11 +85,11 @@ "SELECT url_rank,rowid FROM top_sites " "WHERE url_rank<>-1 " "ORDER BY url_rank"; - sql::Statement select_statement(db->GetUniqueStatement(kByRankSql)); + sql::Statement select_statement(db.GetUniqueStatement(kByRankSql)); static constexpr char kAdjustRankSql[] = "UPDATE top_sites SET url_rank=? WHERE rowid=?"; - sql::Statement update_statement(db->GetUniqueStatement(kAdjustRankSql)); + sql::Statement update_statement(db.GetUniqueStatement(kAdjustRankSql)); // Update any rows where `next_rank` doesn't match `url_rank`. int next_rank = 0; @@ -106,7 +109,7 @@ // constraints. void RecoverAndFixup(sql::Database* db, const base::FilePath& db_path) { // NOTE(shess): If the version changes, review this code. - DCHECK_EQ(5, kVersionNumber); + static_assert(kVersionNumber == 5); std::unique_ptr<sql::Recovery> recovery = sql::Recovery::BeginRecoverDatabase(db, db_path); @@ -140,8 +143,7 @@ return; } - // TODO(shess): Inline this? - FixTopSitesTable(recovery->db(), version); + FixTopSitesTable(*recovery->db()); std::ignore = sql::Recovery::Recovered(std::move(recovery)); } @@ -154,7 +156,45 @@ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(db_); - // Attempt to recover corrupt databases. + // TODO(https://crbug.com/1513464): Simplify this code as soon as we're + // confident that we can remove sql::Recovery. + if (base::FeatureList::IsEnabled( + kTopSitesDatabaseUseBuiltInRecoveryIfSupported) && + sql::BuiltInRecovery::ShouldAttemptRecovery(db_.get(), extended_error)) { + bool recovery_was_attempted = sql::BuiltInRecovery::RecoverIfPossible( + db_.get(), extended_error, + sql::BuiltInRecovery::Strategy::kRecoverWithMetaVersionOrRaze, + &kTopSitesDatabaseUseBuiltInRecoveryIfSupported); + if (!recovery_was_attempted) { + LOG(ERROR) + << "Recovery should have been attempted if the checks above passed."; + base::debug::DumpWithoutCrashing(); + return; + } + // Recovery was attempted. The database handle has been poisoned and the + // error callback has been reset. + + // Since the database was recovered from corruption, it's possible that some + // data in the newly recovered database is incorrect. When re-opening the + // database, we should attempt to fix any broken constraints. + // + // Unlike below when using sql::Recovery, which runs `FixTopSitesTable()` on + // the recovered copy of the database before overwriting the original + // (corrupted) database, here we defer the fix-up logic to after we've + // re-opened the database and all the other checks in the Init() method + // (version, schema, etc) pass. + // + // Note that recovery is only run when we detect corruption, but undetected + // corruption can happen at any time. We could consider running + // `FixTopSitesTable()` every time the database is opened, but in most cases + // that would be a (possibly expensive) no-op. + needs_fixing_up_ = true; + + // Signal the test-expectation framework that the error was handled. + std::ignore = sql::Database::IsExpectedSqliteError(extended_error); + return; + } + if (sql::Recovery::ShouldRecover(extended_error)) { // Prevent reentrant calls. db_->reset_error_callback(); @@ -172,21 +212,6 @@ return; } - // TODO(shess): This database's error histograms look like: - // 84% SQLITE_CORRUPT, SQLITE_CANTOPEN, SQLITE_NOTADB - // 7% SQLITE_ERROR - // 6% SQLITE_IOERR variants - // 2% SQLITE_READONLY - // .4% SQLITE_FULL - // nominal SQLITE_TOBIG, SQLITE_AUTH, and SQLITE_BUSY. In the case of - // thumbnail_database.cc, as soon as the recovery code landed, SQLITE_IOERR - // shot to leadership. If the I/O error is system-level, there is probably no - // hope, but if it is restricted to something about the database file, it is - // possible that the recovery code could be brought to bear. In fact, it is - // possible that running recovery would be a reasonable default when errors - // are seen. - - // The default handling is to assert on debug and to ignore on release. if (!sql::Database::IsExpectedSqliteError(extended_error)) DLOG(FATAL) << db_->GetErrorMessage(); } @@ -306,6 +331,15 @@ if (meta_table.GetVersionNumber() != kVersionNumber) return false; + // Attempt to fix up the table if recovery was attempted when opening. + if (needs_fixing_up_) { + CHECK(base::FeatureList::IsEnabled( + kTopSitesDatabaseUseBuiltInRecoveryIfSupported)); + + FixTopSitesTable(*db_); + needs_fixing_up_ = false; + } + // Initialization is complete. return transaction.Commit(); }
diff --git a/components/history/core/browser/top_sites_database.h b/components/history/core/browser/top_sites_database.h index c685aaa..fd3bb0f 100644 --- a/components/history/core/browser/top_sites_database.h +++ b/components/history/core/browser/top_sites_database.h
@@ -98,6 +98,11 @@ SEQUENCE_CHECKER(sequence_checker_); + // If recovery is attempted during one of the preliminary open attempts, the + // database should be checked for broken constraints. See comment in the + // DatabaseErrorCallback for more details. + bool needs_fixing_up_ = false; + std::unique_ptr<sql::Database> db_ GUARDED_BY_CONTEXT(sequence_checker_); };
diff --git a/components/history/core/browser/top_sites_database_unittest.cc b/components/history/core/browser/top_sites_database_unittest.cc index d8be1ae..e8b9e8a 100644 --- a/components/history/core/browser/top_sites_database_unittest.cc +++ b/components/history/core/browser/top_sites_database_unittest.cc
@@ -2,13 +2,16 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "components/history/core/browser/top_sites_database.h" + #include <stddef.h> #include "base/files/file_path.h" #include "base/files/scoped_temp_dir.h" #include "base/strings/utf_string_conversions.h" +#include "base/test/scoped_feature_list.h" +#include "components/history/core/browser/features.h" #include "components/history/core/browser/history_types.h" -#include "components/history/core/browser/top_sites_database.h" #include "components/history/core/test/database_test_utils.h" #include "components/history/core/test/thumbnail-inl.h" #include "sql/database.h" @@ -75,6 +78,20 @@ base::FilePath file_name_; }; +// Tests both the legacy `sql::Recovery` interface and the newer +// `sql::BuiltInRecovery` interface, if it's supported. +class TopSitesDatabaseRecoveryTest : public TopSitesDatabaseTest, + public testing::WithParamInterface<bool> { + public: + TopSitesDatabaseRecoveryTest() { + scoped_feature_list_.InitWithFeatureState( + kTopSitesDatabaseUseBuiltInRecoveryIfSupported, GetParam()); + } + + private: + base::test::ScopedFeatureList scoped_feature_list_; +}; + // Version 1 is deprecated, the resulting schema should be current, // with no data. TEST_F(TopSitesDatabaseTest, Version1) { @@ -154,7 +171,7 @@ // Version 1 is deprecated, the resulting schema should be current, with no // data. -TEST_F(TopSitesDatabaseTest, Recovery1) { +TEST_P(TopSitesDatabaseRecoveryTest, Recovery1) { // Create an example database. ASSERT_TRUE(CreateDatabaseFromSQL(file_name_, "TopSites.v1.sql")); @@ -174,22 +191,20 @@ } // Corruption should be detected and recovered during Init(). + TopSitesDatabase db; { - TopSitesDatabase db; - { - sql::test::ScopedErrorExpecter expecter; - expecter.ExpectError(SQLITE_CORRUPT); - ASSERT_TRUE(db.Init(file_name_)); - EXPECT_TRUE(expecter.SawExpectedErrors()); - } - VerifyTablesAndColumns(db.db_for_testing()); - VerifyDatabaseEmpty(db.db_for_testing()); + sql::test::ScopedErrorExpecter expecter; + expecter.ExpectError(SQLITE_CORRUPT); + ASSERT_TRUE(db.Init(file_name_)); + EXPECT_TRUE(expecter.SawExpectedErrors()); } + VerifyTablesAndColumns(db.db_for_testing()); + VerifyDatabaseEmpty(db.db_for_testing()); } // Version 2 is deprecated, the resulting schema should be current, with no // data. -TEST_F(TopSitesDatabaseTest, Recovery2) { +TEST_P(TopSitesDatabaseRecoveryTest, Recovery2) { // Create an example database. ASSERT_TRUE(CreateDatabaseFromSQL(file_name_, "TopSites.v2.sql")); @@ -209,20 +224,18 @@ } // Corruption should be detected and recovered during Init(). + TopSitesDatabase db; { - TopSitesDatabase db; - { - sql::test::ScopedErrorExpecter expecter; - expecter.ExpectError(SQLITE_CORRUPT); - ASSERT_TRUE(db.Init(file_name_)); - EXPECT_TRUE(expecter.SawExpectedErrors()); - } - VerifyTablesAndColumns(db.db_for_testing()); - VerifyDatabaseEmpty(db.db_for_testing()); + sql::test::ScopedErrorExpecter expecter; + expecter.ExpectError(SQLITE_CORRUPT); + ASSERT_TRUE(db.Init(file_name_)); + EXPECT_TRUE(expecter.SawExpectedErrors()); } + VerifyTablesAndColumns(db.db_for_testing()); + VerifyDatabaseEmpty(db.db_for_testing()); } -TEST_F(TopSitesDatabaseTest, Recovery4_CorruptHeader) { +TEST_P(TopSitesDatabaseRecoveryTest, Recovery4_CorruptHeader) { // Create an example database. EXPECT_TRUE(CreateDatabaseFromSQL(file_name_, "TopSites.v4.sql")); @@ -264,7 +277,7 @@ } } -TEST_F(TopSitesDatabaseTest, Recovery5_CorruptIndex) { +TEST_P(TopSitesDatabaseRecoveryTest, Recovery5_CorruptIndex) { // Create an example database. ASSERT_TRUE(CreateDatabaseFromSQL(file_name_, "TopSites.v5.sql")); @@ -281,23 +294,20 @@ } // Open the database and access the corrupt index. + TopSitesDatabase db; + ASSERT_TRUE(db.Init(file_name_)); + { - TopSitesDatabase db; - ASSERT_TRUE(db.Init(file_name_)); + sql::test::ScopedErrorExpecter expecter; + expecter.ExpectError(SQLITE_CORRUPT); - { - sql::test::ScopedErrorExpecter expecter; - expecter.ExpectError(SQLITE_CORRUPT); + // Accessing the index will throw SQLITE_CORRUPT. The corruption handler + // will recover the database and poison the handle, so the outer call + // fails. + EXPECT_EQ(TopSitesDatabase::kRankOfNonExistingURL, + db.GetURLRankForTesting(MostVisitedURL(kUrl1, std::u16string()))); - // Accessing the index will throw SQLITE_CORRUPT. The corruption handler - // will recover the database and poison the handle, so the outer call - // fails. - EXPECT_EQ( - TopSitesDatabase::kRankOfNonExistingURL, - db.GetURLRankForTesting(MostVisitedURL(kUrl1, std::u16string()))); - - EXPECT_TRUE(expecter.SawExpectedErrors()); - } + EXPECT_TRUE(expecter.SawExpectedErrors()); } // Check that the database is recovered at the SQLite level. @@ -309,27 +319,24 @@ // After recovery, the database accesses won't throw errors. Recovery should // have regenerated the index with no data loss. - { - TopSitesDatabase db; - ASSERT_TRUE(db.Init(file_name_)); - VerifyTablesAndColumns(db.db_for_testing()); + ASSERT_TRUE(db.Init(file_name_)); + VerifyTablesAndColumns(db.db_for_testing()); - EXPECT_EQ(0, - db.GetURLRankForTesting(MostVisitedURL(kUrl0, std::u16string()))); - EXPECT_EQ(1, - db.GetURLRankForTesting(MostVisitedURL(kUrl1, std::u16string()))); - EXPECT_EQ(2, - db.GetURLRankForTesting(MostVisitedURL(kUrl2, std::u16string()))); + EXPECT_EQ(0, + db.GetURLRankForTesting(MostVisitedURL(kUrl0, std::u16string()))); + EXPECT_EQ(1, + db.GetURLRankForTesting(MostVisitedURL(kUrl1, std::u16string()))); + EXPECT_EQ(2, + db.GetURLRankForTesting(MostVisitedURL(kUrl2, std::u16string()))); - MostVisitedURLList urls = db.GetSites(); - ASSERT_EQ(3u, urls.size()); - EXPECT_EQ(kUrl0, urls[0].url); // [0] because of url_rank. - EXPECT_EQ(kUrl1, urls[1].url); // [1] because of url_rank. - EXPECT_EQ(kUrl2, urls[2].url); // [2] because of url_rank. - } + MostVisitedURLList urls = db.GetSites(); + ASSERT_EQ(3u, urls.size()); + EXPECT_EQ(kUrl0, urls[0].url); // [0] because of url_rank. + EXPECT_EQ(kUrl1, urls[1].url); // [1] because of url_rank. + EXPECT_EQ(kUrl2, urls[2].url); // [2] because of url_rank. } -TEST_F(TopSitesDatabaseTest, Recovery5_CorruptIndexAndLostRow) { +TEST_P(TopSitesDatabaseRecoveryTest, Recovery5_CorruptIndexAndLostRow) { // Create an example database. ASSERT_TRUE(CreateDatabaseFromSQL(file_name_, "TopSites.v5.sql")); @@ -354,23 +361,20 @@ } // Open the database and access the corrupt index. + TopSitesDatabase db; + ASSERT_TRUE(db.Init(file_name_)); + { - TopSitesDatabase db; - ASSERT_TRUE(db.Init(file_name_)); + sql::test::ScopedErrorExpecter expecter; + expecter.ExpectError(SQLITE_CORRUPT); - { - sql::test::ScopedErrorExpecter expecter; - expecter.ExpectError(SQLITE_CORRUPT); + // Accessing the index will throw SQLITE_CORRUPT. The corruption handler + // will recover the database and poison the handle, so the outer call + // fails. + EXPECT_EQ(TopSitesDatabase::kRankOfNonExistingURL, + db.GetURLRankForTesting(MostVisitedURL(kUrl0, std::u16string()))); - // Accessing the index will throw SQLITE_CORRUPT. The corruption handler - // will recover the database and poison the handle, so the outer call - // fails. - EXPECT_EQ( - TopSitesDatabase::kRankOfNonExistingURL, - db.GetURLRankForTesting(MostVisitedURL(kUrl0, std::u16string()))); - - EXPECT_TRUE(expecter.SawExpectedErrors()); - } + EXPECT_TRUE(expecter.SawExpectedErrors()); } // Check that the database is recovered at the SQLite level. @@ -382,23 +386,20 @@ // After recovery, the database accesses won't throw errors. Recovery should // have regenerated the index and adjusted the ranks. - { - TopSitesDatabase db; - ASSERT_TRUE(db.Init(file_name_)); - VerifyTablesAndColumns(db.db_for_testing()); + ASSERT_TRUE(db.Init(file_name_)); + VerifyTablesAndColumns(db.db_for_testing()); - EXPECT_EQ(0, - db.GetURLRankForTesting(MostVisitedURL(kUrl0, std::u16string()))); - EXPECT_EQ(1, - db.GetURLRankForTesting(MostVisitedURL(kUrl2, std::u16string()))); - EXPECT_EQ(TopSitesDatabase::kRankOfNonExistingURL, - db.GetURLRankForTesting(MostVisitedURL(kUrl1, std::u16string()))); + EXPECT_EQ(0, + db.GetURLRankForTesting(MostVisitedURL(kUrl0, std::u16string()))); + EXPECT_EQ(1, + db.GetURLRankForTesting(MostVisitedURL(kUrl2, std::u16string()))); + EXPECT_EQ(TopSitesDatabase::kRankOfNonExistingURL, + db.GetURLRankForTesting(MostVisitedURL(kUrl1, std::u16string()))); - MostVisitedURLList urls = db.GetSites(); - ASSERT_EQ(2u, urls.size()); - EXPECT_EQ(kUrl0, urls[0].url); // [0] because of url_rank. - EXPECT_EQ(kUrl2, urls[1].url); // [1] because of url_rank. - } + MostVisitedURLList urls = db.GetSites(); + ASSERT_EQ(2u, urls.size()); + EXPECT_EQ(kUrl0, urls[0].url); // [0] because of url_rank. + EXPECT_EQ(kUrl2, urls[1].url); // [1] because of url_rank. } TEST_F(TopSitesDatabaseTest, ApplyDelta_Delete) { @@ -549,4 +550,6 @@ } } +INSTANTIATE_TEST_SUITE_P(All, TopSitesDatabaseRecoveryTest, testing::Bool()); + } // namespace history
diff --git a/components/optimization_guide/core/model_execution/on_device_model_service_controller_unittest.cc b/components/optimization_guide/core/model_execution/on_device_model_service_controller_unittest.cc index 9ebcc6c..094e941 100644 --- a/components/optimization_guide/core/model_execution/on_device_model_service_controller_unittest.cc +++ b/components/optimization_guide/core/model_execution/on_device_model_service_controller_unittest.cc
@@ -450,6 +450,7 @@ response_error_ = result.error().error(); return; } + provided_by_on_device_ = result.value().provided_by_on_device; auto response = ParsedAnyMetadata<proto::ComposeResponse>(result.value().response); if (result.value().is_complete) { @@ -470,6 +471,7 @@ raw_ptr<OnDeviceModelAccessController> access_controller_ = nullptr; std::vector<std::string> streamed_responses_; std::optional<std::string> response_received_; + std::optional<bool> provided_by_on_device_; std::unique_ptr<ModelQualityLogEntry> log_entry_received_; std::optional<OptimizationGuideModelExecutionError::ModelExecutionError> response_error_; @@ -493,6 +495,7 @@ EXPECT_TRUE(response_received_); const std::string expected_response = "Input: execute:foo\n"; EXPECT_EQ(*response_received_, expected_response); + EXPECT_TRUE(*provided_by_on_device_); EXPECT_THAT(streamed_responses_, ElementsAre(expected_response)); EXPECT_TRUE(log_entry_received_); EXPECT_GT(log_entry_received_->log_ai_data_request() @@ -1178,6 +1181,7 @@ "2z"); EXPECT_FALSE( log_ai_data_request_passed_to_remote_->compose().has_response_data()); + EXPECT_FALSE(provided_by_on_device_.has_value()); } TEST_F(OnDeviceModelServiceControllerTest,
diff --git a/components/optimization_guide/core/model_execution/session_impl.cc b/components/optimization_guide/core/model_execution/session_impl.cc index f4a223d7..49ec394 100644 --- a/components/optimization_guide/core/model_execution/session_impl.cc +++ b/components/optimization_guide/core/model_execution/session_impl.cc
@@ -468,6 +468,7 @@ StreamingResponse{ .response = *output, .is_complete = is_complete, + .provided_by_on_device = true, }, std::move(log_entry)); }
diff --git a/components/optimization_guide/core/optimization_guide_model_executor.h b/components/optimization_guide/core/optimization_guide_model_executor.h index f5196d1..0319f0d 100644 --- a/components/optimization_guide/core/optimization_guide_model_executor.h +++ b/components/optimization_guide/core/optimization_guide_model_executor.h
@@ -28,6 +28,9 @@ // True if streaming has finished. bool is_complete = false; + + // True if the response was computed on-device. + bool provided_by_on_device = false; }; using OptimizationGuideModelStreamingExecutionResult =
diff --git a/components/policy/test/data/pref_mapping/EssentialSearchEnabled.json b/components/policy/test/data/pref_mapping/EssentialSearchEnabled.json index 31997fe2..238eb170 100644 --- a/components/policy/test/data/pref_mapping/EssentialSearchEnabled.json +++ b/components/policy/test/data/pref_mapping/EssentialSearchEnabled.json
@@ -1,5 +1,38 @@ [ { - "reason_for_missing_test": "TODO(b/275929724): Feature not yet implemented" + "os": [ + "chromeos_ash", + "chromeos_lacros" + ], + "policy_pref_mapping_tests": [ + { + "policies": {}, + "prefs": { + "essential_search_enabled": { + "default_value": false + } + } + }, + { + "policies": { + "EssentialSearchEnabled": false + }, + "prefs": { + "essential_search_enabled": { + "value": false + } + } + }, + { + "policies": { + "EssentialSearchEnabled": true + }, + "prefs": { + "essential_search_enabled": { + "value": true + } + } + } + ] } ]
diff --git a/components/push_notification/BUILD.gn b/components/push_notification/BUILD.gn index 762cbc6..e970cc7c 100644 --- a/components/push_notification/BUILD.gn +++ b/components/push_notification/BUILD.gn
@@ -14,3 +14,13 @@ ] deps = [ "//base" ] } + +source_set("unit_tests") { + testonly = true + sources = [ "push_notification_client_manager_unittest.cc" ] + deps = [ + ":push_notification", + "//base/test:test_support", + "//testing/gtest", + ] +}
diff --git a/components/push_notification/push_notification_client.h b/components/push_notification/push_notification_client.h index 472df28..80d916a 100644 --- a/components/push_notification/push_notification_client.h +++ b/components/push_notification/push_notification_client.h
@@ -6,21 +6,23 @@ #define COMPONENTS_PUSH_NOTIFICATION_PUSH_NOTIFICATION_CLIENT_H_ #include <string> + +#include "base/containers/flat_map.h" #include "components/push_notification/push_notification_client_id.h" namespace push_notification { // Base class for PushNotificationService clients to. Each feature that uses the -// PushNotificationService must create it's own PushNotificationClient and +// PushNotificationService must create its own PushNotificationClient and // implement the OnMessageReceived functionality. PushNotificationClient must // register with the PushNotificationService to begin receiving messages. class PushNotificationClient { public: - explicit PushNotificationClient(ClientId client_id); - virtual ~PushNotificationClient() = 0; + explicit PushNotificationClient(ClientId client_id) : client_id_(client_id) {} + virtual ~PushNotificationClient() = default; // Returns the feature's `client_id_`. - const ClientId& GetClientId() { return client_id_; } + ClientId GetClientId() { return client_id_; } // Only called when the instance of the `message_data` matches the // `client_id_`.
diff --git a/components/push_notification/push_notification_client_id.cc b/components/push_notification/push_notification_client_id.cc index 54ca945..a98a462 100644 --- a/components/push_notification/push_notification_client_id.cc +++ b/components/push_notification/push_notification_client_id.cc
@@ -15,11 +15,11 @@ } } -ClientId GetClientIdFromStr(const std::string& id_string) { +std::optional<ClientId> GetClientIdFromStr(const std::string& id_string) { if (id_string == kNearbyPresenceClientId) { return ClientId::kNearbyPresence; } - return ClientId::kInvalidClientId; + return std::nullopt; } } // namespace push_notification
diff --git a/components/push_notification/push_notification_client_id.h b/components/push_notification/push_notification_client_id.h index c78bdb3..adc490f 100644 --- a/components/push_notification/push_notification_client_id.h +++ b/components/push_notification/push_notification_client_id.h
@@ -12,13 +12,12 @@ enum class ClientId { kNearbyPresence, - kInvalidClientId, }; static constexpr char kNearbyPresenceClientId[] = "nearby_presence"; std::optional<std::string> GetClientIdStr(ClientId id); -ClientId GetClientIdFromStr(const std::string& id_string); +std::optional<ClientId> GetClientIdFromStr(const std::string& id_string); } // namespace push_notification
diff --git a/components/push_notification/push_notification_client_manager.cc b/components/push_notification/push_notification_client_manager.cc index db24eb6c..3a2402c 100644 --- a/components/push_notification/push_notification_client_manager.cc +++ b/components/push_notification/push_notification_client_manager.cc
@@ -4,22 +4,31 @@ #include "components/push_notification/push_notification_client_manager.h" +#include "base/logging.h" + +namespace { + +const char kClientIdKey[] = "type_id"; + +} // namespace + namespace push_notification { -PushNotificationClientManager::PushNotificationClientManager() = default; +PushNotificationClientManager::PushNotificationClientManager() {} + PushNotificationClientManager::~PushNotificationClientManager() = default; void PushNotificationClientManager::AddPushNotificationClient( PushNotificationClient* client) { CHECK(client); - // TODO(b/287340843): implement adding a PushNotification client to the - // `clients` map. + CHECK(GetClientIdStr(client->GetClientId())); + client_id_to_client_map_.insert_or_assign(client->GetClientId(), client); + FlushPendingMessageStore(client->GetClientId()); } void PushNotificationClientManager::RemovePushNotificationClient( ClientId client_id) { - // TODO(b/287340843): implement removing a PushNotification client from the - // `clients` map. + client_id_to_client_map_.erase(client_id); } std::vector<const PushNotificationClient*> @@ -31,12 +40,50 @@ return client_list; } +void PushNotificationClientManager::NotifyPushNotificationClientOfMessage( + PushNotificationMessage message) { + auto client_id = GetClientIdFromStr(message.data.at(kClientIdKey)); + + if (!client_id.has_value()) { + VLOG(1) + << __func__ + << "Received a message for an invalid client ID. Message discarded."; + return; + } + + if (client_id_to_client_map_.contains(client_id)) { + client_id_to_client_map_.at(client_id)->OnMessageReceived(message.data); + } else { + pending_message_store_.push_back(std::move(message)); + } +} + +void PushNotificationClientManager::FlushPendingMessageStore( + ClientId client_id) { + // Iterate through the `pending_message_store`, dispatch any messages that + // belong to the client being registered and remove dispatched messages. + auto iter = pending_message_store_.begin(); + std::optional<std::string> client_id_str = GetClientIdStr(client_id); + if (!client_id_str.has_value()) { + return; + } + while (iter != pending_message_store_.end()) { + if (iter->data.at(kClientIdKey) == client_id_str) { + client_id_to_client_map_.at(client_id)->OnMessageReceived(iter->data); + iter = pending_message_store_.erase(iter); + } else { + ++iter; + } + } +} + PushNotificationClientManager::PushNotificationMessage:: PushNotificationMessage() = default; - PushNotificationClientManager::PushNotificationMessage::PushNotificationMessage( PushNotificationMessage&& other) = default; - +PushNotificationClientManager::PushNotificationMessage& +PushNotificationClientManager::PushNotificationMessage::operator=( + PushNotificationMessage&& other) = default; PushNotificationClientManager::PushNotificationMessage:: ~PushNotificationMessage() = default;
diff --git a/components/push_notification/push_notification_client_manager.h b/components/push_notification/push_notification_client_manager.h index 5f294a18..e26b914 100644 --- a/components/push_notification/push_notification_client_manager.h +++ b/components/push_notification/push_notification_client_manager.h
@@ -6,22 +6,28 @@ #define COMPONENTS_PUSH_NOTIFICATION_PUSH_NOTIFICATION_CLIENT_MANAGER_H_ #include "base/containers/flat_map.h" +#include "base/containers/flat_set.h" #include "components/push_notification/push_notification_client.h" namespace push_notification { -// PushNotificationClientManager is responsible for delegating notifications to -// the corresponding features who have a registered PushNotificationClient. +// `PushNotificationClientManager` is responsible for delegating notifications +// to the corresponding features who have a registered `PushNotificationClient`. +// Messages received before the corresponding `PushNotificationClient` are +// delivered to that client once registered via the client calling +// `CheckPendingMessageStore()`. class PushNotificationClientManager { public: PushNotificationClientManager(); - virtual ~PushNotificationClientManager(); + ~PushNotificationClientManager(); struct PushNotificationMessage { PushNotificationMessage(); PushNotificationMessage(const PushNotificationMessage& other) = delete; PushNotificationMessage(PushNotificationMessage&& other); - virtual ~PushNotificationMessage(); + ~PushNotificationMessage(); + + PushNotificationMessage& operator=(PushNotificationMessage&& other); // Key Value map to contain all relevant information intended for the // `PushNotificationClient`. @@ -38,14 +44,19 @@ void AddPushNotificationClient(PushNotificationClient* client); void RemovePushNotificationClient(ClientId client_id); - std::vector<const PushNotificationClient*> GetPushNotificationClients(); + void NotifyPushNotificationClientOfMessage(PushNotificationMessage message); - virtual void NotifyPushNotificationClientOfMessage( - PushNotificationMessage message) = 0; + private: + void FlushPendingMessageStore(ClientId client_id); - protected: base::flat_map<ClientId, PushNotificationClient*> client_id_to_client_map_; + + // Messages for clients that have not registered with the service yet. After a + // client registers, `FlushPendingMessageStore()` iterates through this vector + // and checks if there are any pending messages which should immediately be + // directed to the new client. + std::vector<PushNotificationMessage> pending_message_store_; }; } // namespace push_notification
diff --git a/components/push_notification/push_notification_client_manager_unittest.cc b/components/push_notification/push_notification_client_manager_unittest.cc new file mode 100644 index 0000000..2f68fa7 --- /dev/null +++ b/components/push_notification/push_notification_client_manager_unittest.cc
@@ -0,0 +1,136 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/push_notification/push_notification_client_manager.h" + +#include <memory> + +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +const char kTestMessage[] = "This is a test message"; +const char kNotificationTypeIdKey[] = "type_id"; +const char kNotificationPayloadKey[] = "payload"; + +class FakePushNotificationClient + : public push_notification::PushNotificationClient { + public: + explicit FakePushNotificationClient( + const push_notification::ClientId& client_id) + : push_notification::PushNotificationClient(client_id) {} + FakePushNotificationClient(const FakePushNotificationClient&) = delete; + FakePushNotificationClient& operator=(const FakePushNotificationClient&) = + delete; + ~FakePushNotificationClient() override = default; + + void OnMessageReceived( + base::flat_map<std::string, std::string> message_data) override { + last_received_message_ = message_data.at(kNotificationPayloadKey); + } + + const std::string& GetMostRecentMessageRecieved() { + return last_received_message_; + } + + private: + std::string last_received_message_; +}; + +} // namespace + +namespace push_notification { + +class PushNotificationClientManagerTest : public testing::Test { + public: + PushNotificationClientManagerTest() = default; + ~PushNotificationClientManagerTest() override = default; + + // testing::Test: + void SetUp() override { + push_notification_client_manager_ = + std::make_unique<PushNotificationClientManager>(); + } + + std::unique_ptr<PushNotificationClientManager> + push_notification_client_manager_; +}; + +TEST_F(PushNotificationClientManagerTest, AddClient) { + auto fake_push_notification_client = + std::make_unique<FakePushNotificationClient>( + push_notification::ClientId::kNearbyPresence); + push_notification_client_manager_->AddPushNotificationClient( + fake_push_notification_client.get()); + + EXPECT_EQ( + 1u, + push_notification_client_manager_->GetPushNotificationClients().size()); +} + +TEST_F(PushNotificationClientManagerTest, AddThenRemoveClient) { + auto fake_push_notification_client = + std::make_unique<FakePushNotificationClient>( + push_notification::ClientId::kNearbyPresence); + push_notification_client_manager_->AddPushNotificationClient( + fake_push_notification_client.get()); + EXPECT_EQ( + 1u, + push_notification_client_manager_->GetPushNotificationClients().size()); + push_notification_client_manager_->RemovePushNotificationClient( + push_notification::ClientId::kNearbyPresence); + EXPECT_EQ( + 0u, + push_notification_client_manager_->GetPushNotificationClients().size()); +} + +TEST_F(PushNotificationClientManagerTest, PassPushNotificationMessageToClient) { + auto fake_push_notification_client = + std::make_unique<FakePushNotificationClient>( + push_notification::ClientId::kNearbyPresence); + + push_notification_client_manager_->AddPushNotificationClient( + fake_push_notification_client.get()); + EXPECT_EQ( + 1u, + push_notification_client_manager_->GetPushNotificationClients().size()); + + PushNotificationClientManager::PushNotificationMessage test_incoming_message; + test_incoming_message.data.insert_or_assign( + kNotificationTypeIdKey, push_notification::kNearbyPresenceClientId); + test_incoming_message.data.insert_or_assign(kNotificationPayloadKey, + kTestMessage); + + push_notification_client_manager_->NotifyPushNotificationClientOfMessage( + std::move(test_incoming_message)); + EXPECT_EQ(kTestMessage, + fake_push_notification_client->GetMostRecentMessageRecieved()); + ; +} + +TEST_F(PushNotificationClientManagerTest, + PassPushNotificationMessageBeforeAddingClient) { + PushNotificationClientManager::PushNotificationMessage test_incoming_message; + test_incoming_message.data.insert_or_assign( + kNotificationTypeIdKey, push_notification::kNearbyPresenceClientId); + test_incoming_message.data.insert_or_assign(kNotificationPayloadKey, + kTestMessage); + + push_notification_client_manager_->NotifyPushNotificationClientOfMessage( + std::move(test_incoming_message)); + + auto fake_push_notification_client = + std::make_unique<FakePushNotificationClient>( + push_notification::ClientId::kNearbyPresence); + + push_notification_client_manager_->AddPushNotificationClient( + fake_push_notification_client.get()); + EXPECT_EQ( + 1u, + push_notification_client_manager_->GetPushNotificationClients().size()); + EXPECT_EQ(kTestMessage, + fake_push_notification_client->GetMostRecentMessageRecieved()); +} + +} // namespace push_notification
diff --git a/components/push_notification/push_notification_service.cc b/components/push_notification/push_notification_service.cc index bdad767..d560eb2 100644 --- a/components/push_notification/push_notification_service.cc +++ b/components/push_notification/push_notification_service.cc
@@ -6,7 +6,9 @@ namespace push_notification { -PushNotificationService::PushNotificationService() = default; +PushNotificationService::PushNotificationService() + : client_manager_(std::make_unique<PushNotificationClientManager>()) {} + PushNotificationService::~PushNotificationService() = default; PushNotificationClientManager*
diff --git a/components/user_manager/OWNERS b/components/user_manager/OWNERS index 1e3e2653..52a5f18 100644 --- a/components/user_manager/OWNERS +++ b/components/user_manager/OWNERS
@@ -1,5 +1,4 @@ achuith@chromium.org alemate@chromium.org antrim@chromium.org -rsorokin@google.com xiyuan@chromium.org
diff --git a/components/visitedlink/browser/visitedlink_writer.cc b/components/visitedlink/browser/visitedlink_writer.cc index 6785fd9..1c47272 100644 --- a/components/visitedlink/browser/visitedlink_writer.cc +++ b/components/visitedlink/browser/visitedlink_writer.cc
@@ -9,6 +9,7 @@ #include <algorithm> #include <memory> +#include <string_view> #include <utility> #include "base/files/file_util.h" @@ -328,8 +329,7 @@ if (!url.is_valid()) return null_hash_; // Don't add invalid URLs. - Fingerprint fingerprint = - ComputeURLFingerprint(url.spec().data(), url.spec().size(), salt_); + Fingerprint fingerprint = ComputeURLFingerprint(url.spec(), salt_); // If the table isn't loaded the table will be rebuilt and after // that accumulated fingerprints will be applied to the table. if (table_builder_.get() || table_is_loading_from_file_) { @@ -424,8 +424,7 @@ if (!url.is_valid()) continue; - Fingerprint fingerprint = - ComputeURLFingerprint(url.spec().data(), url.spec().size(), salt_); + Fingerprint fingerprint = ComputeURLFingerprint(url.spec(), salt_); deleted_since_rebuild_.insert(fingerprint); // If the URL was just added and now we're deleting it, it may be in the @@ -450,8 +449,7 @@ const GURL& url(urls->NextURL()); if (!url.is_valid()) continue; - deleted_fingerprints.insert( - ComputeURLFingerprint(url.spec().data(), url.spec().size(), salt_)); + deleted_fingerprints.insert(ComputeURLFingerprint(url.spec(), salt_)); } DeleteFingerprintsFromCurrentTable(deleted_fingerprints); } @@ -760,16 +758,14 @@ // Also add anything that was added while we were asynchronously // loading the table. for (const GURL& url : added_since_load_) { - Fingerprint fingerprint = - ComputeURLFingerprint(url.spec().data(), url.spec().size(), salt_); + Fingerprint fingerprint = ComputeURLFingerprint(url.spec(), salt_); AddFingerprint(fingerprint, false); } added_since_load_.clear(); // Now handle deletions. for (const GURL& url : deleted_since_load_) { - Fingerprint fingerprint = - ComputeURLFingerprint(url.spec().data(), url.spec().size(), salt_); + Fingerprint fingerprint = ComputeURLFingerprint(url.spec(), salt_); DeleteFingerprint(fingerprint, false); } deleted_since_load_.clear(); @@ -1160,8 +1156,8 @@ void VisitedLinkWriter::TableBuilder::OnURL(const GURL& url) { if (!url.is_empty()) { - fingerprints_.push_back(VisitedLinkWriter::ComputeURLFingerprint( - url.spec().data(), url.spec().length(), salt_)); + fingerprints_.push_back( + VisitedLinkWriter::ComputeURLFingerprint(url.spec(), salt_)); } }
diff --git a/components/visitedlink/common/visitedlink_common.cc b/components/visitedlink/common/visitedlink_common.cc index b0d455e..65e239984 100644 --- a/components/visitedlink/common/visitedlink_common.cc +++ b/components/visitedlink/common/visitedlink_common.cc
@@ -7,6 +7,7 @@ #include <string.h> // for memset() #include <ostream> +#include <string_view> #include "base/bit_cast.h" #include "base/check.h" @@ -27,17 +28,18 @@ // FIXME: this uses linear probing, it should be replaced with quadratic // probing or something better. See VisitedLinkWriter::AddFingerprint -bool VisitedLinkCommon::IsVisited(const char* canonical_url, - size_t url_len) const { - if (url_len == 0) +bool VisitedLinkCommon::IsVisited(std::string_view canonical_url) const { + if (canonical_url.size() == 0) { return false; - if (!hash_table_ || table_length_ == 0) + } + if (!hash_table_ || table_length_ == 0) { return false; - return IsVisited(ComputeURLFingerprint(canonical_url, url_len)); + } + return IsVisited(ComputeURLFingerprint(canonical_url)); } bool VisitedLinkCommon::IsVisited(const GURL& url) const { - return IsVisited(url.spec().data(), url.spec().size()); + return IsVisited(url.spec()); } bool VisitedLinkCommon::IsVisited(Fingerprint fingerprint) const { @@ -77,16 +79,15 @@ // static VisitedLinkCommon::Fingerprint VisitedLinkCommon::ComputeURLFingerprint( - const char* canonical_url, - size_t url_len, + std::string_view canonical_url, const uint8_t salt[LINK_SALT_LENGTH]) { - DCHECK(url_len > 0) << "Canonical URLs should not be empty"; + DCHECK(canonical_url.size() > 0) << "Canonical URLs should not be empty"; base::MD5Context ctx; base::MD5Init(&ctx); base::MD5Update(&ctx, base::StringPiece(reinterpret_cast<const char*>(salt), LINK_SALT_LENGTH)); - base::MD5Update(&ctx, base::StringPiece(canonical_url, url_len)); + base::MD5Update(&ctx, canonical_url); base::MD5Digest digest; base::MD5Final(&digest, &ctx);
diff --git a/components/visitedlink/common/visitedlink_common.h b/components/visitedlink/common/visitedlink_common.h index 05a150a..d63728a1 100644 --- a/components/visitedlink/common/visitedlink_common.h +++ b/components/visitedlink/common/visitedlink_common.h
@@ -8,6 +8,7 @@ #include <stddef.h> #include <stdint.h> +#include <string_view> #include <vector> #include "base/memory/raw_ptr.h" @@ -66,15 +67,14 @@ virtual ~VisitedLinkCommon(); // Returns the fingerprint for the given URL. - Fingerprint ComputeURLFingerprint(const char* canonical_url, - size_t url_len) const { - return ComputeURLFingerprint(canonical_url, url_len, salt_); + Fingerprint ComputeURLFingerprint(std::string_view canonical_url) const { + return ComputeURLFingerprint(canonical_url, salt_); } // Looks up the given key in the table. The fingerprint for the URL is // computed if you call one with the string argument. Returns true if found. // Does not modify the hastable. - bool IsVisited(const char* canonical_url, size_t url_len) const; + bool IsVisited(const std::string_view canonical_url) const; bool IsVisited(const GURL& url) const; bool IsVisited(Fingerprint fingerprint) const; @@ -119,8 +119,7 @@ // pass the salt as a parameter. See the non-static version above if you // want to use the current class' salt. static Fingerprint ComputeURLFingerprint( - const char* canonical_url, - size_t url_len, + std::string_view canonical_url, const uint8_t salt[LINK_SALT_LENGTH]); // Computes the hash value of the given fingerprint, this is used as a lookup
diff --git a/components/viz/common/features.cc b/components/viz/common/features.cc index f1e29506..a9ba95dd 100644 --- a/components/viz/common/features.cc +++ b/components/viz/common/features.cc
@@ -261,7 +261,12 @@ // callbacks to match the preferred framerate. BASE_FEATURE(kOnBeginFrameThrottleVideo, "OnBeginFrameThrottleVideo", - base::FEATURE_DISABLED_BY_DEFAULT); +#if BUILDFLAG(IS_ANDROID) + base::FEATURE_ENABLED_BY_DEFAULT +#else + base::FEATURE_DISABLED_BY_DEFAULT +#endif + ); BASE_FEATURE(kSharedBitmapToSharedImage, "SharedBitmapToSharedImage",
diff --git a/components/viz/service/display/display_resource_provider_software.cc b/components/viz/service/display/display_resource_provider_software.cc index 0696509..771f03b 100644 --- a/components/viz/service/display/display_resource_provider_software.cc +++ b/components/viz/service/display/display_resource_provider_software.cc
@@ -56,6 +56,10 @@ WaitSyncToken(resource->transferable.mailbox_holder.sync_token); access->representation = shared_image_manager_->ProduceMemory(mailbox, memory_tracker_.get()); + if (!access->representation) { + return nullptr; + } + access->read_access = access->representation->BeginScopedReadAccess(); resource_shared_images_.emplace(id, std::move(access)); } @@ -80,13 +84,15 @@ return resource; } -void DisplayResourceProviderSoftware::UnlockForRead(ResourceId id) { +void DisplayResourceProviderSoftware::UnlockForRead(ResourceId id, + const SkImage* sk_image) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); ChildResource* resource = GetResource(id); - DCHECK(!resource->is_gpu_resource_type()); - DCHECK_GT(resource->lock_for_read_count, 0); - resource->lock_for_read_count--; + if (sk_image) { + DCHECK_GE(resource->lock_for_read_count, 0); + resource->lock_for_read_count--; + } TryReleaseResource(id, resource); } @@ -159,7 +165,9 @@ SkAlphaType alpha_type) : resource_provider_(resource_provider), resource_id_(resource_id) { const ChildResource* resource = resource_provider->LockForRead(resource_id); - DCHECK(resource); + if (!resource) { + return; + } DCHECK(!resource->is_gpu_resource_type()); // Use cached SkImage if possible. @@ -209,7 +217,7 @@ DisplayResourceProviderSoftware::ScopedReadLockSkImage:: ~ScopedReadLockSkImage() { - resource_provider_->UnlockForRead(resource_id_); + resource_provider_->UnlockForRead(resource_id_, sk_image_.get()); } DisplayResourceProviderSoftware::SharedImageAccess::SharedImageAccess() =
diff --git a/components/viz/service/display/display_resource_provider_software.h b/components/viz/service/display/display_resource_provider_software.h index b88e26a..d5595fef4 100644 --- a/components/viz/service/display/display_resource_provider_software.h +++ b/components/viz/service/display/display_resource_provider_software.h
@@ -62,7 +62,7 @@ // These functions are used by ScopedReadLockSkImage to lock and unlock // resources. const ChildResource* LockForRead(ResourceId id); - void UnlockForRead(ResourceId id); + void UnlockForRead(ResourceId id, const SkImage* sk_image); // DisplayResourceProvider overrides: std::vector<ReturnedResource> DeleteAndReturnUnusedResourcesToChildImpl(
diff --git a/components/web_package/signed_web_bundles/signed_web_bundle_id.cc b/components/web_package/signed_web_bundles/signed_web_bundle_id.cc index 5527e98..be1f7d6 100644 --- a/components/web_package/signed_web_bundles/signed_web_bundle_id.cc +++ b/components/web_package/signed_web_bundles/signed_web_bundle_id.cc
@@ -85,9 +85,9 @@ // static SignedWebBundleId SignedWebBundleId::CreateRandomForDevelopment( - base::RepeatingCallback<void(void*, size_t)> random_generator) { + base::RepeatingCallback<void(base::span<uint8_t>)> random_generator) { std::array<uint8_t, kDecodedIdLength - kTypeSuffixLength> random_bytes; - random_generator.Run(random_bytes.data(), random_bytes.size()); + random_generator.Run(random_bytes); return CreateForDevelopment(random_bytes); } @@ -104,9 +104,12 @@ SignedWebBundleId::~SignedWebBundleId() = default; // static -base::RepeatingCallback<void(void*, size_t)> +base::RepeatingCallback<void(base::span<uint8_t>)> SignedWebBundleId::GetDefaultRandomGenerator() { - return base::BindRepeating(&base::RandBytes); + // TODO(crbug.com/1490484): Remove the static_cast once all callers of + // base::RandBytes are migrated to the span variant. + return base::BindRepeating( + static_cast<void (*)(base::span<uint8_t>)>(&base::RandBytes)); } } // namespace web_package
diff --git a/components/web_package/signed_web_bundles/signed_web_bundle_id.h b/components/web_package/signed_web_bundles/signed_web_bundle_id.h index b6eb78f91..f1c155a 100644 --- a/components/web_package/signed_web_bundles/signed_web_bundle_id.h +++ b/components/web_package/signed_web_bundles/signed_web_bundle_id.h
@@ -5,6 +5,7 @@ #ifndef COMPONENTS_WEB_PACKAGE_SIGNED_WEB_BUNDLES_SIGNED_WEB_BUNDLE_ID_H_ #define COMPONENTS_WEB_PACKAGE_SIGNED_WEB_BUNDLES_SIGNED_WEB_BUNDLE_ID_H_ +#include "base/containers/span.h" #include "base/functional/callback.h" #include "base/strings/string_piece.h" #include "base/types/expected.h" @@ -55,7 +56,7 @@ base::span<const uint8_t, kDecodedIdLength - kTypeSuffixLength> data); static SignedWebBundleId CreateRandomForDevelopment( - base::RepeatingCallback<void(void*, size_t)> random_generator = + base::RepeatingCallback<void(base::span<uint8_t>)> random_generator = GetDefaultRandomGenerator()); SignedWebBundleId(const SignedWebBundleId& other); @@ -87,7 +88,7 @@ std::string encoded_id_; std::array<uint8_t, kDecodedIdLength> decoded_id_; - static base::RepeatingCallback<void(void*, size_t)> + static base::RepeatingCallback<void(base::span<uint8_t>)> GetDefaultRandomGenerator(); };
diff --git a/components/web_package/signed_web_bundles/signed_web_bundle_id_unittest.cc b/components/web_package/signed_web_bundles/signed_web_bundle_id_unittest.cc index ed5630a..44b7a66 100644 --- a/components/web_package/signed_web_bundles/signed_web_bundle_id_unittest.cc +++ b/components/web_package/signed_web_bundles/signed_web_bundle_id_unittest.cc
@@ -153,9 +153,9 @@ TEST(SignedWebBundleIdTest, CreateRandomForDevelopmentCustomGenerator) { auto custom_callback = - base::BindLambdaForTesting([](void* ptr, size_t len) -> void { - DCHECK_EQ(len, kDevelopmentBytes.size()); - base::ranges::copy(kDevelopmentBytes, static_cast<uint8_t*>(ptr)); + base::BindLambdaForTesting([](base::span<uint8_t> buffer) -> void { + DCHECK_EQ(buffer.size(), kDevelopmentBytes.size()); + base::ranges::copy(kDevelopmentBytes, buffer.begin()); }); SignedWebBundleId id =
diff --git a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc index 03bcd106..729f4a2 100644 --- a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc +++ b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
@@ -3013,6 +3013,11 @@ FILE_PATH_LITERAL("progress-with-background-exposes-values.html")); } +IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest, + AccessibilityProgressMeterCrash) { + RunFormControlsTest(FILE_PATH_LITERAL("progress-meter-crash.html")); +} + IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest, AccessibilityQ) { RunHtmlTest(FILE_PATH_LITERAL("q.html")); }
diff --git a/content/browser/attribution_reporting/attribution_host.cc b/content/browser/attribution_reporting/attribution_host.cc index ef2aa7f..74317e16 100644 --- a/content/browser/attribution_reporting/attribution_host.cc +++ b/content/browser/attribution_reporting/attribution_host.cc
@@ -322,6 +322,11 @@ return absl::nullopt; } + if (!render_frame_host->IsFeatureEnabled( + blink::mojom::PermissionsPolicyFeature::kAttributionReporting)) { + return absl::nullopt; + } + return suitable_top_frame_origin; }
diff --git a/content/browser/attribution_reporting/attribution_host_unittest.cc b/content/browser/attribution_reporting/attribution_host_unittest.cc index 467bf59b..0bfd986 100644 --- a/content/browser/attribution_reporting/attribution_host_unittest.cc +++ b/content/browser/attribution_reporting/attribution_host_unittest.cc
@@ -129,6 +129,16 @@ fenced_frame_node->set_fenced_frame_properties(new_props); } + blink::ParsedPermissionsPolicy RestrictivePermissionsPolicy( + const url::Origin& allowed_origin) { + return {blink::ParsedPermissionsPolicyDeclaration( + blink::mojom::PermissionsPolicyFeature::kAttributionReporting, + /*allowed_origins=*/ + {*blink::OriginWithPossibleWildcards::FromOrigin(allowed_origin)}, + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, /*matches_opaque_src=*/false)}; + } + void ClearAttributionManager() { mock_data_host_manager_ = nullptr; OverrideAttributionManager(nullptr); @@ -650,6 +660,7 @@ static_cast<RenderFrameHostImpl*>(fenced_frame) ->frame_tree_node() ->SetFencedFramePropertiesOpaqueAdsModeForTesting(); + SetFencedFrameConfigPermissions(fenced_frame); fenced_frame = NavigationSimulatorImpl::NavigateAndCommitFromDocument( GURL("https://fencedframe.example"), fenced_frame); ScopedAttributionHostTargetFrame frame_scope(attribution_host(), @@ -768,14 +779,8 @@ auto simulator = NavigationSimulatorImpl::CreateRendererInitiated( GURL(test_case.fenced_frame_url), fenced_frame); - simulator->SetPermissionsPolicyHeader( - {blink::ParsedPermissionsPolicyDeclaration( - blink::mojom::PermissionsPolicyFeature::kAttributionReporting, - /*allowed_origins=*/ - {*blink::OriginWithPossibleWildcards::FromOrigin( - url::Origin::Create(GURL(kAllowedOriginUrl)))}, - /*self_if_matches=*/absl::nullopt, - /*matches_all_origins=*/false, /*matches_opaque_src=*/false)}); + simulator->SetPermissionsPolicyHeader(RestrictivePermissionsPolicy( + url::Origin::Create(GURL(kAllowedOriginUrl)))); simulator->Commit(); fenced_frame = simulator->GetFinalRenderFrameHost(); @@ -806,12 +811,8 @@ auto simulator1 = NavigationSimulatorImpl::CreateRendererInitiated( GURL(test_case.url), main_rfh()); - simulator1->SetPermissionsPolicyHeader( - {blink::ParsedPermissionsPolicyDeclaration( - blink::mojom::PermissionsPolicyFeature::kAttributionReporting, - /*allowed_origins=*/{}, - /*self_if_matches*/ url::Origin::Create(GURL(kAllowedOriginUrl)), - /*matches_all_origins=*/false, /*matches_opaque_src=*/false)}); + simulator1->SetPermissionsPolicyHeader(RestrictivePermissionsPolicy( + url::Origin::Create(GURL(kAllowedOriginUrl)))); simulator1->Commit(); auto simulator2 = NavigationSimulatorImpl::CreateRendererInitiated( @@ -822,6 +823,122 @@ } } +TEST_F(AttributionHostTest, RegisterDataHost_FeaturePolicyChecked) { + contents()->NavigateAndCommit(GURL("https://top.example")); + + static constexpr char kAllowedOriginUrl[] = "https://a.test"; + + const struct { + const char* subframe_url; + bool expected; + } kTestCases[] = { + {kAllowedOriginUrl, true}, + {"https://b.test", false}, + }; + + for (const auto& test_case : kTestCases) { + EXPECT_CALL(*mock_data_host_manager(), RegisterDataHost) + .Times(test_case.expected); + + content::RenderFrameHostTester* rfh_tester = + content::RenderFrameHostTester::For(main_rfh()); + content::RenderFrameHost* subframe = rfh_tester->AppendChildWithPolicy( + "subframe", RestrictivePermissionsPolicy( + url::Origin::Create(GURL(kAllowedOriginUrl)))); + subframe = NavigationSimulatorImpl::NavigateAndCommitFromDocument( + GURL(test_case.subframe_url), subframe); + ScopedAttributionHostTargetFrame frame_scope(attribution_host(), subframe); + + mojo::Remote<blink::mojom::AttributionDataHost> data_host_remote; + attribution_host_mojom()->RegisterDataHost( + data_host_remote.BindNewPipeAndPassReceiver(), + RegistrationEligibility::kSource); + + base::RunLoop().RunUntilIdle(); + } +} +TEST_F(AttributionHostTest, RegisterNavigationDataHost_FeaturePolicyChecked) { + contents()->NavigateAndCommit(GURL("https://top.example")); + + static constexpr char kAllowedOriginUrl[] = "https://a.test"; + + const struct { + const char* subframe_url; + bool expected; + } kTestCases[] = { + {kAllowedOriginUrl, true}, + {"https://b.test", false}, + }; + + for (const auto& test_case : kTestCases) { + if (test_case.expected) { + EXPECT_CALL(*mock_data_host_manager(), RegisterNavigationDataHost) + .WillOnce(Return(true)); + } else { + EXPECT_CALL(*mock_data_host_manager(), RegisterNavigationDataHost) + .Times(0); + } + + content::RenderFrameHostTester* rfh_tester = + content::RenderFrameHostTester::For(main_rfh()); + content::RenderFrameHost* subframe = rfh_tester->AppendChildWithPolicy( + "subframe", RestrictivePermissionsPolicy( + url::Origin::Create(GURL(kAllowedOriginUrl)))); + subframe = NavigationSimulatorImpl::NavigateAndCommitFromDocument( + GURL(test_case.subframe_url), subframe); + ScopedAttributionHostTargetFrame frame_scope(attribution_host(), subframe); + + mojo::Remote<blink::mojom::AttributionDataHost> data_host_remote; + attribution_host_mojom()->RegisterNavigationDataHost( + data_host_remote.BindNewPipeAndPassReceiver(), + blink::AttributionSrcToken()); + + base::RunLoop().RunUntilIdle(); + } +} +TEST_F( + AttributionHostTest, + NotifyNavigationWithBackgroundRegistrationsWillStart_FeaturePolicyChecked) { + contents()->NavigateAndCommit(GURL("https://top.example")); + + static constexpr char kAllowedOriginUrl[] = "https://a.test"; + + const struct { + const char* subframe_url; + bool expected; + } kTestCases[] = { + {kAllowedOriginUrl, true}, + {"https://b.test", false}, + }; + + for (const auto& test_case : kTestCases) { + if (test_case.expected) { + EXPECT_CALL(*mock_data_host_manager(), + NotifyNavigationWithBackgroundRegistrationsWillStart) + .WillOnce(Return(true)); + } else { + EXPECT_CALL(*mock_data_host_manager(), + NotifyNavigationWithBackgroundRegistrationsWillStart) + .Times(0); + } + + content::RenderFrameHostTester* rfh_tester = + content::RenderFrameHostTester::For(main_rfh()); + content::RenderFrameHost* subframe = rfh_tester->AppendChildWithPolicy( + "subframe", RestrictivePermissionsPolicy( + url::Origin::Create(GURL(kAllowedOriginUrl)))); + subframe = NavigationSimulatorImpl::NavigateAndCommitFromDocument( + GURL(test_case.subframe_url), subframe); + ScopedAttributionHostTargetFrame frame_scope(attribution_host(), subframe); + + attribution_host_mojom() + ->NotifyNavigationWithBackgroundRegistrationsWillStart( + blink::AttributionSrcToken(), /*expected_registrations=*/1); + + base::RunLoop().RunUntilIdle(); + } +} + TEST_F(AttributionHostTest, InsecureTaintTracking) { blink::Impression impression;
diff --git a/content/browser/back_forward_cache_features_browsertest.cc b/content/browser/back_forward_cache_features_browsertest.cc index 85fd7cc0..38ac662 100644 --- a/content/browser/back_forward_cache_features_browsertest.cc +++ b/content/browser/back_forward_cache_features_browsertest.cc
@@ -4978,13 +4978,19 @@ } }; -// TODO(crbug.com/1491942): This fails with the field trial testing config. class BackForwardCacheBrowserTestWithMediaSessionNoTestingConfig : public BackForwardCacheBrowserTestWithMediaSession { public: void SetUpCommandLine(base::CommandLine* command_line) override { - command_line->AppendSwitch("disable-field-trial-config"); DisableFeature(features::kBackForwardCacheMediaSessionService); + + // The MediaSessionEnterPictureInPicture feature depends on the + // BackForwardCacheMediaSessionService feature, so we need to also disable + // it here. + // TODO(https://crbug.com/1510995): Remove these tests since the + // BackForwardCacheMediaSessionService feature has been launched. + DisableFeature(blink::features::kMediaSessionEnterPictureInPicture); + BackForwardCacheBrowserTestWithMediaSession::SetUpCommandLine(command_line); } };
diff --git a/content/browser/media/session/media_session_impl.cc b/content/browser/media/session/media_session_impl.cc index cac23a8..6e9c975 100644 --- a/content/browser/media/session/media_session_impl.cc +++ b/content/browser/media/session/media_session_impl.cc
@@ -177,6 +177,11 @@ } // static +MediaSession* MediaSession::GetIfExists(WebContents* contents) { + return MediaSessionImpl::FromWebContents(contents); +} + +// static const base::UnguessableToken& MediaSession::GetSourceId( BrowserContext* browser_context) { return MediaSessionData::GetOrCreate(browser_context)->source_id(); @@ -231,6 +236,7 @@ CreateForWebContents(web_contents); session = FromWebContents(web_contents); session->Initialize(); + static_cast<WebContentsImpl*>(web_contents)->MediaSessionCreated(session); } return session; }
diff --git a/content/browser/renderer_host/navigation_entry_impl.cc b/content/browser/renderer_host/navigation_entry_impl.cc index bca3f67..d3fd2fb 100644 --- a/content/browser/renderer_host/navigation_entry_impl.cc +++ b/content/browser/renderer_host/navigation_entry_impl.cc
@@ -512,6 +512,14 @@ return title_; } +void NavigationEntryImpl::SetAppTitle(const std::u16string& app_title) { + app_title_ = app_title; +} + +const std::u16string& NavigationEntryImpl::GetAppTitle() { + return app_title_; +} + void NavigationEntryImpl::SetPageState(const blink::PageState& state, NavigationEntryRestoreContext* context) { DCHECK(state.IsValid());
diff --git a/content/browser/renderer_host/navigation_entry_impl.h b/content/browser/renderer_host/navigation_entry_impl.h index e48b6870..5c073400 100644 --- a/content/browser/renderer_host/navigation_entry_impl.h +++ b/content/browser/renderer_host/navigation_entry_impl.h
@@ -138,6 +138,8 @@ const GURL& GetVirtualURL() override; void SetTitle(const std::u16string& title) override; const std::u16string& GetTitle() override; + void SetAppTitle(const std::u16string& app_title) override; + const std::u16string& GetAppTitle() override; void SetPageState(const blink::PageState& state, NavigationEntryRestoreContext* context) override; blink::PageState GetPageState() override; @@ -535,6 +537,11 @@ GURL virtual_url_; bool update_virtual_url_with_url_; std::u16string title_; + // The app title is optional and may be empty. If set to a non-empty value, a + // web app displayed in an app window may use this string instead of the + // regular title. See + // https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/DocumentSubtitle/explainer.md + std::u16string app_title_; FaviconStatus favicon_; SSLStatus ssl_; ui::PageTransition transition_type_;
diff --git a/content/browser/renderer_host/render_frame_host_delegate.h b/content/browser/renderer_host/render_frame_host_delegate.h index 99619b7..472e4d0 100644 --- a/content/browser/renderer_host/render_frame_host_delegate.h +++ b/content/browser/renderer_host/render_frame_host_delegate.h
@@ -255,6 +255,10 @@ const std::u16string& title, base::i18n::TextDirection title_direction) {} + // Update app title. + virtual void UpdateAppTitle(RenderFrameHostImpl* render_frame_host, + const std::u16string& app_title) {} + // The destination URL has changed and should be updated. virtual void UpdateTargetURL(RenderFrameHostImpl* render_frame_host, const GURL& url) {}
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc index cc4841dc..77ff4f22 100644 --- a/content/browser/renderer_host/render_frame_host_impl.cc +++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -6661,6 +6661,11 @@ delegate_->UpdateTitle(this, received_title, title_direction); } +// Update app title. +void RenderFrameHostImpl::UpdateAppTitle(const ::std::u16string& app_title) { + delegate_->UpdateAppTitle(this, app_title); +} + void RenderFrameHostImpl::DidInferColorScheme( blink::mojom::PreferredColorScheme color_scheme) { if (is_main_frame()) {
diff --git a/content/browser/renderer_host/render_frame_host_impl.h b/content/browser/renderer_host/render_frame_host_impl.h index 5ecccb9..500f4765 100644 --- a/content/browser/renderer_host/render_frame_host_impl.h +++ b/content/browser/renderer_host/render_frame_host_impl.h
@@ -2337,6 +2337,7 @@ void NavigateEventHandlerPresenceChanged(bool present) override; void UpdateTitle(const absl::optional<::std::u16string>& title, base::i18n::TextDirection title_direction) override; + void UpdateAppTitle(const ::std::u16string& app_title) override; void UpdateUserActivationState( blink::mojom::UserActivationUpdateType update_type, blink::mojom::UserActivationNotificationType notification_type) override;
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc index c65048c2..3c2d09a 100644 --- a/content/browser/web_contents/web_contents_impl.cc +++ b/content/browser/web_contents/web_contents_impl.cc
@@ -2195,6 +2195,10 @@ return GetNavigationEntryForTitle()->GetTitleForDisplay(); } +const std::u16string& WebContentsImpl::GetAppTitle() { + return GetNavigationEntryForTitle()->GetAppTitle(); +} + SiteInstanceImpl* WebContentsImpl::GetSiteInstance() { return GetRenderManager()->current_frame_host()->GetSiteInstance(); } @@ -8419,6 +8423,36 @@ } } +void WebContentsImpl::UpdateAppTitle(RenderFrameHostImpl* render_frame_host, + const std::u16string& app_title) { + OPTIONAL_TRACE_EVENT2("content", "WebContentsImpl::UpdateTitle", + "render_frame_host", render_frame_host, "app_title", + app_title); + // Same logic as UpdateTitle() above. + NavigationEntryImpl* entry = + render_frame_host->frame_tree()->controller().GetEntryWithUniqueID( + render_frame_host->nav_entry_id()); + if (!entry) { + if (render_frame_host->GetParent() || !render_frame_host->frame_tree() + ->controller() + .GetLastCommittedEntry() + ->IsInitialEntry()) { + return; + } + entry = + render_frame_host->frame_tree()->controller().GetLastCommittedEntry(); + } + std::u16string final_app_title; + base::TrimWhitespace(app_title, base::TRIM_ALL, &final_app_title); + + if (final_app_title == entry->GetAppTitle()) { + return; + } + + entry->SetAppTitle(final_app_title); + NotifyNavigationStateChanged(INVALIDATE_TYPE_TITLE); +} + void WebContentsImpl::UpdateTargetURL(RenderFrameHostImpl* render_frame_host, const GURL& url) { OPTIONAL_TRACE_EVENT2("content", "WebContentsImpl::UpdateTargetURL", @@ -9712,6 +9746,11 @@ observers_.NotifyObservers(&WebContentsObserver::MediaDestroyed, id); } +void WebContentsImpl::MediaSessionCreated(MediaSession* media_session) { + observers_.NotifyObservers(&WebContentsObserver::MediaSessionCreated, + media_session); +} + int WebContentsImpl::GetCurrentlyPlayingVideoCount() { return currently_playing_video_count_; }
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h index 3ba96d4a..e66c4b1e 100644 --- a/content/browser/web_contents/web_contents_impl.h +++ b/content/browser/web_contents/web_contents_impl.h
@@ -121,6 +121,7 @@ class BrowserPluginGuest; class FindRequestManager; class JavaScriptDialogManager; +class MediaSession; class MediaWebContentsObserver; class NFCHost; class RenderFrameHost; @@ -375,6 +376,7 @@ bool IsWebContentsOnlyAccessibilityModeForTesting() override; bool IsFullAccessibilityModeForTesting() override; const std::u16string& GetTitle() override; + const std::u16string& GetAppTitle() override; void UpdateTitleForEntry(NavigationEntry* entry, const std::u16string& title) override; SiteInstanceImpl* GetSiteInstance() override; @@ -640,6 +642,12 @@ void UpdateTitle(RenderFrameHostImpl* render_frame_host, const std::u16string& title, base::i18n::TextDirection title_direction) override; + // The app title is an alternative title. If non-empty, the browser may choose + // to use the app title instead of the regular title for a web app displayed + // in an app window. See + // https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/DocumentSubtitle/explainer.md + void UpdateAppTitle(RenderFrameHostImpl* render_frame_host, + const std::u16string& app_title) override; void UpdateTargetURL(RenderFrameHostImpl* render_frame_host, const GURL& url) override; bool IsNeverComposited() override; @@ -1139,6 +1147,9 @@ // Called by MediaWebContentsObserver when a media player is destroyed. void MediaDestroyed(const MediaPlayerId& id); + // Called by MediaSessionImpl when one is created and initialized for this. + void MediaSessionCreated(MediaSession* media_session); + int GetCurrentlyPlayingVideoCount() override; absl::optional<gfx::Size> GetFullscreenVideoSize() override;
diff --git a/content/browser/web_contents/web_contents_impl_browsertest.cc b/content/browser/web_contents/web_contents_impl_browsertest.cc index 69582f9e..3c1b1908 100644 --- a/content/browser/web_contents/web_contents_impl_browsertest.cc +++ b/content/browser/web_contents/web_contents_impl_browsertest.cc
@@ -4518,10 +4518,9 @@ // frame and mouse up is on OOF iframe, the mouse up event is delivered to the // main frame as well to clear cached mouse states including autoscroll // selection state. -// TODO(crbug.com/1512574): This test was detected flaky. IN_PROC_BROWSER_TEST_F( WebContentsImplBrowserTest, - DISABLED_MouseUpInOOPIframeShouldCancelMainFrameAutoscrollSelection) { + MouseUpInOOPIframeShouldCancelMainFrameAutoscrollSelection) { ASSERT_TRUE(embedded_test_server()->Start()); WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(shell()->web_contents()); @@ -4575,12 +4574,24 @@ ui::DomCode::US_A, ui::VKEY_A, false, false, false, false); SimulateKeyPress(web_contents, ui::DomKey::FromCharacter('B'), ui::DomCode::US_B, ui::VKEY_B, false, false, false, false); - RunUntilInputProcessed(web_contents->GetRenderWidgetHostWithPageFocus()); + EXPECT_TRUE(ExecJs(web_contents, + "var inputElement = document.getElementById('input1');" + "new Promise(function(resolve) {" + " if (inputElement.value == 'AB')" + " resolve(true);" + " inputElement.addEventListener('change', () => {" + " if (inputElement.value == 'AB')" + " resolve(true);" + " });" + "});")); EXPECT_EQ("AB", EvalJs(web_contents, "document.getElementById('input1').value") .ExtractString()); EXPECT_TRUE(ExecJs(web_contents, + "document.addEventListener('mousedown', () => { " + "window.receivedMouseDown = true; });")); + EXPECT_TRUE(ExecJs(web_contents, "document.addEventListener('mouseup', () => { " "window.receivedMouseUp = true; });")); @@ -4605,7 +4616,10 @@ blink::WebMouseEvent::Button::kLeft, gfx::Point(iframe_center_x, input_center_y)); RunUntilInputProcessed(web_contents->GetRenderWidgetHostWithPageFocus()); - + EXPECT_TRUE(ExecJs(web_contents, + "new Promise(resolve => setTimeout(() => {" + " resolve(window.receivedMouseDown);" + "}));")); EXPECT_TRUE(web_contents->GetInputEventRouter() ->root_view_receive_additional_mouse_up_); @@ -4613,20 +4627,29 @@ blink::WebMouseEvent::Button::kLeft, gfx::Point(iframe_center_x, input_center_y)); RunUntilInputProcessed(web_contents->GetRenderWidgetHostWithPageFocus()); - + // Main frame should receive mouse up event. + EXPECT_TRUE(ExecJs(web_contents, + "new Promise(resolve => setTimeout(() => {" + " resolve(window.receivedMouseUp);" + "}));")); EXPECT_FALSE(web_contents->GetInputEventRouter() ->root_view_receive_additional_mouse_up_); - // Main frame should receive mouse up event. - EXPECT_TRUE(EvalJs(web_contents, "window.receivedMouseUp").ExtractBool()); - // Type again in input element, insert text should be left to right. SimulateKeyPress(web_contents, ui::DomKey::FromCharacter('E'), ui::DomCode::US_E, ui::VKEY_E, false, false, false, false); SimulateKeyPress(web_contents, ui::DomKey::FromCharacter('F'), ui::DomCode::US_F, ui::VKEY_F, false, false, false, false); - RunUntilInputProcessed(web_contents->GetRenderWidgetHostWithPageFocus()); - + EXPECT_TRUE(ExecJs(web_contents, + "var inputElement = document.getElementById('input1');" + "new Promise(function(resolve) {" + " if (inputElement.value == 'EF')" + " resolve(true);" + " inputElement.addEventListener('change', () => {" + " if (inputElement.value == 'EF')" + " resolve(true);" + " });" + "});")); EXPECT_EQ("EF", EvalJs(web_contents, "document.getElementById('input1').value") .ExtractString());
diff --git a/content/ppapi_plugin/ppapi_blink_platform_impl.cc b/content/ppapi_plugin/ppapi_blink_platform_impl.cc index 615e5b0..74c84d8 100644 --- a/content/ppapi_plugin/ppapi_blink_platform_impl.cc +++ b/content/ppapi_plugin/ppapi_blink_platform_impl.cc
@@ -9,6 +9,7 @@ #include <map> #include <memory> #include <string> +#include <string_view> #include "base/notreached.h" #include "base/threading/platform_thread.h" @@ -61,8 +62,8 @@ #endif } -uint64_t PpapiBlinkPlatformImpl::VisitedLinkHash(const char* canonical_url, - size_t length) { +uint64_t PpapiBlinkPlatformImpl::VisitedLinkHash( + std::string_view canonical_url) { NOTREACHED(); return 0; }
diff --git a/content/ppapi_plugin/ppapi_blink_platform_impl.h b/content/ppapi_plugin/ppapi_blink_platform_impl.h index c1edbed..aa30da40 100644 --- a/content/ppapi_plugin/ppapi_blink_platform_impl.h +++ b/content/ppapi_plugin/ppapi_blink_platform_impl.h
@@ -8,6 +8,7 @@ #include <stddef.h> #include <memory> +#include <string_view> #include "build/build_config.h" #include "content/child/blink_platform_impl.h" @@ -28,7 +29,7 @@ // BlinkPlatformImpl methods: blink::WebSandboxSupport* GetSandboxSupport() override; - uint64_t VisitedLinkHash(const char* canonical_url, size_t length) override; + uint64_t VisitedLinkHash(std::string_view canonical_url) override; bool IsLinkVisited(uint64_t link_hash) override; blink::WebString DefaultLocale() override;
diff --git a/content/public/browser/media_session.h b/content/public/browser/media_session.h index e02511c..fca03cc5 100644 --- a/content/public/browser/media_session.h +++ b/content/public/browser/media_session.h
@@ -30,6 +30,10 @@ // none is currently available. CONTENT_EXPORT static MediaSession* Get(WebContents* contents); + // Returns the MediaSession associated to this WebContents if it already + // exists. Returns null otherwise. + CONTENT_EXPORT static MediaSession* GetIfExists(WebContents* contents); + // Returns the source identity for the given BrowserContext. CONTENT_EXPORT static const base::UnguessableToken& GetSourceId( BrowserContext* browser_context);
diff --git a/content/public/browser/navigation_entry.h b/content/public/browser/navigation_entry.h index a79b3fc..f37dab4e 100644 --- a/content/public/browser/navigation_entry.h +++ b/content/public/browser/navigation_entry.h
@@ -110,6 +110,12 @@ virtual void SetTitle(const std::u16string& title) = 0; virtual const std::u16string& GetTitle() = 0; + // The app title as set by the page. This will be empty if there is no app + // title set. This information is provided by an experimental meta tag. See: + // https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/DocumentSubtitle/explainer.md + virtual void SetAppTitle(const std::u16string& app_title) = 0; + virtual const std::u16string& GetAppTitle() = 0; + // Page state is an opaque blob created by Blink that represents the state of // the page. This includes form entries and scroll position for each frame. // We store it so that we can supply it back to Blink to restore form state
diff --git a/content/public/browser/web_contents.h b/content/public/browser/web_contents.h index 0daa926..248b0111 100644 --- a/content/public/browser/web_contents.h +++ b/content/public/browser/web_contents.h
@@ -639,6 +639,12 @@ virtual void UpdateTitleForEntry(NavigationEntry* entry, const std::u16string& title) = 0; + // Returns app title of the current navigation entry. The apptitle is + // an alternative title text that can be used by app windows. + // See + // https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/DocumentSubtitle/explainer.md + virtual const std::u16string& GetAppTitle() = 0; + // Returns the SiteInstance associated with the current page. virtual SiteInstance* GetSiteInstance() = 0;
diff --git a/content/public/browser/web_contents_observer.h b/content/public/browser/web_contents_observer.h index a3b5e3b..58c1d39f 100644 --- a/content/public/browser/web_contents_observer.h +++ b/content/public/browser/web_contents_observer.h
@@ -57,6 +57,7 @@ namespace content { +class MediaSession; class NavigationEntry; class NavigationHandle; class RenderFrameHost; @@ -814,6 +815,10 @@ virtual void MediaMutedStatusChanged(const MediaPlayerId& id, bool muted) {} virtual void MediaDestroyed(const MediaPlayerId& id) {} + // Invoked when a MediaSession associated with this WebContents has been + // created and initialized. + virtual void MediaSessionCreated(MediaSession* media_session) {} + // Invoked when the renderer process changes the page scale factor. virtual void OnPageScaleFactorChanged(float page_scale_factor) {}
diff --git a/content/public/renderer/content_renderer_client.cc b/content/public/renderer/content_renderer_client.cc index ae07dcf..440ebd5 100644 --- a/content/public/renderer/content_renderer_client.cc +++ b/content/public/renderer/content_renderer_client.cc
@@ -4,6 +4,8 @@ #include "content/public/renderer/content_renderer_client.h" +#include <string_view> + #include "base/command_line.h" #include "base/task/sequenced_task_runner.h" #include "base/task/single_thread_task_runner.h" @@ -135,8 +137,8 @@ return false; } -uint64_t ContentRendererClient::VisitedLinkHash(const char* canonical_url, - size_t length) { +uint64_t ContentRendererClient::VisitedLinkHash( + std::string_view canonical_url) { return 0; }
diff --git a/content/public/renderer/content_renderer_client.h b/content/public/renderer/content_renderer_client.h index 72f72e2c..9cbf626 100644 --- a/content/public/renderer/content_renderer_client.h +++ b/content/public/renderer/content_renderer_client.h
@@ -10,6 +10,7 @@ #include <map> #include <memory> #include <string> +#include <string_view> #include <vector> #include "base/files/file_path.h" @@ -260,7 +261,7 @@ virtual bool IsPrefetchOnly(RenderFrame* render_frame); // See blink::Platform. - virtual uint64_t VisitedLinkHash(const char* canonical_url, size_t length); + virtual uint64_t VisitedLinkHash(std::string_view canonical_url); virtual bool IsLinkVisited(uint64_t link_hash); // Creates a WebPrescientNetworking instance for |render_frame|. The returned
diff --git a/content/renderer/renderer_blink_platform_impl.cc b/content/renderer/renderer_blink_platform_impl.cc index 0557627..fa7c9cc 100644 --- a/content/renderer/renderer_blink_platform_impl.cc +++ b/content/renderer/renderer_blink_platform_impl.cc
@@ -6,6 +6,7 @@ #include <algorithm> #include <memory> +#include <string_view> #include <utility> #include <vector> @@ -279,9 +280,9 @@ switches::kSingleProcess); } -uint64_t RendererBlinkPlatformImpl::VisitedLinkHash(const char* canonical_url, - size_t length) { - return GetContentClient()->renderer()->VisitedLinkHash(canonical_url, length); +uint64_t RendererBlinkPlatformImpl::VisitedLinkHash( + std::string_view canonical_url) { + return GetContentClient()->renderer()->VisitedLinkHash(canonical_url); } bool RendererBlinkPlatformImpl::IsLinkVisited(uint64_t link_hash) {
diff --git a/content/renderer/renderer_blink_platform_impl.h b/content/renderer/renderer_blink_platform_impl.h index 9ff612d..5e505892 100644 --- a/content/renderer/renderer_blink_platform_impl.h +++ b/content/renderer/renderer_blink_platform_impl.h
@@ -10,6 +10,7 @@ #include <memory> #include <string> +#include <string_view> #include "base/containers/id_map.h" #include "base/memory/raw_ptr.h" @@ -78,7 +79,7 @@ // blink::Platform implementation. blink::WebSandboxSupport* GetSandboxSupport() override; virtual bool sandboxEnabled(); - uint64_t VisitedLinkHash(const char* canonicalURL, size_t length) override; + uint64_t VisitedLinkHash(std::string_view canonical_url) override; bool IsLinkVisited(uint64_t linkHash) override; blink::WebString UserAgent() override; blink::UserAgentMetadata UserAgentMetadata() override;
diff --git a/content/test/content_test_bundle_data.filelist b/content/test/content_test_bundle_data.filelist index 1946d24..76ae288 100644 --- a/content/test/content_test_bundle_data.filelist +++ b/content/test/content_test_bundle_data.filelist
@@ -2628,6 +2628,7 @@ data/accessibility/form-controls/img-form.html data/accessibility/form-controls/img-map-pseudo.html data/accessibility/form-controls/map-inside-map.html +data/accessibility/form-controls/progress-meter-crash.html data/accessibility/form-controls/role-group-expected-android.txt data/accessibility/form-controls/role-group-expected-blink.txt data/accessibility/form-controls/role-group.html
diff --git a/content/test/data/accessibility/form-controls/progress-meter-crash.html b/content/test/data/accessibility/form-controls/progress-meter-crash.html new file mode 100644 index 0000000..0ed5c821 --- /dev/null +++ b/content/test/data/accessibility/form-controls/progress-meter-crash.html
@@ -0,0 +1,10 @@ +<script> +document.addEventListener("DOMContentLoaded", () => { + document.getElementById('div').setAttribute('aria-owns','bold') +}); +</script> +<progress> + <b id="bold"> +</progress> +<div id='div'> +
diff --git a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt index 925d5f41e..38a56a94 100644 --- a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
@@ -973,6 +973,15 @@ crbug.com/1448570 [ android android-pixel-2 angle-disabled no-passthrough ] conformance/extensions/webgl-compressed-texture-etc1.html [ Failure ] crbug.com/1448569 [ win angle-d3d11 ] conformance2/glsl3/texture-bias.html [ Failure ] +################################################################# +# Temporary suppressions for introduction of drawingBufferStorage +################################################################# +crbug.com/1230619 conformance/offscreencanvas/methods-worker.html [ Failure ] +crbug.com/1230619 conformance/offscreencanvas/methods.html [ Failure ] +crbug.com/1230619 conformance2/context/constants-and-properties-2.html [ Failure ] +crbug.com/1230619 conformance2/offscreencanvas/methods-2-worker.html [ Failure ] +crbug.com/1230619 conformance2/offscreencanvas/methods-2.html [ Failure ] + ####################################################################### # Automated Entries After This Point - Do Not Manually Add Below Here # #######################################################################
diff --git a/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt index 18b1cc3..20a9d67 100644 --- a/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt
@@ -737,6 +737,13 @@ crbug.com/1448743 [ android-nexus-5x ] conformance/textures/misc/texture-srgb-upload.html [ Failure ] crbug.com/1448743 [ angle-disabled chromeos chromeos-board-amd64-generic no-passthrough ] conformance/textures/misc/texture-srgb-upload.html [ Failure ] +################################################################# +# Temporary suppressions for introduction of drawingBufferStorage +################################################################# +crbug.com/1230619 conformance/context/constants-and-properties.html [ Failure ] +crbug.com/1230619 conformance/offscreencanvas/methods-worker.html [ Failure ] +crbug.com/1230619 conformance/offscreencanvas/methods.html [ Failure ] + ####################################################################### # Automated Entries After This Point - Do Not Manually Add Below Here # #######################################################################
diff --git a/device/bluetooth/BUILD.gn b/device/bluetooth/BUILD.gn index 6a66287..e09b425d 100644 --- a/device/bluetooth/BUILD.gn +++ b/device/bluetooth/BUILD.gn
@@ -67,6 +67,7 @@ # Approved clients: "//chrome/browser/ash/nearby:*", "//chrome/browser/ui/webui/bluetooth_internals:*", + "//chrome/services/sharing/nearby/platform:*", # Implementation tests # Ideally only device_unittests, however android & fushia generate
diff --git a/device/vr/BUILD.gn b/device/vr/BUILD.gn index b175ad2..9db79e2 100644 --- a/device/vr/BUILD.gn +++ b/device/vr/BUILD.gn
@@ -153,6 +153,7 @@ if (enable_openxr) { sources += [ "openxr/context_provider_callbacks.h", + "openxr/exit_xr_present_reason.h", "openxr/openxr_anchor_manager.cc", "openxr/openxr_anchor_manager.h", "openxr/openxr_api_wrapper.cc", @@ -204,8 +205,6 @@ "openxr/openxr_view_configuration.cc", "openxr/openxr_view_configuration.h", "test/test_hook.h", - "windows/compositor_base.cc", - "windows/compositor_base.h", ] if (is_win) {
diff --git a/device/vr/openxr/exit_xr_present_reason.h b/device/vr/openxr/exit_xr_present_reason.h new file mode 100644 index 0000000..d710dd90 --- /dev/null +++ b/device/vr/openxr/exit_xr_present_reason.h
@@ -0,0 +1,21 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef DEVICE_VR_OPENXR_EXIT_XR_PRESENT_REASON_H_ +#define DEVICE_VR_OPENXR_EXIT_XR_PRESENT_REASON_H_ + +enum class ExitXrPresentReason : int32_t { + kUnknown = 0, + kMojoConnectionError = 1, + kOpenXrUninitialize = 2, + kStartRuntimeFailed = 3, + kOpenXrStartFailed = 4, + kXrEndFrameFailed = 5, + kGetFrameAfterSessionEnded = 6, + kSubmitFrameFailed = 7, + kBrowserShutdown = 8, + kXrPlatformHelperShutdown = 9, +}; + +#endif // DEVICE_VR_OPENXR_EXIT_XR_PRESENT_REASON_H_
diff --git a/device/vr/openxr/openxr_api_wrapper.h b/device/vr/openxr/openxr_api_wrapper.h index b911418c..b76c8411 100644 --- a/device/vr/openxr/openxr_api_wrapper.h +++ b/device/vr/openxr/openxr_api_wrapper.h
@@ -11,6 +11,7 @@ #include "base/functional/callback.h" #include "base/memory/raw_ptr.h" +#include "device/vr/openxr/exit_xr_present_reason.h" #include "device/vr/openxr/openxr_anchor_manager.h" #include "device/vr/openxr/openxr_graphics_binding.h" #include "device/vr/openxr/openxr_platform.h" @@ -20,7 +21,6 @@ #include "device/vr/public/mojom/vr_service.mojom.h" #include "device/vr/public/mojom/xr_session.mojom.h" #include "device/vr/vr_export.h" -#include "device/vr/windows/compositor_base.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/openxr/src/include/openxr/openxr.h"
diff --git a/device/vr/openxr/openxr_device.cc b/device/vr/openxr/openxr_device.cc index 721a3f9..897ff8cf2dd 100644 --- a/device/vr/openxr/openxr_device.cc +++ b/device/vr/openxr/openxr_device.cc
@@ -164,7 +164,7 @@ if (overlay_receiver_) { render_loop_->task_runner()->PostTask( - FROM_HERE, base::BindOnce(&XRCompositorCommon::RequestOverlay, + FROM_HERE, base::BindOnce(&OpenXrRenderLoop::RequestOverlay, base::Unretained(render_loop_.get()), std::move(overlay_receiver_))); } @@ -177,7 +177,7 @@ &OpenXrDevice::OnVisibilityStateChanged, weak_ptr_factory_.GetWeakPtr()); render_loop_->task_runner()->PostTask( - FROM_HERE, base::BindOnce(&XRCompositorCommon::RequestSession, + FROM_HERE, base::BindOnce(&OpenXrRenderLoop::RequestSession, base::Unretained(render_loop_.get()), std::move(on_visibility_state_changed), std::move(options), std::move(my_callback))); @@ -217,7 +217,7 @@ if (render_loop_) { render_loop_->task_runner()->PostTask( FROM_HERE, - base::BindOnce(&XRCompositorCommon::ExitPresent, + base::BindOnce(&OpenXrRenderLoop::ExitPresent, base::Unretained(render_loop_.get()), reason)); render_loop_.reset(); } @@ -251,7 +251,7 @@ // This should only be triggered if we have a session if (render_loop_) { render_loop_->task_runner()->PostTask( - FROM_HERE, base::BindOnce(&XRCompositorCommon::RequestOverlay, + FROM_HERE, base::BindOnce(&OpenXrRenderLoop::RequestOverlay, base::Unretained(render_loop_.get()), std::move(overlay_receiver))); } else {
diff --git a/device/vr/openxr/openxr_device.h b/device/vr/openxr/openxr_device.h index 3a1fb3e3..e210b2b 100644 --- a/device/vr/openxr/openxr_device.h +++ b/device/vr/openxr/openxr_device.h
@@ -9,11 +9,11 @@ #include "components/viz/common/gpu/context_provider.h" #include "device/vr/openxr/context_provider_callbacks.h" +#include "device/vr/openxr/exit_xr_present_reason.h" #include "device/vr/openxr/openxr_platform_helper.h" #include "device/vr/public/mojom/vr_service.mojom.h" #include "device/vr/vr_device_base.h" #include "device/vr/vr_export.h" -#include "device/vr/windows/compositor_base.h" #include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/cpp/bindings/pending_remote.h" #include "mojo/public/cpp/bindings/receiver.h"
diff --git a/device/vr/openxr/openxr_render_loop.cc b/device/vr/openxr/openxr_render_loop.cc index afc361a..8cb76cc 100644 --- a/device/vr/openxr/openxr_render_loop.cc +++ b/device/vr/openxr/openxr_render_loop.cc
@@ -5,10 +5,16 @@ #include "device/vr/openxr/openxr_render_loop.h" #include "base/containers/contains.h" +#include "base/functional/bind.h" #include "base/functional/callback_helpers.h" #include "base/ranges/algorithm.h" #include "base/task/bind_post_task.h" +#include "base/task/single_thread_task_runner.h" +#include "base/trace_event/trace_event.h" +#include "base/types/cxx23_to_underlying.h" +#include "build/build_config.h" #include "components/viz/common/gpu/context_provider.h" +#include "device/vr/openxr/exit_xr_present_reason.h" #include "device/vr/openxr/openxr_api_wrapper.h" #include "device/vr/openxr/openxr_input_helper.h" #include "device/vr/util/stage_utils.h" @@ -24,20 +30,52 @@ #if BUILDFLAG(IS_WIN) #include <d3d11_4.h> + +#include "device/vr/windows/d3d11_texture_helper.h" #endif +namespace { +// Number of frames to use for sliding averages for pose timings, +// as used for estimating prediction times. +constexpr unsigned kSlidingAverageSize = 5; + +device::mojom::XRRenderInfoPtr GetRenderInfo( + const device::mojom::XRFrameData& frame_data) { + device::mojom::XRRenderInfoPtr result = device::mojom::XRRenderInfo::New(); + + result->frame_id = frame_data.frame_id; + result->mojo_from_viewer = frame_data.mojo_from_viewer.Clone(); + + for (size_t i = 0; i < frame_data.views.size(); i++) { + result->views.push_back(frame_data.views[i]->Clone()); + } + + return result; +} + +} // namespace + namespace device { +OpenXrRenderLoop::OutstandingFrame::OutstandingFrame() = default; +OpenXrRenderLoop::OutstandingFrame::~OutstandingFrame() = default; + OpenXrRenderLoop::OpenXrRenderLoop( VizContextProviderFactoryAsync context_provider_factory_async, XrInstance instance, const OpenXrExtensionHelper& extension_helper, OpenXrPlatformHelper* platform_helper) - : instance_(instance), + : XRThread("OpenXrRenderLoop"), + main_thread_task_runner_( + base::SingleThreadTaskRunner::GetCurrentDefault()), + instance_(instance), extension_helper_(extension_helper), context_provider_factory_async_( std::move(context_provider_factory_async)), + webxr_js_time_(kSlidingAverageSize), + webxr_gpu_time_(kSlidingAverageSize), platform_helper_(platform_helper) { + DCHECK(main_thread_task_runner_); DCHECK(instance_ != XR_NULL_HANDLE); } @@ -45,11 +83,572 @@ Stop(); } +void OpenXrRenderLoop::ExitPresent(ExitXrPresentReason reason) { + DVLOG(1) << __func__ << " reason=" << base::to_underlying(reason); + TRACE_EVENT_INSTANT1("xr", "ExitPresent", TRACE_EVENT_SCOPE_THREAD, "reason", + base::to_underlying(reason)); + if (!is_presenting_) { + return; + } + + is_presenting_ = false; + webxr_has_pose_ = false; + presentation_receiver_.reset(); + frame_data_receiver_.reset(); + submit_client_.reset(); + + pending_frame_.reset(); + delayed_get_frame_data_callback_.Reset(); + + // Reset webxr_visible_ for subsequent presentations. + webxr_visible_ = true; + + // Kill outstanding overlays: + overlay_visible_ = false; + overlay_receiver_.reset(); + +#if BUILDFLAG(IS_WIN) + texture_helper_.SetSourceAndOverlayVisible(false, false); +#endif + + // Don't call StopRuntime until this thread has finished the rest of the work. + // This is to prevent the OpenXrApiWrapper from being deleted before its + // cleanup work has finished. + task_runner()->PostTask( + FROM_HERE, + base::BindOnce(&OpenXrRenderLoop::StopRuntime, base::Unretained(this))); +} + +void OpenXrRenderLoop::GetFrameData( + mojom::XRFrameDataRequestOptionsPtr options, + mojom::XRFrameDataProvider::GetFrameDataCallback callback) { + TRACE_EVENT0("xr", "GetFrameData"); + if (HasSessionEnded()) { + ExitPresent(ExitXrPresentReason::kGetFrameAfterSessionEnded); + return; + } + + // HasSessionEnded() may do some work that alters the state of + // `is_presenting_`, in which case we'll get the ExitPresent log to know that + // we've ignored this request; but otherwise, we should log the rest of the + // state after that. + DVLOG(3) << __func__ << " is_presenting_=" << is_presenting_ + << " webxr_visible=" << webxr_visible_ + << " on_webxr_submitted_=" << !!on_webxr_submitted_ + << " webxr_has_pose_=" << webxr_has_pose_; + + if (!is_presenting_) { + return; + } + + // If we've already given out a pose for the current frame, or aren't visible, + // delay giving out a pose until the next frame we are visible. + // However, if we aren't visible and the browser is waiting to learn that + // WebXR has submitted a frame, we can give out a pose as though we are + // visible. + if ((!webxr_visible_ && !on_webxr_submitted_) || webxr_has_pose_) { + // There should only be one outstanding GetFrameData call at a time. We + // shouldn't get new ones until this resolves or presentation ends/restarts. + if (delayed_get_frame_data_callback_) { + frame_data_receiver_.ReportBadMessage( + "Multiple outstanding GetFrameData calls"); + return; + } + delayed_get_frame_data_callback_ = + base::BindOnce(&OpenXrRenderLoop::GetFrameData, base::Unretained(this), + std::move(options), std::move(callback)); + return; + } + + StartPendingFrame(); + webxr_has_pose_ = true; + pending_frame_->webxr_has_pose_ = true; + pending_frame_->sent_frame_data_time_ = base::TimeTicks::Now(); + + // TODO(https://crbug.com/1218135): The lack of frame_data_ here indicates + // that we probably should have deferred this call, but it matches the + // behavior from before the stage parameters were updated in this function and + // avoids a crash. Likely the deferral above should check if we're awaiting + // either the webxr or overlay submit. + if (pending_frame_->frame_data_) { + // If the stage parameters have been updated since the last frame that was + // sent, send the updated values. + pending_frame_->frame_data_->stage_parameters_id = stage_parameters_id_; + if (options->stage_parameters_id != stage_parameters_id_) { + pending_frame_->frame_data_->stage_parameters = + current_stage_parameters_.Clone(); + } + } else { + TRACE_EVENT0("xr", "GetFrameData Missing FrameData"); + } + + // Yield here to let the event queue process pending mojo messages, + // specifically the next gamepad callback request that's likely to + // have been sent during WaitGetPoses. + task_runner()->PostTask( + FROM_HERE, base::BindOnce(&OpenXrRenderLoop::SendFrameData, + base::Unretained(this), std::move(callback), + std::move(pending_frame_->frame_data_))); + + next_frame_id_ += 1; + if (next_frame_id_ < 0) { + next_frame_id_ = 0; + } +} + +void OpenXrRenderLoop::RequestOverlay( + mojo::PendingReceiver<mojom::ImmersiveOverlay> receiver) { + overlay_receiver_.reset(); + overlay_receiver_.Bind(std::move(receiver)); + + // WebXR is visible and overlay hidden by default until the overlay overrides + // this. + SetOverlayAndWebXRVisibility(false, true); +} + +void OpenXrRenderLoop::RequestSession( + base::RepeatingCallback<void(mojom::XRVisibilityState)> + on_visibility_state_changed, + mojom::XRRuntimeSessionOptionsPtr options, + RequestSessionCallback callback) { + webxr_has_pose_ = false; + presentation_receiver_.reset(); + frame_data_receiver_.reset(); + + EnableSupportedFeatures(options->required_features, + options->optional_features); + + // Call OpenXrRenderLoop::StartRuntime. Upon completion, this function will + // invoke the provided start_runtime_callback. + // OpenXrRenderLoop::StartRuntimeFinish. We setup BindOnce such that all of + // the parameters give to us here in OpenXrRenderLoop::RequestSession are + // passed through to StartRuntimeFinish so that it can finish the job. + StartRuntime(base::BindOnce(&OpenXrRenderLoop::StartRuntimeFinish, + base::Unretained(this), + std::move(on_visibility_state_changed), + std::move(options), std::move(callback))); +} + bool OpenXrRenderLoop::IsFeatureEnabled( device::mojom::XRSessionFeature feature) const { return base::Contains(enabled_features_, feature); } +void OpenXrRenderLoop::SetVisibilityState( + mojom::XRVisibilityState visibility_state) { + if (visibility_state_ != visibility_state) { + visibility_state_ = visibility_state; + if (on_visibility_state_changed_) { + main_thread_task_runner_->PostTask( + FROM_HERE, + base::BindOnce(on_visibility_state_changed_, visibility_state)); + } + } +} + +void OpenXrRenderLoop::SetStageParameters( + mojom::VRStageParametersPtr stage_parameters) { + // If the stage parameters are identical no need to update them. + if ((!current_stage_parameters_ && !stage_parameters) || + (current_stage_parameters_ && stage_parameters && + current_stage_parameters_.Equals(stage_parameters))) { + return; + } + + // If they have changed, increment the ID and save the new parameters. + stage_parameters_id_++; + current_stage_parameters_ = std::move(stage_parameters); +} + +#if BUILDFLAG(IS_WIN) +void OpenXrRenderLoop::SubmitFrameWithTextureHandle( + int16_t frame_index, + mojo::PlatformHandle texture_handle, + const gpu::SyncToken& sync_token) { + DVLOG(3) << __func__ << " frame_index=" << frame_index; + TRACE_EVENT1("xr", "SubmitFrameWithTextureHandle", "frameIndex", frame_index); + if (!MarkFrameSubmitted(frame_index)) { + return; + } + + base::win::ScopedHandle scoped_handle = texture_handle.is_valid() + ? texture_handle.TakeHandle() + : base::win::ScopedHandle(); + texture_helper_.SetSourceTexture(std::move(scoped_handle), sync_token, + left_webxr_bounds_, right_webxr_bounds_); + + // Regardless of success - try to composite what we have. + MaybeCompositeAndSubmit(); +} +#endif + +void OpenXrRenderLoop::CleanUp() { + DVLOG(1) << __func__; + submit_client_.reset(); + webxr_has_pose_ = false; + presentation_receiver_.reset(); + frame_data_receiver_.reset(); + overlay_receiver_.reset(); + StopRuntime(); +} + +void OpenXrRenderLoop::ClearPendingFrame() { + // Complete the frame if OpenXR has started one with BeginFrame. This also + // releases the swapchain image that was acquired in BeginFrame so that the + // next frame can acquire it. + if (openxr_->HasPendingFrame() && XR_FAILED(openxr_->EndFrame())) { + // The start of the next frame will detect that the session has ended via + // HasSessionEnded and will exit presentation. + ExitPresent(ExitXrPresentReason::kXrEndFrameFailed); + return; + } + + pending_frame_.reset(); + // Send frame data to outstanding requests. + if (delayed_get_frame_data_callback_ && + (webxr_visible_ || on_webxr_submitted_)) { + // If WebXR is not visible, but the browser wants to know when it submits a + // frame, we allow the renderer to receive poses. + std::move(delayed_get_frame_data_callback_).Run(); + } +} + +void OpenXrRenderLoop::StartPendingFrame() { + DVLOG(3) << __func__ << " pending_frame_=" << pending_frame_.has_value(); + if (!pending_frame_) { + pending_frame_.emplace(); + pending_frame_->waiting_for_webxr_ = webxr_visible_; + pending_frame_->waiting_for_overlay_ = overlay_visible_; + pending_frame_->frame_data_ = GetNextFrameData(); + // GetNextFrameData() should never return null: + DCHECK(pending_frame_->frame_data_); + pending_frame_->render_info_ = GetRenderInfo(*pending_frame_->frame_data_); + } +} + +void OpenXrRenderLoop::StartRuntimeFinish( + base::RepeatingCallback<void(mojom::XRVisibilityState)> + on_visibility_state_changed, + mojom::XRRuntimeSessionOptionsPtr options, + RequestSessionCallback callback, + bool success) { + if (!success) { + TRACE_EVENT_INSTANT0("xr", "Failed to start runtime", + TRACE_EVENT_SCOPE_THREAD); + main_thread_task_runner_->PostTask( + FROM_HERE, base::BindOnce(std::move(callback), false, nullptr)); + return; + } + + on_visibility_state_changed_ = std::move(on_visibility_state_changed); + + // Queue up a notification to the requester of the current visibility state, + // so that it can be initialized to the right value. + if (on_visibility_state_changed_) { + main_thread_task_runner_->PostTask( + FROM_HERE, + base::BindOnce(on_visibility_state_changed_, visibility_state_)); + } + + device::mojom::XRPresentationTransportOptionsPtr transport_options = + device::mojom::XRPresentationTransportOptions::New(); + + if (graphics_binding_->IsUsingSharedImages()) { + transport_options->transport_method = + device::mojom::XRPresentationTransportMethod::DRAW_INTO_TEXTURE_MAILBOX; + } else if constexpr (BUILDFLAG(IS_WIN)) { + transport_options->transport_method = + device::mojom::XRPresentationTransportMethod::SUBMIT_AS_TEXTURE_HANDLE; + } else { + transport_options->transport_method = + device::mojom::XRPresentationTransportMethod::SUBMIT_AS_MAILBOX_HOLDER; + } + + // Only set boolean options that we need. Default is false, and we should be + // able to safely ignore ones that our implementation doesn't care about. + transport_options->wait_for_transfer_notification = true; + + LogViewerType(VrViewerType::OPENXR_UNKNOWN); + + auto submit_frame_sink = device::mojom::XRPresentationConnection::New(); + submit_frame_sink->provider = + presentation_receiver_.BindNewPipeAndPassRemote(); + submit_frame_sink->client_receiver = + submit_client_.BindNewPipeAndPassReceiver(); + submit_frame_sink->transport_options = std::move(transport_options); + + auto session = device::mojom::XRSession::New(); + session->data_provider = frame_data_receiver_.BindNewPipeAndPassRemote(); + session->submit_frame_sink = std::move(submit_frame_sink); + + session->enabled_features.insert(session->enabled_features.end(), + enabled_features_.begin(), + enabled_features_.end()); + + session->device_config = device::mojom::XRSessionDeviceConfig::New(); + session->device_config->enable_anti_aliasing = + openxr_->CanEnableAntiAliasing(); + session->device_config->views = openxr_->GetDefaultViews(); + session->enviroment_blend_mode = + openxr_->PickEnvironmentBlendModeForSession(options->mode); + session->interaction_mode = device::mojom::XRInteractionMode::kWorldSpace; + + main_thread_task_runner_->PostTask( + FROM_HERE, base::BindOnce(std::move(callback), true, std::move(session))); + is_presenting_ = true; + +#if BUILDFLAG(IS_WIN) + texture_helper_.SetSourceAndOverlayVisible(webxr_visible_, overlay_visible_); +#endif +} + +void OpenXrRenderLoop::MaybeCompositeAndSubmit() { + DVLOG(3) << __func__; + if (!pending_frame_) { + // There is no outstanding frame, nor frame to composite, but there may be + // pending GetFrameData calls, so ClearPendingFrame() to respond to them. + ClearPendingFrame(); + return; + } + + // Check if we have obtained all layers (overlay and webxr) that we need. + if (pending_frame_->waiting_for_webxr_ || + pending_frame_->waiting_for_overlay_) { + DVLOG(3) << __func__ << "Waiting for additional layers, waiting_for_webxr_=" + << pending_frame_->waiting_for_webxr_ + << " waiting_for_overlay=" << pending_frame_->waiting_for_overlay_; + // Haven't received submits from all layers. + return; + } + + // TODO(https://crbug.com/1454950): Unify OpenXr Rendering paths. +#if BUILDFLAG(IS_WIN) + bool copy_successful = false; + bool has_webxr_content = pending_frame_->webxr_submitted_ && webxr_visible_; + bool has_overlay_content = + pending_frame_->overlay_submitted_ && overlay_visible_; + bool can_submit = has_webxr_content || has_overlay_content; + + // Tell texture helper to composite, then grab the output texture, and submit. + // If we submitted, set up the next frame, and send outstanding pose requests. + if (can_submit) { + copy_successful = texture_helper_.UpdateBackbufferSizes() && + texture_helper_.CompositeToBackBuffer(); + } else { + texture_helper_.CleanupNoSubmit(); + } +#elif BUILDFLAG(IS_ANDROID) + bool copy_successful = true; +#endif + + // A copy can only be successful if we actually tried to submit. + if (copy_successful) { + pending_frame_->frame_ready_time_ = base::TimeTicks::Now(); + if (!SubmitCompositedFrame()) { + ExitPresent(ExitXrPresentReason::kSubmitFrameFailed); + // ExitPresent() clears pending_frame_, so return here to avoid + // accessing it below. + return; + } + } + + if (pending_frame_->webxr_submitted_ && copy_successful) { + // We've submitted a frame. + webxr_js_time_.AddSample(pending_frame_->submit_frame_time_ - + pending_frame_->sent_frame_data_time_); + webxr_gpu_time_.AddSample(pending_frame_->frame_ready_time_ - + pending_frame_->submit_frame_time_); + + TRACE_EVENT_INSTANT2( + "gpu", "WebXR frame time (ms)", TRACE_EVENT_SCOPE_THREAD, "javascript", + webxr_js_time_.GetAverage().InMillisecondsF(), "rendering", + webxr_gpu_time_.GetAverage().InMillisecondsF()); + fps_meter_.AddFrame(base::TimeTicks::Now()); + TRACE_COUNTER1("gpu", "WebXR FPS", fps_meter_.GetFPS()); + } + + if (pending_frame_->webxr_submitted_ && submit_client_) { + // Tell WebVR that we are done with the texture (if we got a texture) + submit_client_->OnSubmitFrameTransferred(copy_successful); + submit_client_->OnSubmitFrameRendered(); + TRACE_EVENT1("xr", "SubmitFrameTransferred", "success", copy_successful); + } + + if (pending_frame_->overlay_submitted_ && overlay_submit_callback_) { + // Tell the browser/overlay that we are done with its texture so it can be + // reused. + std::move(overlay_submit_callback_).Run(copy_successful); + } + + ClearPendingFrame(); +} + +bool OpenXrRenderLoop::MarkFrameSubmitted(int16_t frame_index) { + DVLOG(3) << __func__; + webxr_has_pose_ = false; + // Tell the browser that WebXR has submitted a frame. + if (on_webxr_submitted_) { + std::move(on_webxr_submitted_).Run(); + } + + if (!pending_frame_ || + pending_frame_->render_info_->frame_id != frame_index) { + // We weren't expecting a submitted frame. This can happen if WebXR was + // hidden by an overlay for some time. + if (submit_client_) { + submit_client_->OnSubmitFrameTransferred(false); + submit_client_->OnSubmitFrameRendered(); + TRACE_EVENT1("xr", "SubmitFrameTransferred", "success", false); + } + return false; + } + + pending_frame_->waiting_for_webxr_ = false; + pending_frame_->webxr_submitted_ = true; + pending_frame_->submit_frame_time_ = base::TimeTicks::Now(); + + return true; +} + +void OpenXrRenderLoop::SubmitFrameMissing(int16_t frame_index, + const gpu::SyncToken& sync_token) { + DVLOG(3) << __func__ << " frame_index=" << frame_index; + TRACE_EVENT_INSTANT0("xr", "SubmitFrameMissing", TRACE_EVENT_SCOPE_THREAD); + if (pending_frame_) { + // WebXR for this frame is hidden. + pending_frame_->waiting_for_webxr_ = false; + } + webxr_has_pose_ = false; +#if (BUILDFLAG(IS_ANDROID)) + // We haven't finished the rendering path on Android yet so are just calling + // this to ensure that the page stays un-stuck while we aren't actually + // rendering anything. + // TODO(alcooper): Clean this up. + pending_frame_->webxr_submitted_ = true; +#endif + MaybeCompositeAndSubmit(); +} + +void OpenXrRenderLoop::UpdateLayerBounds(int16_t frame_id, + const gfx::RectF& left_bounds, + const gfx::RectF& right_bounds, + const gfx::Size& source_size) { + // Bounds are updated instantly, rather than waiting for frame_id. This works + // since blink always passes the current frame_id when updating the bounds. + // Ignoring the frame_id keeps the logic simpler, so this can more easily + // merge with vr_shell_gl eventually. + left_webxr_bounds_ = left_bounds; + right_webxr_bounds_ = right_bounds; + + // Swap top/bottom to account for differences between D3D and GL coordinates. + left_webxr_bounds_.set_y( + 1 - (left_webxr_bounds_.y() + left_webxr_bounds_.height())); + right_webxr_bounds_.set_y( + 1 - (right_webxr_bounds_.y() + right_webxr_bounds_.height())); + + source_size_ = source_size; + + graphics_binding_->SetTransferSize(source_size); +} + +void OpenXrRenderLoop::SubmitOverlayTexture( + int16_t frame_id, + mojo::PlatformHandle texture_handle, + const gpu::SyncToken& sync_token, + const gfx::RectF& left_bounds, + const gfx::RectF& right_bounds, + SubmitOverlayTextureCallback overlay_submit_callback) { + TRACE_EVENT_INSTANT0("xr", "SubmitOverlay", TRACE_EVENT_SCOPE_THREAD); + DCHECK(overlay_visible_); + overlay_submit_callback_ = std::move(overlay_submit_callback); + if (!pending_frame_) { + // We may stop presenting while there is a pending SubmitOverlayTexture + // outstanding. If we get an overlay submit we weren't expecting, just + // ignore it. + DCHECK(!is_presenting_); + std::move(overlay_submit_callback_).Run(false); + return; + } + + pending_frame_->waiting_for_overlay_ = false; + +#if BUILDFLAG(IS_WIN) + texture_helper_.SetOverlayTexture(texture_handle.TakeHandle(), sync_token, + left_bounds, right_bounds); + pending_frame_->overlay_submitted_ = true; + + // Regardless of success - try to composite what we have. + MaybeCompositeAndSubmit(); +#endif +} + +void OpenXrRenderLoop::RequestNextOverlayPose( + RequestNextOverlayPoseCallback callback) { + DVLOG(3) << __func__; + // We will only request poses while the overlay is visible. + DCHECK(overlay_visible_); + TRACE_EVENT_INSTANT0("xr", "RequestOverlayPose", TRACE_EVENT_SCOPE_THREAD); + + // Ensure we have a pending frame. + StartPendingFrame(); + pending_frame_->overlay_has_pose_ = true; + std::move(callback).Run(pending_frame_->render_info_->Clone()); +} + +void OpenXrRenderLoop::SetOverlayAndWebXRVisibility(bool overlay_visible, + bool webxr_visible) { + DVLOG(1) << __func__ << " overlay_visible=" << overlay_visible + << " webxr_visible=" << webxr_visible; + TRACE_EVENT_INSTANT2("xr", "SetOverlayAndWebXRVisibility", + TRACE_EVENT_SCOPE_THREAD, "overlay", overlay_visible, + "webxr", webxr_visible); + // Update state. + webxr_visible_ = webxr_visible; + overlay_visible_ = overlay_visible; + if (pending_frame_) { + pending_frame_->waiting_for_webxr_ = + pending_frame_->waiting_for_webxr_ && webxr_visible; + pending_frame_->waiting_for_overlay_ = + pending_frame_->waiting_for_overlay_ && overlay_visible; + } + + // Update texture helper. +#if BUILDFLAG(IS_WIN) + texture_helper_.SetSourceAndOverlayVisible(webxr_visible, overlay_visible); +#endif + + // Maybe composite and submit if we have a pending that is now valid to + // submit. + MaybeCompositeAndSubmit(); +} + +void OpenXrRenderLoop::RequestNotificationOnWebXrSubmitted( + RequestNotificationOnWebXrSubmittedCallback callback) { + on_webxr_submitted_ = std::move(callback); +} + +void OpenXrRenderLoop::SendFrameData( + XRFrameDataProvider::GetFrameDataCallback callback, + mojom::XRFrameDataPtr frame_data) { + DVLOG(3) << __func__; + TRACE_EVENT0("xr", "SendFrameData"); + + // This method represents a call from the renderer process. If our visibility + // state is hidden, we should avoid handing "sensitive" information, like the + // pose back up to the renderer. Note that this check is done here as other + // methods (RequestNextOverlayPose) represent a call from the browser process, + // which should receive the pose. + bool is_visible = + (visibility_state_ != device::mojom::XRVisibilityState::HIDDEN); + + // We have posted a message to allow other calls to get through, and now state + // may have changed. WebXR may not be presenting any more, or may be hidden. + std::move(callback).Run(is_presenting_ && is_visible && + (webxr_visible_ || on_webxr_submitted_) + ? std::move(frame_data) + : mojom::XRFrameData::New()); +} + mojom::XRFrameDataPtr OpenXrRenderLoop::GetNextFrameData() { DVLOG(3) << __func__; mojom::XRFrameDataPtr frame_data = mojom::XRFrameData::New(); @@ -84,7 +683,7 @@ if (anchor_manager) { frame_data->anchors_data = anchor_manager->ProcessAnchorsForFrame( - openxr_.get(), GetCurrentStageParameters(), + openxr_.get(), current_stage_parameters_, frame_data->input_state.value(), openxr_->GetPredictedDisplayTime()); } @@ -110,7 +709,7 @@ return frame_data; } -// StartRuntime is called by XRCompositorCommon::RequestSession. When the +// StartRuntime is called by OpenXrRenderLoop::RequestSession. When the // runtime is fully started, start_runtime_callback.Run must be called with a // success boolean, or false on failure. OpenXrRenderLoop::StartRuntime waits // until the Viz context provider is fully started before running @@ -239,32 +838,6 @@ }); } -device::mojom::XREnvironmentBlendMode OpenXrRenderLoop::GetEnvironmentBlendMode( - device::mojom::XRSessionMode session_mode) { - return openxr_->PickEnvironmentBlendModeForSession(session_mode); -} - -device::mojom::XRInteractionMode OpenXrRenderLoop::GetInteractionMode( - device::mojom::XRSessionMode session_mode) { - return device::mojom::XRInteractionMode::kWorldSpace; -} - -bool OpenXrRenderLoop::CanEnableAntiAliasing() const { - return openxr_->CanEnableAntiAliasing(); -} - -std::vector<mojom::XRViewPtr> OpenXrRenderLoop::GetDefaultViews() const { - return openxr_->GetDefaultViews(); -} - -void OpenXrRenderLoop::OnLayerBoundsChanged(const gfx::Size& source_size) { - graphics_binding_->SetTransferSize(source_size); -} - -void OpenXrRenderLoop::OnSessionStart() { - LogViewerType(VrViewerType::OPENXR_UNKNOWN); -} - bool OpenXrRenderLoop::HasSessionEnded() { return openxr_ && openxr_->UpdateAndGetSessionEnded(); } @@ -273,27 +846,11 @@ return XR_SUCCEEDED(openxr_->EndFrame()); } -void OpenXrRenderLoop::ClearPendingFrameInternal() { - // Complete the frame if OpenXR has started one with BeginFrame. This also - // releases the swapchain image that was acquired in BeginFrame so that the - // next frame can acquire it. - if (openxr_->HasPendingFrame() && XR_FAILED(openxr_->EndFrame())) { - // The start of the next frame will detect that the session has ended via - // HasSessionEnded and will exit presentation. - ExitPresent(ExitXrPresentReason::kXrEndFrameFailed); - return; - } -} - -bool OpenXrRenderLoop::IsUsingSharedImages() const { - return graphics_binding_->IsUsingSharedImages(); -} - void OpenXrRenderLoop::SubmitFrame(int16_t frame_index, const gpu::MailboxHolder& mailbox, base::TimeDelta time_waited) { DVLOG(3) << __func__ << " frame_index=" << frame_index; - CHECK(!IsUsingSharedImages()); + CHECK(!graphics_binding_->IsUsingSharedImages()); DCHECK(BUILDFLAG(IS_ANDROID)); // TODO(https://crbug.com/1454942): Support non-shared buffer mode. SubmitFrameMissing(frame_index, mailbox.sync_token); @@ -338,8 +895,7 @@ #endif // Calling SubmitFrameWithTextureHandle can cause openxr_ and - // context_provider_ to become nullptr in ClearPendingFrameInternal if we - // decide to stop the runtime. + // context_provider_ to become nullptr if we decide to stop the runtime. if (context_provider_) { gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL(); gl->DestroyGpuFenceCHROMIUM(id);
diff --git a/device/vr/openxr/openxr_render_loop.h b/device/vr/openxr/openxr_render_loop.h index 697fdda9..b77b0158 100644 --- a/device/vr/openxr/openxr_render_loop.h +++ b/device/vr/openxr/openxr_render_loop.h
@@ -10,12 +10,22 @@ #include "base/functional/callback.h" #include "base/memory/raw_ref.h" +#include "base/memory/scoped_refptr.h" +#include "base/task/single_thread_task_runner.h" +#include "base/time/time.h" +#include "build/build_config.h" #include "components/viz/common/gpu/context_lost_observer.h" #include "device/vr/openxr/context_provider_callbacks.h" +#include "device/vr/openxr/exit_xr_present_reason.h" #include "device/vr/openxr/openxr_anchor_manager.h" #include "device/vr/openxr/openxr_graphics_binding.h" #include "device/vr/openxr/openxr_platform_helper.h" -#include "device/vr/windows/compositor_base.h" +#include "device/vr/public/mojom/isolated_xr_service.mojom.h" +#include "device/vr/public/mojom/vr_service.mojom.h" +#include "device/vr/public/mojom/xr_session.mojom.h" +#include "device/vr/util/fps_meter.h" +#include "device/vr/util/sliding_average.h" +#include "device/vr/vr_device.h" #include "gpu/command_buffer/client/gles2_interface.h" #include "mojo/public/cpp/bindings/associated_receiver.h" #include "mojo/public/cpp/bindings/associated_remote.h" @@ -26,6 +36,20 @@ #include "mojo/public/cpp/bindings/remote.h" #include "mojo/public/cpp/platform/platform_handle.h" #include "third_party/openxr/src/include/openxr/openxr.h" +#include "ui/gfx/geometry/rect_f.h" + +#if BUILDFLAG(IS_WIN) +#include "base/threading/thread.h" +#include "device/vr/windows/d3d11_texture_helper.h" +#endif + +#if BUILDFLAG(IS_ANDROID) +#include "base/android/java_handler_thread.h" +#endif + +namespace gpu::gles2 { +class GLES2Interface; +} // namespace gpu::gles2 namespace gfx { class GpuFence; @@ -35,10 +59,33 @@ class OpenXrApiWrapper; -class OpenXrRenderLoop : public XRCompositorCommon, +#if BUILDFLAG(IS_ANDROID) +class XRThread : public base::android::JavaHandlerThread { + public: + explicit XRThread(const char* name) + : base::android::JavaHandlerThread(name) {} + ~XRThread() override = default; +}; +#elif BUILDFLAG(IS_WIN) +class XRThread : public base::Thread { + public: + explicit XRThread(const char* name) : base::Thread(name) {} + ~XRThread() override = default; +}; +#else +#error "Trying to build OpenXR for an unsupported platform" +#endif + +class OpenXrRenderLoop : public XRThread, + public mojom::XRPresentationProvider, + public mojom::XRFrameDataProvider, + public mojom::ImmersiveOverlay, public mojom::XREnvironmentIntegrationProvider, public viz::ContextLostObserver { public: + using RequestSessionCallback = + base::OnceCallback<void(bool result, mojom::XRSessionPtr)>; + OpenXrRenderLoop( VizContextProviderFactoryAsync context_provider_factory_async, XrInstance instance, @@ -50,36 +97,117 @@ ~OpenXrRenderLoop() override; + void ExitPresent(ExitXrPresentReason reason); + + gpu::gles2::GLES2Interface* GetContextGL(); + + void GetFrameData( + mojom::XRFrameDataRequestOptionsPtr options, + XRFrameDataProvider::GetFrameDataCallback callback) override; + + void RequestOverlay(mojo::PendingReceiver<mojom::ImmersiveOverlay> receiver); + + void RequestSession(base::RepeatingCallback<void(mojom::XRVisibilityState)> + on_visibility_state_changed, + mojom::XRRuntimeSessionOptionsPtr options, + RequestSessionCallback callback); + private: - // XRCompositorCommon: - gpu::gles2::GLES2Interface* GetContextGL() override; - void ClearPendingFrameInternal() override; - bool IsUsingSharedImages() const override; + void SetVisibilityState(mojom::XRVisibilityState visibility_state); + void SetStageParameters(mojom::VRStageParametersPtr stage_parameters); + + // base::Thread overrides: + void CleanUp() override; + + void ClearPendingFrame(); + void StartPendingFrame(); + + void StartRuntimeFinish( + base::RepeatingCallback<void(mojom::XRVisibilityState)> + on_visibility_state_changed, + mojom::XRRuntimeSessionOptionsPtr options, + RequestSessionCallback callback, + bool success); + + // Will Submit if we have textures submitted from the Overlay (if it is + // visible), and WebXR (if it is visible). We decide what to wait for during + // StartPendingFrame, may mark things as ready after SubmitFrameMissing and + // SubmitFrameWithTextureHandle (for WebXR), or SubmitOverlayTexture (for + // overlays), or SetOverlayAndWebXRVisibility (for WebXR and overlays). + // Finally, if we exit presentation while waiting for outstanding submits, we + // will clean up our pending-frame state. + void MaybeCompositeAndSubmit(); + + // Sets all relevant internal state to mark that we have successfully received + // a frame. Will return whether or not the given frame index was expected. + // If not expected, not all state may be successfully cleared. + bool MarkFrameSubmitted(int16_t frame_index); + + // XRPresentationProvider overrides: +#if BUILDFLAG(IS_WIN) + void SubmitFrameWithTextureHandle(int16_t frame_index, + mojo::PlatformHandle texture_handle, + const gpu::SyncToken& sync_token) override; +#endif + void SubmitFrameMissing(int16_t frame_index, const gpu::SyncToken&) override; void SubmitFrame(int16_t frame_index, const gpu::MailboxHolder& mailbox, - base::TimeDelta time_waited) override; + base::TimeDelta time_waited) final; void SubmitFrameDrawnIntoTexture(int16_t frame_index, const gpu::SyncToken&, base::TimeDelta time_waited) override; + void UpdateLayerBounds(int16_t frame_id, + const gfx::RectF& left_bounds, + const gfx::RectF& right_bounds, + const gfx::Size& source_size) override; - // XRDeviceAbstraction: - mojom::XRFrameDataPtr GetNextFrameData() override; - void StartRuntime(StartRuntimeCallback start_runtime_callback) override; - void StopRuntime() override; - void OnSessionStart() override; - bool HasSessionEnded() override; - bool SubmitCompositedFrame() override; + // ImmersiveOverlay: + void SubmitOverlayTexture(int16_t frame_id, + mojo::PlatformHandle texture, + const gpu::SyncToken& sync_token, + const gfx::RectF& left_bounds, + const gfx::RectF& right_bounds, + SubmitOverlayTextureCallback callback) override; + void RequestNextOverlayPose(RequestNextOverlayPoseCallback callback) override; + void SetOverlayAndWebXRVisibility(bool overlay_visible, + bool webxr_visible) override; + void RequestNotificationOnWebXrSubmitted( + RequestNotificationOnWebXrSubmittedCallback callback) override; + + void SendFrameData(XRFrameDataProvider::GetFrameDataCallback callback, + mojom::XRFrameDataPtr frame_data); + + struct OutstandingFrame { + OutstandingFrame(); + ~OutstandingFrame(); + bool webxr_has_pose_ = false; + bool overlay_has_pose_ = false; + bool webxr_submitted_ = false; + bool overlay_submitted_ = false; + bool waiting_for_webxr_ = false; + bool waiting_for_overlay_ = false; + + mojom::XRFrameDataPtr frame_data_; + mojom::XRRenderInfoPtr render_info_; + + base::TimeTicks sent_frame_data_time_; + base::TimeTicks submit_frame_time_; + base::TimeTicks frame_ready_time_; + }; + + mojom::XRFrameDataPtr GetNextFrameData(); + + // TODO(https://crbug.com/1516973): Investigate removing this callback. + using StartRuntimeCallback = base::OnceCallback<void(bool success)>; + + void StartRuntime(StartRuntimeCallback start_runtime_callback); + void StopRuntime(); + void OnSessionStart(); + bool HasSessionEnded(); + bool SubmitCompositedFrame(); void EnableSupportedFeatures( const std::vector<device::mojom::XRSessionFeature>& requiredFeatures, - const std::vector<device::mojom::XRSessionFeature>& optionalFeatures) - override; - device::mojom::XREnvironmentBlendMode GetEnvironmentBlendMode( - device::mojom::XRSessionMode session_mode) override; - device::mojom::XRInteractionMode GetInteractionMode( - device::mojom::XRSessionMode session_mode) override; - bool CanEnableAntiAliasing() const override; - std::vector<mojom::XRViewPtr> GetDefaultViews() const override; - void OnLayerBoundsChanged(const gfx::Size& source_size) override; + const std::vector<device::mojom::XRSessionFeature>& optionalFeatures); // viz::ContextLostObserver Implementation void OnContextLost() override; @@ -139,6 +267,12 @@ std::unique_ptr<gfx::GpuFence> gpu_fence); bool IsFeatureEnabled(device::mojom::XRSessionFeature feature) const; +#if BUILDFLAG(IS_WIN) + D3D11TextureHelper texture_helper_{this}; +#endif + int16_t next_frame_id_ = 0; + scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_; + std::unordered_set<device::mojom::XRSessionFeature> enabled_features_; // Owned by OpenXrStatics XrInstance instance_; @@ -147,6 +281,35 @@ scoped_refptr<viz::ContextProvider> context_provider_; VizContextProviderFactoryAsync context_provider_factory_async_; + FPSMeter fps_meter_; + SlidingTimeDeltaAverage webxr_js_time_; + SlidingTimeDeltaAverage webxr_gpu_time_; + + absl::optional<OutstandingFrame> pending_frame_; + + bool is_presenting_ = false; // True if we have a presenting session. + bool webxr_visible_ = true; // The browser may hide a presenting session. + bool overlay_visible_ = false; + base::OnceCallback<void()> delayed_get_frame_data_callback_; + + gfx::RectF left_webxr_bounds_; + gfx::RectF right_webxr_bounds_; + gfx::Size source_size_; + + mojo::Remote<mojom::XRPresentationClient> submit_client_; + SubmitOverlayTextureCallback overlay_submit_callback_; + RequestNotificationOnWebXrSubmittedCallback on_webxr_submitted_; + bool webxr_has_pose_ = false; + base::RepeatingCallback<void(mojom::XRVisibilityState)> + on_visibility_state_changed_; + mojo::Receiver<mojom::XRPresentationProvider> presentation_receiver_{this}; + mojo::Receiver<mojom::XRFrameDataProvider> frame_data_receiver_{this}; + mojo::Receiver<mojom::ImmersiveOverlay> overlay_receiver_{this}; + mojom::XRVisibilityState visibility_state_ = + mojom::XRVisibilityState::VISIBLE; + mojom::VRStageParametersPtr current_stage_parameters_; + uint32_t stage_parameters_id_; + // Lifetime of the platform helper is guaranteed by the OpenXrDevice. raw_ptr<OpenXrPlatformHelper> platform_helper_; std::unique_ptr<OpenXrGraphicsBinding> graphics_binding_;
diff --git a/device/vr/windows/compositor_base.cc b/device/vr/windows/compositor_base.cc deleted file mode 100644 index 837cae9..0000000 --- a/device/vr/windows/compositor_base.cc +++ /dev/null
@@ -1,672 +0,0 @@ -// Copyright 2018 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "device/vr/windows/compositor_base.h" - -#include "base/functional/bind.h" -#include "base/task/single_thread_task_runner.h" -#include "base/trace_event/trace_event.h" -#include "base/types/cxx23_to_underlying.h" -#include "build/build_config.h" -#include "components/viz/common/gpu/context_provider.h" -#include "ui/gfx/geometry/angle_conversions.h" -#include "ui/gfx/geometry/transform.h" - -#if BUILDFLAG(IS_WIN) -#include "device/vr/windows/d3d11_texture_helper.h" -#endif - -namespace { -// Number of frames to use for sliding averages for pose timings, -// as used for estimating prediction times. -constexpr unsigned kSlidingAverageSize = 5; - -device::mojom::XRRenderInfoPtr GetRenderInfo( - const device::mojom::XRFrameData& frame_data) { - device::mojom::XRRenderInfoPtr result = device::mojom::XRRenderInfo::New(); - - result->frame_id = frame_data.frame_id; - result->mojo_from_viewer = frame_data.mojo_from_viewer.Clone(); - - for (size_t i = 0; i < frame_data.views.size(); i++) { - result->views.push_back(frame_data.views[i]->Clone()); - } - - return result; -} - -} // namespace - -namespace device { - -mojom::XRFrameDataPtr XRDeviceAbstraction::GetNextFrameData() { - return nullptr; -} -void XRDeviceAbstraction::OnSessionStart() {} -void XRDeviceAbstraction::HandleDeviceLost() {} -bool XRDeviceAbstraction::HasSessionEnded() { - return false; -} -void XRDeviceAbstraction::OnLayerBoundsChanged(const gfx::Size& frame_size) {} -device::mojom::XREnvironmentBlendMode -XRDeviceAbstraction::GetEnvironmentBlendMode( - device::mojom::XRSessionMode session_mode) { - return device::mojom::XREnvironmentBlendMode::kOpaque; -} -device::mojom::XRInteractionMode XRDeviceAbstraction::GetInteractionMode( - device::mojom::XRSessionMode session_mode) { - return device::mojom::XRInteractionMode::kWorldSpace; -} -bool XRDeviceAbstraction::CanEnableAntiAliasing() const { - return true; -} - -XRCompositorCommon::OutstandingFrame::OutstandingFrame() = default; -XRCompositorCommon::OutstandingFrame::~OutstandingFrame() = default; - -XRCompositorCommon::XRCompositorCommon() - : XRThread("WindowsXRCompositor"), - main_thread_task_runner_( - base::SingleThreadTaskRunner::GetCurrentDefault()), - webxr_js_time_(kSlidingAverageSize), - webxr_gpu_time_(kSlidingAverageSize) { - DCHECK(main_thread_task_runner_); -} - -XRCompositorCommon::~XRCompositorCommon() { - // Since we derive from base::Thread, all derived classes must call Stop() in - // their destructor so the thread gets torn down before any members that may - // be in use on the thread get torn down. -} - -void XRCompositorCommon::ClearPendingFrame() { - DVLOG(3) << __func__; - // Notify the derived class first so it can clear its pending frame before - // potentially starting a new frame with delayed_get_frame_data_callback_. - ClearPendingFrameInternal(); - - pending_frame_.reset(); - // Send frame data to outstanding requests. - if (delayed_get_frame_data_callback_ && - (webxr_visible_ || on_webxr_submitted_)) { - // If WebXR is not visible, but the browser wants to know when it submits a - // frame, we allow the renderer to receive poses. - std::move(delayed_get_frame_data_callback_).Run(); - } -} - -bool XRCompositorCommon::IsUsingSharedImages() const { - return false; -} - -void XRCompositorCommon::SubmitFrameMissing(int16_t frame_index, - const gpu::SyncToken& sync_token) { - DVLOG(3) << __func__ << " frame_index=" << frame_index; - TRACE_EVENT_INSTANT0("xr", "SubmitFrameMissing", TRACE_EVENT_SCOPE_THREAD); - if (pending_frame_) { - // WebXR for this frame is hidden. - pending_frame_->waiting_for_webxr_ = false; - } - webxr_has_pose_ = false; -#if (BUILDFLAG(IS_ANDROID)) - // We haven't finished the rendering path on Android yet so are just calling - // this to ensure that the page stays un-stuck while we aren't actually - // rendering anything. - // TODO(alcooper): Clean this up. - pending_frame_->webxr_submitted_ = true; -#endif - MaybeCompositeAndSubmit(); -} - -void XRCompositorCommon::SubmitFrame(int16_t frame_index, - const gpu::MailboxHolder& mailbox, - base::TimeDelta time_waited) { - DVLOG(3) << __func__ << " frame_index=" << frame_index; - NOTREACHED(); -} - -void XRCompositorCommon::SubmitFrameDrawnIntoTexture( - int16_t frame_index, - const gpu::SyncToken& sync_token, - base::TimeDelta time_waited) { - DVLOG(3) << __func__ << " frame_index=" << frame_index; - NOTREACHED(); -} - -bool XRCompositorCommon::MarkFrameSubmitted(int16_t frame_index) { - DVLOG(3) << __func__; - webxr_has_pose_ = false; - // Tell the browser that WebXR has submitted a frame. - if (on_webxr_submitted_) { - std::move(on_webxr_submitted_).Run(); - } - - if (!pending_frame_ || - pending_frame_->render_info_->frame_id != frame_index) { - // We weren't expecting a submitted frame. This can happen if WebXR was - // hidden by an overlay for some time. - if (submit_client_) { - submit_client_->OnSubmitFrameTransferred(false); - submit_client_->OnSubmitFrameRendered(); - TRACE_EVENT1("xr", "SubmitFrameTransferred", "success", false); - } - return false; - } - - pending_frame_->waiting_for_webxr_ = false; - pending_frame_->webxr_submitted_ = true; - pending_frame_->submit_frame_time_ = base::TimeTicks::Now(); - - return true; -} - -#if BUILDFLAG(IS_WIN) -void XRCompositorCommon::SubmitFrameWithTextureHandle( - int16_t frame_index, - mojo::PlatformHandle texture_handle, - const gpu::SyncToken& sync_token) { - DVLOG(3) << __func__ << " frame_index=" << frame_index; - TRACE_EVENT1("xr", "SubmitFrameWithTextureHandle", "frameIndex", frame_index); - if (!MarkFrameSubmitted(frame_index)) { - return; - } - - base::win::ScopedHandle scoped_handle = texture_handle.is_valid() - ? texture_handle.TakeHandle() - : base::win::ScopedHandle(); - texture_helper_.SetSourceTexture(std::move(scoped_handle), sync_token, - left_webxr_bounds_, right_webxr_bounds_); - - // Regardless of success - try to composite what we have. - MaybeCompositeAndSubmit(); -} -#endif - -void XRCompositorCommon::CleanUp() { - DVLOG(1) << __func__; - submit_client_.reset(); - webxr_has_pose_ = false; - presentation_receiver_.reset(); - frame_data_receiver_.reset(); - overlay_receiver_.reset(); - StopRuntime(); -} - -void XRCompositorCommon::RequestOverlay( - mojo::PendingReceiver<mojom::ImmersiveOverlay> receiver) { - overlay_receiver_.reset(); - overlay_receiver_.Bind(std::move(receiver)); - - // WebXR is visible and overlay hidden by default until the overlay overrides - // this. - SetOverlayAndWebXRVisibility(false, true); -} - -void XRCompositorCommon::UpdateLayerBounds(int16_t frame_id, - const gfx::RectF& left_bounds, - const gfx::RectF& right_bounds, - const gfx::Size& source_size) { - // Bounds are updated instantly, rather than waiting for frame_id. This works - // since blink always passes the current frame_id when updating the bounds. - // Ignoring the frame_id keeps the logic simpler, so this can more easily - // merge with vr_shell_gl eventually. - left_webxr_bounds_ = left_bounds; - right_webxr_bounds_ = right_bounds; - - // Swap top/bottom to account for differences between D3D and GL coordinates. - left_webxr_bounds_.set_y( - 1 - (left_webxr_bounds_.y() + left_webxr_bounds_.height())); - right_webxr_bounds_.set_y( - 1 - (right_webxr_bounds_.y() + right_webxr_bounds_.height())); - - source_size_ = source_size; - - OnLayerBoundsChanged(source_size_); -} - -void XRCompositorCommon::RequestSession( - base::RepeatingCallback<void(mojom::XRVisibilityState)> - on_visibility_state_changed, - mojom::XRRuntimeSessionOptionsPtr options, - RequestSessionCallback callback) { - webxr_has_pose_ = false; - presentation_receiver_.reset(); - frame_data_receiver_.reset(); - - EnableSupportedFeatures(options->required_features, - options->optional_features); - - // Call the subclass's StartRuntime method. Upon completion, StartRuntime will - // call the callback passed to its first parameter, start_runtime_callback. - // XRCompositorCommon::StartRuntimeFinish. We setup BindOnce such that all of - // the parameters give to us here in XRCompositorCommon::RequestSession are - // passed through to StartRuntimeFinish so that it can finish the job. - StartRuntime(base::BindOnce(&XRCompositorCommon::StartRuntimeFinish, - base::Unretained(this), - std::move(on_visibility_state_changed), - std::move(options), std::move(callback))); -} - -void XRCompositorCommon::StartRuntimeFinish( - base::RepeatingCallback<void(mojom::XRVisibilityState)> - on_visibility_state_changed, - mojom::XRRuntimeSessionOptionsPtr options, - RequestSessionCallback callback, - bool success) { - if (!success) { - TRACE_EVENT_INSTANT0("xr", "Failed to start runtime", - TRACE_EVENT_SCOPE_THREAD); - main_thread_task_runner_->PostTask( - FROM_HERE, base::BindOnce(std::move(callback), false, nullptr)); - return; - } - - on_visibility_state_changed_ = std::move(on_visibility_state_changed); - - // Queue up a notification to the requester of the current visibility state, - // so that it can be initialized to the right value. - if (on_visibility_state_changed_) { - main_thread_task_runner_->PostTask( - FROM_HERE, - base::BindOnce(on_visibility_state_changed_, visibility_state_)); - } - - device::mojom::XRPresentationTransportOptionsPtr transport_options = - device::mojom::XRPresentationTransportOptions::New(); - - if (IsUsingSharedImages()) { - transport_options->transport_method = - device::mojom::XRPresentationTransportMethod::DRAW_INTO_TEXTURE_MAILBOX; - } else { -#if BUILDFLAG(IS_WIN) - transport_options->transport_method = - device::mojom::XRPresentationTransportMethod::SUBMIT_AS_TEXTURE_HANDLE; -#else - transport_options->transport_method = - device::mojom::XRPresentationTransportMethod::SUBMIT_AS_MAILBOX_HOLDER; -#endif - } - - // Only set boolean options that we need. Default is false, and we should be - // able to safely ignore ones that our implementation doesn't care about. - transport_options->wait_for_transfer_notification = true; - - OnSessionStart(); - - auto submit_frame_sink = device::mojom::XRPresentationConnection::New(); - submit_frame_sink->provider = - presentation_receiver_.BindNewPipeAndPassRemote(); - submit_frame_sink->client_receiver = - submit_client_.BindNewPipeAndPassReceiver(); - submit_frame_sink->transport_options = std::move(transport_options); - - auto session = device::mojom::XRSession::New(); - session->data_provider = frame_data_receiver_.BindNewPipeAndPassRemote(); - session->submit_frame_sink = std::move(submit_frame_sink); - - session->enabled_features.insert(session->enabled_features.end(), - enabled_features_.begin(), - enabled_features_.end()); - - session->device_config = device::mojom::XRSessionDeviceConfig::New(); - session->device_config->enable_anti_aliasing = CanEnableAntiAliasing(); - session->device_config->views = GetDefaultViews(); - session->enviroment_blend_mode = GetEnvironmentBlendMode(options->mode); - session->interaction_mode = GetInteractionMode(options->mode); - - main_thread_task_runner_->PostTask( - FROM_HERE, base::BindOnce(std::move(callback), true, std::move(session))); - is_presenting_ = true; - -#if BUILDFLAG(IS_WIN) - texture_helper_.SetSourceAndOverlayVisible(webxr_visible_, overlay_visible_); -#endif -} - -void XRCompositorCommon::ExitPresent(ExitXrPresentReason reason) { - DVLOG(1) << __func__ << " reason=" << base::to_underlying(reason); - TRACE_EVENT_INSTANT1("xr", "ExitPresent", TRACE_EVENT_SCOPE_THREAD, "reason", - base::to_underlying(reason)); - if (!is_presenting_) - return; - - is_presenting_ = false; - webxr_has_pose_ = false; - presentation_receiver_.reset(); - frame_data_receiver_.reset(); - submit_client_.reset(); - - pending_frame_.reset(); - delayed_get_frame_data_callback_.Reset(); - - // Reset webxr_visible_ for subsequent presentations. - webxr_visible_ = true; - - // Kill outstanding overlays: - overlay_visible_ = false; - overlay_receiver_.reset(); - -#if BUILDFLAG(IS_WIN) - texture_helper_.SetSourceAndOverlayVisible(false, false); -#endif - - // Don't call StopRuntime until this thread has finished the rest of the work. - // This is to prevent the OpenXrApiWrapper from being deleted before its - // cleanup work has finished. - task_runner()->PostTask(FROM_HERE, - base::BindOnce(&XRCompositorCommon::StopRuntime, - weak_ptr_factory_.GetWeakPtr())); -} - -void XRCompositorCommon::SetVisibilityState( - mojom::XRVisibilityState visibility_state) { - if (visibility_state_ != visibility_state) { - visibility_state_ = visibility_state; - if (on_visibility_state_changed_) { - main_thread_task_runner_->PostTask( - FROM_HERE, - base::BindOnce(on_visibility_state_changed_, visibility_state)); - } - } -} - -const mojom::VRStageParametersPtr& -XRCompositorCommon::GetCurrentStageParameters() const { - return current_stage_parameters_; -} - -void XRCompositorCommon::SetStageParameters( - mojom::VRStageParametersPtr stage_parameters) { - // If the stage parameters are identical no need to update them. - if ((!current_stage_parameters_ && !stage_parameters) || - (current_stage_parameters_ && stage_parameters && - current_stage_parameters_.Equals(stage_parameters))) { - return; - } - - // If they have changed, increment the ID and save the new parameters. - stage_parameters_id_++; - current_stage_parameters_ = std::move(stage_parameters); -} - -void XRCompositorCommon::Init() {} - -void XRCompositorCommon::StartPendingFrame() { - DVLOG(3) << __func__ << " pending_frame_=" << pending_frame_.has_value(); - if (!pending_frame_) { - pending_frame_.emplace(); - pending_frame_->waiting_for_webxr_ = webxr_visible_; - pending_frame_->waiting_for_overlay_ = overlay_visible_; - pending_frame_->frame_data_ = GetNextFrameData(); - // GetNextFrameData() should never return null: - DCHECK(pending_frame_->frame_data_); - pending_frame_->render_info_ = GetRenderInfo(*pending_frame_->frame_data_); - } -} - -void XRCompositorCommon::GetFrameData( - mojom::XRFrameDataRequestOptionsPtr options, - mojom::XRFrameDataProvider::GetFrameDataCallback callback) { - TRACE_EVENT0("xr", "GetFrameData"); - if (HasSessionEnded()) { - ExitPresent(ExitXrPresentReason::kGetFrameAfterSessionEnded); - return; - } - - // HasSessionEnded() may do some work that alters the state of - // `is_presenting_`, in which case we'll get the ExitPresent log to know that - // we've ignored this request; but otherwise, we should log the rest of the - // state after that. - DVLOG(3) << __func__ << " is_presenting_=" << is_presenting_ - << " webxr_visible=" << webxr_visible_ - << " on_webxr_submitted_=" << !!on_webxr_submitted_ - << " webxr_has_pose_=" << webxr_has_pose_; - - if (!is_presenting_) { - return; - } - - // If we've already given out a pose for the current frame, or aren't visible, - // delay giving out a pose until the next frame we are visible. - // However, if we aren't visible and the browser is waiting to learn that - // WebXR has submitted a frame, we can give out a pose as though we are - // visible. - if ((!webxr_visible_ && !on_webxr_submitted_) || webxr_has_pose_) { - // There should only be one outstanding GetFrameData call at a time. We - // shouldn't get new ones until this resolves or presentation ends/restarts. - if (delayed_get_frame_data_callback_) { - frame_data_receiver_.ReportBadMessage( - "Multiple outstanding GetFrameData calls"); - return; - } - delayed_get_frame_data_callback_ = base::BindOnce( - &XRCompositorCommon::GetFrameData, base::Unretained(this), - std::move(options), std::move(callback)); - return; - } - - StartPendingFrame(); - webxr_has_pose_ = true; - pending_frame_->webxr_has_pose_ = true; - pending_frame_->sent_frame_data_time_ = base::TimeTicks::Now(); - - // TODO(https://crbug.com/1218135): The lack of frame_data_ here indicates - // that we probably should have deferred this call, but it matches the - // behavior from before the stage parameters were updated in this function and - // avoids a crash. Likely the deferral above should check if we're awaiting - // either the webxr or overlay submit. - if (pending_frame_->frame_data_) { - // If the stage parameters have been updated since the last frame that was - // sent, send the updated values. - pending_frame_->frame_data_->stage_parameters_id = stage_parameters_id_; - if (options->stage_parameters_id != stage_parameters_id_) { - pending_frame_->frame_data_->stage_parameters = - current_stage_parameters_.Clone(); - } - } else { - TRACE_EVENT0("xr", "GetFrameData Missing FrameData"); - } - - // Yield here to let the event queue process pending mojo messages, - // specifically the next gamepad callback request that's likely to - // have been sent during WaitGetPoses. - task_runner()->PostTask( - FROM_HERE, base::BindOnce(&XRCompositorCommon::SendFrameData, - base::Unretained(this), std::move(callback), - std::move(pending_frame_->frame_data_))); - - next_frame_id_ += 1; - if (next_frame_id_ < 0) { - next_frame_id_ = 0; - } -} - -void XRCompositorCommon::SendFrameData( - XRFrameDataProvider::GetFrameDataCallback callback, - mojom::XRFrameDataPtr frame_data) { - DVLOG(3) << __func__; - TRACE_EVENT0("xr", "SendFrameData"); - - // This method represents a call from the renderer process. If our visibility - // state is hidden, we should avoid handing "sensitive" information, like the - // pose back up to the renderer. Note that this check is done here as other - // methods (RequestNextOverlayPose) represent a call from the browser process, - // which should receive the pose. - bool is_visible = - (visibility_state_ != device::mojom::XRVisibilityState::HIDDEN); - - // We have posted a message to allow other calls to get through, and now state - // may have changed. WebXR may not be presenting any more, or may be hidden. - std::move(callback).Run(is_presenting_ && is_visible && - (webxr_visible_ || on_webxr_submitted_) - ? std::move(frame_data) - : mojom::XRFrameData::New()); -} - -void XRCompositorCommon::GetEnvironmentIntegrationProvider( - mojo::PendingAssociatedReceiver< - device::mojom::XREnvironmentIntegrationProvider> environment_provider) { - // Environment integration is not supported. This call should not - // be made on this device. - mojo::ReportBadMessage("Environment integration is not supported."); -} - -void XRCompositorCommon::SubmitOverlayTexture( - int16_t frame_id, - mojo::PlatformHandle texture_handle, - const gpu::SyncToken& sync_token, - const gfx::RectF& left_bounds, - const gfx::RectF& right_bounds, - SubmitOverlayTextureCallback overlay_submit_callback) { - TRACE_EVENT_INSTANT0("xr", "SubmitOverlay", TRACE_EVENT_SCOPE_THREAD); - DCHECK(overlay_visible_); - overlay_submit_callback_ = std::move(overlay_submit_callback); - if (!pending_frame_) { - // We may stop presenting while there is a pending SubmitOverlayTexture - // outstanding. If we get an overlay submit we weren't expecting, just - // ignore it. - DCHECK(!is_presenting_); - std::move(overlay_submit_callback_).Run(false); - return; - } - - pending_frame_->waiting_for_overlay_ = false; - -#if BUILDFLAG(IS_WIN) - texture_helper_.SetOverlayTexture(texture_handle.TakeHandle(), sync_token, - left_bounds, right_bounds); - pending_frame_->overlay_submitted_ = true; - - // Regardless of success - try to composite what we have. - MaybeCompositeAndSubmit(); -#endif -} - -void XRCompositorCommon::RequestNextOverlayPose( - RequestNextOverlayPoseCallback callback) { - DVLOG(3) << __func__; - // We will only request poses while the overlay is visible. - DCHECK(overlay_visible_); - TRACE_EVENT_INSTANT0("xr", "RequestOverlayPose", TRACE_EVENT_SCOPE_THREAD); - - // Ensure we have a pending frame. - StartPendingFrame(); - pending_frame_->overlay_has_pose_ = true; - std::move(callback).Run(pending_frame_->render_info_->Clone()); -} - -void XRCompositorCommon::SetOverlayAndWebXRVisibility(bool overlay_visible, - bool webxr_visible) { - DVLOG(1) << __func__ << " overlay_visible=" << overlay_visible - << " webxr_visible=" << webxr_visible; - TRACE_EVENT_INSTANT2("xr", "SetOverlayAndWebXRVisibility", - TRACE_EVENT_SCOPE_THREAD, "overlay", overlay_visible, - "webxr", webxr_visible); - // Update state. - webxr_visible_ = webxr_visible; - overlay_visible_ = overlay_visible; - if (pending_frame_) { - pending_frame_->waiting_for_webxr_ = - pending_frame_->waiting_for_webxr_ && webxr_visible; - pending_frame_->waiting_for_overlay_ = - pending_frame_->waiting_for_overlay_ && overlay_visible; - } - - // Update texture helper. -#if BUILDFLAG(IS_WIN) - texture_helper_.SetSourceAndOverlayVisible(webxr_visible, overlay_visible); -#endif - - // Maybe composite and submit if we have a pending that is now valid to - // submit. - MaybeCompositeAndSubmit(); -} - -void XRCompositorCommon::RequestNotificationOnWebXrSubmitted( - RequestNotificationOnWebXrSubmittedCallback callback) { - on_webxr_submitted_ = std::move(callback); -} - -void XRCompositorCommon::MaybeCompositeAndSubmit() { - DVLOG(3) << __func__; - if (!pending_frame_) { - // There is no outstanding frame, nor frame to composite, but there may be - // pending GetFrameData calls, so ClearPendingFrame() to respond to them. - ClearPendingFrame(); - return; - } - - // Check if we have obtained all layers (overlay and webxr) that we need. - if (pending_frame_->waiting_for_webxr_ || - pending_frame_->waiting_for_overlay_) { - DVLOG(3) << __func__ << "Waiting for additional layers, waiting_for_webxr_=" - << pending_frame_->waiting_for_webxr_ - << " waiting_for_overlay=" << pending_frame_->waiting_for_overlay_; - // Haven't received submits from all layers. - return; - } - - // TODO(https://crbug.com/1454950): Unify OpenXr Rendering paths. -#if BUILDFLAG(IS_WIN) - bool copy_successful = false; - bool has_webxr_content = pending_frame_->webxr_submitted_ && webxr_visible_; - bool has_overlay_content = - pending_frame_->overlay_submitted_ && overlay_visible_; - bool can_submit = has_webxr_content || has_overlay_content; - - // Tell texture helper to composite, then grab the output texture, and submit. - // If we submitted, set up the next frame, and send outstanding pose requests. - if (can_submit) { - copy_successful = texture_helper_.UpdateBackbufferSizes() && - texture_helper_.CompositeToBackBuffer(); - } else { - texture_helper_.CleanupNoSubmit(); - } -#elif BUILDFLAG(IS_ANDROID) - bool copy_successful = true; -#endif - - // A copy can only be succesful if we actually tried to submit. - if (copy_successful) { - pending_frame_->frame_ready_time_ = base::TimeTicks::Now(); - if (!SubmitCompositedFrame()) { - ExitPresent(ExitXrPresentReason::kSubmitFrameFailed); - // ExitPresent() clears pending_frame_, so return here to avoid - // accessing it below. - return; - } - } - - if (pending_frame_->webxr_submitted_ && copy_successful) { - // We've submitted a frame. - webxr_js_time_.AddSample(pending_frame_->submit_frame_time_ - - pending_frame_->sent_frame_data_time_); - webxr_gpu_time_.AddSample(pending_frame_->frame_ready_time_ - - pending_frame_->submit_frame_time_); - - TRACE_EVENT_INSTANT2( - "gpu", "WebXR frame time (ms)", TRACE_EVENT_SCOPE_THREAD, "javascript", - webxr_js_time_.GetAverage().InMillisecondsF(), "rendering", - webxr_gpu_time_.GetAverage().InMillisecondsF()); - fps_meter_.AddFrame(base::TimeTicks::Now()); - TRACE_COUNTER1("gpu", "WebXR FPS", fps_meter_.GetFPS()); - } - - if (pending_frame_->webxr_submitted_ && submit_client_) { - // Tell WebVR that we are done with the texture (if we got a texture) - submit_client_->OnSubmitFrameTransferred(copy_successful); - submit_client_->OnSubmitFrameRendered(); - TRACE_EVENT1("xr", "SubmitFrameTransferred", "success", copy_successful); - } - - if (pending_frame_->overlay_submitted_ && overlay_submit_callback_) { - // Tell the browser/overlay that we are done with its texture so it can be - // reused. - std::move(overlay_submit_callback_).Run(copy_successful); - } - - ClearPendingFrame(); -} - -} // namespace device
diff --git a/device/vr/windows/compositor_base.h b/device/vr/windows/compositor_base.h deleted file mode 100644 index 120bdcc..0000000 --- a/device/vr/windows/compositor_base.h +++ /dev/null
@@ -1,269 +0,0 @@ -// Copyright 2018 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef DEVICE_VR_WINDOWS_COMPOSITOR_BASE_H_ -#define DEVICE_VR_WINDOWS_COMPOSITOR_BASE_H_ - -#include "base/memory/scoped_refptr.h" -#include "base/memory/weak_ptr.h" -#include "base/task/single_thread_task_runner.h" -#include "base/time/time.h" -#include "build/build_config.h" -#include "device/vr/public/mojom/isolated_xr_service.mojom.h" -#include "device/vr/public/mojom/vr_service.mojom.h" -#include "device/vr/public/mojom/xr_session.mojom.h" -#include "device/vr/util/fps_meter.h" -#include "device/vr/util/sliding_average.h" -#include "device/vr/vr_device.h" -#include "mojo/public/cpp/bindings/associated_remote.h" -#include "mojo/public/cpp/bindings/pending_associated_receiver.h" -#include "mojo/public/cpp/bindings/pending_associated_remote.h" -#include "mojo/public/cpp/bindings/pending_receiver.h" -#include "mojo/public/cpp/bindings/receiver.h" -#include "mojo/public/cpp/bindings/remote.h" -#include "mojo/public/cpp/platform/platform_handle.h" -#include "ui/gfx/geometry/rect_f.h" - -#if BUILDFLAG(IS_WIN) -#include "base/threading/thread.h" -#include "device/vr/windows/d3d11_texture_helper.h" -#endif - -#if BUILDFLAG(IS_ANDROID) -#include "base/android/java_handler_thread.h" -#endif - -namespace gpu::gles2 { -class GLES2Interface; -} // namespace gpu::gles2 - -namespace device { - -enum class ExitXrPresentReason : int32_t { - kUnknown = 0, - kMojoConnectionError = 1, - kOpenXrUninitialize = 2, - kStartRuntimeFailed = 3, - kOpenXrStartFailed = 4, - kXrEndFrameFailed = 5, - kGetFrameAfterSessionEnded = 6, - kSubmitFrameFailed = 7, - kBrowserShutdown = 8, - kXrPlatformHelperShutdown = 9, -}; - -class XRDeviceAbstraction { - public: - virtual mojom::XRFrameDataPtr GetNextFrameData(); - - using StartRuntimeCallback = base::OnceCallback<void(bool success)>; - virtual void StartRuntime(StartRuntimeCallback start_runtime_callback) = 0; - virtual void StopRuntime() = 0; - virtual void OnSessionStart(); - virtual bool HasSessionEnded(); - virtual bool SubmitCompositedFrame() = 0; - virtual void HandleDeviceLost(); - virtual void OnLayerBoundsChanged(const gfx::Size& size); - // Sets enabled_features_ based on what features are supported - virtual void EnableSupportedFeatures( - const std::vector<device::mojom::XRSessionFeature>& requiredFeatures, - const std::vector<device::mojom::XRSessionFeature>& optionalFeatures) = 0; - virtual device::mojom::XREnvironmentBlendMode GetEnvironmentBlendMode( - device::mojom::XRSessionMode session_mode); - virtual device::mojom::XRInteractionMode GetInteractionMode( - device::mojom::XRSessionMode session_mode); - virtual bool CanEnableAntiAliasing() const; - virtual std::vector<mojom::XRViewPtr> GetDefaultViews() const = 0; -}; - -#if BUILDFLAG(IS_ANDROID) -class XRThread : public base::android::JavaHandlerThread { - public: - explicit XRThread(const char* name) - : base::android::JavaHandlerThread(name) {} - ~XRThread() override = default; -}; -#elif BUILDFLAG(IS_WIN) -class XRThread : public base::Thread { - public: - explicit XRThread(const char* name) : base::Thread(name) {} - ~XRThread() override = default; -}; -#else -#error "Trying to build OpenXR for an unsupported platform" -#endif - -class XRCompositorCommon : public XRThread, - public XRDeviceAbstraction, - public mojom::XRPresentationProvider, - public mojom::XRFrameDataProvider, - public mojom::ImmersiveOverlay { - public: - using RequestSessionCallback = - base::OnceCallback<void(bool result, mojom::XRSessionPtr)>; - - XRCompositorCommon(); - - XRCompositorCommon(const XRCompositorCommon&) = delete; - XRCompositorCommon& operator=(const XRCompositorCommon&) = delete; - - ~XRCompositorCommon() override; - - void RequestSession(base::RepeatingCallback<void(mojom::XRVisibilityState)> - on_visibility_state_changed, - mojom::XRRuntimeSessionOptionsPtr options, - RequestSessionCallback callback); - void ExitPresent(ExitXrPresentReason reason); - - void GetFrameData(mojom::XRFrameDataRequestOptionsPtr options, - XRFrameDataProvider::GetFrameDataCallback callback) final; - - void GetEnvironmentIntegrationProvider( - mojo::PendingAssociatedReceiver< - device::mojom::XREnvironmentIntegrationProvider> environment_provider) - override; - - void RequestOverlay(mojo::PendingReceiver<mojom::ImmersiveOverlay> receiver); - - virtual gpu::gles2::GLES2Interface* GetContextGL() = 0; - - protected: - void SetVisibilityState(mojom::XRVisibilityState visibility_state); - const mojom::VRStageParametersPtr& GetCurrentStageParameters() const; - void SetStageParameters(mojom::VRStageParametersPtr stage_parameters); -#if BUILDFLAG(IS_WIN) - D3D11TextureHelper texture_helper_{this}; -#endif - int16_t next_frame_id_ = 0; - - // Allow derived classes to call methods on the main thread. - scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_; - - // Derived classes override this to be notified to clear its pending frame. - virtual void ClearPendingFrameInternal() {} - - std::unordered_set<device::mojom::XRSessionFeature> enabled_features_; - - // Override the default of false if you wish to use shared buffers across - // processes - virtual bool IsUsingSharedImages() const; - - // XRPresentationProvider overrides: - void SubmitFrame(int16_t frame_index, - const gpu::MailboxHolder& mailbox, - base::TimeDelta time_waited) override; - void SubmitFrameDrawnIntoTexture(int16_t frame_index, - const gpu::SyncToken&, - base::TimeDelta time_waited) override; - void SubmitFrameMissing(int16_t frame_index, const gpu::SyncToken&) final; -#if BUILDFLAG(IS_WIN) - void SubmitFrameWithTextureHandle(int16_t frame_index, - mojo::PlatformHandle texture_handle, - const gpu::SyncToken& sync_token) final; -#endif - - // Will Submit if we have textures submitted from the Overlay (if it is - // visible), and WebXR (if it is visible). We decide what to wait for during - // StartPendingFrame, may mark things as ready after SubmitFrameMissing and - // SubmitFrameWithTextureHandle (for WebXR), or SubmitOverlayTexture (for - // overlays), or SetOverlayAndWebXRVisibility (for WebXR and overlays). - // Finally, if we exit presentation while waiting for outstanding submits, we - // will clean up our pending-frame state. - void MaybeCompositeAndSubmit(); - - // Sets all relevant internal state to mark that we have successfully received - // a frame. Will return whether or not the given frame index was expected. - // If not expected, not all state may be successfully cleared. - bool MarkFrameSubmitted(int16_t frame_index); - - private: - // base::Thread overrides: - void Init() final; - void CleanUp() final; - - void ClearPendingFrame(); - void StartPendingFrame(); - - void StartRuntimeFinish( - base::RepeatingCallback<void(mojom::XRVisibilityState)> - on_visibility_state_changed, - mojom::XRRuntimeSessionOptionsPtr options, - RequestSessionCallback callback, - bool success); - - // XRPresentationProvider overrides: - void UpdateLayerBounds(int16_t frame_id, - const gfx::RectF& left_bounds, - const gfx::RectF& right_bounds, - const gfx::Size& source_size) final; - - // ImmersiveOverlay: - void SubmitOverlayTexture(int16_t frame_id, - mojo::PlatformHandle texture, - const gpu::SyncToken& sync_token, - const gfx::RectF& left_bounds, - const gfx::RectF& right_bounds, - SubmitOverlayTextureCallback callback) override; - void RequestNextOverlayPose(RequestNextOverlayPoseCallback callback) override; - void SetOverlayAndWebXRVisibility(bool overlay_visible, - bool webxr_visible) override; - void RequestNotificationOnWebXrSubmitted( - RequestNotificationOnWebXrSubmittedCallback callback) override; - - void SendFrameData(XRFrameDataProvider::GetFrameDataCallback callback, - mojom::XRFrameDataPtr frame_data); - - struct OutstandingFrame { - OutstandingFrame(); - ~OutstandingFrame(); - bool webxr_has_pose_ = false; - bool overlay_has_pose_ = false; - bool webxr_submitted_ = false; - bool overlay_submitted_ = false; - bool waiting_for_webxr_ = false; - bool waiting_for_overlay_ = false; - - mojom::XRFrameDataPtr frame_data_; - mojom::XRRenderInfoPtr render_info_; - - base::TimeTicks sent_frame_data_time_; - base::TimeTicks submit_frame_time_; - base::TimeTicks frame_ready_time_; - }; - - FPSMeter fps_meter_; - SlidingTimeDeltaAverage webxr_js_time_; - SlidingTimeDeltaAverage webxr_gpu_time_; - - absl::optional<OutstandingFrame> pending_frame_; - - bool is_presenting_ = false; // True if we have a presenting session. - bool webxr_visible_ = true; // The browser may hide a presenting session. - bool overlay_visible_ = false; - base::OnceCallback<void()> delayed_get_frame_data_callback_; - - gfx::RectF left_webxr_bounds_; - gfx::RectF right_webxr_bounds_; - gfx::Size source_size_; - - mojo::Remote<mojom::XRPresentationClient> submit_client_; - SubmitOverlayTextureCallback overlay_submit_callback_; - RequestNotificationOnWebXrSubmittedCallback on_webxr_submitted_; - bool webxr_has_pose_ = false; - base::RepeatingCallback<void(mojom::XRVisibilityState)> - on_visibility_state_changed_; - mojo::Receiver<mojom::XRPresentationProvider> presentation_receiver_{this}; - mojo::Receiver<mojom::XRFrameDataProvider> frame_data_receiver_{this}; - mojo::Receiver<mojom::ImmersiveOverlay> overlay_receiver_{this}; - mojom::XRVisibilityState visibility_state_ = - mojom::XRVisibilityState::VISIBLE; - mojom::VRStageParametersPtr current_stage_parameters_; - uint32_t stage_parameters_id_; - - base::WeakPtrFactory<XRCompositorCommon> weak_ptr_factory_{this}; -}; - -} // namespace device - -#endif // DEVICE_VR_WINDOWS_COMPOSITOR_BASE_H_
diff --git a/device/vr/windows/d3d11_texture_helper.cc b/device/vr/windows/d3d11_texture_helper.cc index 2b551241..96da3dba 100644 --- a/device/vr/windows/d3d11_texture_helper.cc +++ b/device/vr/windows/d3d11_texture_helper.cc
@@ -6,7 +6,7 @@ #include "base/trace_event/common/trace_event_common.h" #include "base/trace_event/trace_event.h" -#include "device/vr/windows/compositor_base.h" +#include "device/vr/openxr/openxr_render_loop.h" #include "gpu/command_buffer/client/gles2_interface.h" #include "gpu/command_buffer/common/constants.h" #include "mojo/public/c/system/platform_handle.h" @@ -72,8 +72,8 @@ D3D11TextureHelper::LayerData::LayerData() = default; D3D11TextureHelper::LayerData::~LayerData() = default; -D3D11TextureHelper::D3D11TextureHelper(XRCompositorCommon* compositor) - : compositor_(compositor) {} +D3D11TextureHelper::D3D11TextureHelper(OpenXrRenderLoop* render_loop) + : render_loop_(render_loop) {} D3D11TextureHelper::~D3D11TextureHelper() {} @@ -205,7 +205,7 @@ // until GPU process has passed the sync token. This must happen before // AcquireSync(0) below otherwise the GPU process will be unable to // acquire the mutex and work will happen out of order. - gpu::gles2::GLES2Interface* gl = compositor_->GetContextGL(); + gpu::gles2::GLES2Interface* gl = render_loop_->GetContextGL(); gl->WaitSyncTokenCHROMIUM( render_state_.source_.sync_token_.GetConstData()); gl->Finish(); @@ -228,7 +228,7 @@ // until GPU process has passed the sync token. This must happen before // AcquireSync(0) below otherwise the GPU process will be unable to // acquire the mutex and work will happen out of order. - gpu::gles2::GLES2Interface* gl = compositor_->GetContextGL(); + gpu::gles2::GLES2Interface* gl = render_loop_->GetContextGL(); gl->WaitSyncTokenCHROMIUM( render_state_.overlay_.sync_token_.GetConstData()); gl->Finish();
diff --git a/device/vr/windows/d3d11_texture_helper.h b/device/vr/windows/d3d11_texture_helper.h index c2cb5925..1b12c34 100644 --- a/device/vr/windows/d3d11_texture_helper.h +++ b/device/vr/windows/d3d11_texture_helper.h
@@ -16,11 +16,11 @@ namespace device { -class XRCompositorCommon; +class OpenXrRenderLoop; class D3D11TextureHelper { public: - explicit D3D11TextureHelper(XRCompositorCommon* compositor); + explicit D3D11TextureHelper(OpenXrRenderLoop* render_loop); ~D3D11TextureHelper(); void Reset(); @@ -106,7 +106,7 @@ LayerData overlay_; }; - const raw_ptr<XRCompositorCommon> compositor_; + const raw_ptr<OpenXrRenderLoop> render_loop_; bool overlay_visible_ = true; bool source_visible_ = true;
diff --git a/docs/security/shepherd.md b/docs/security/shepherd.md index 5d399ba1..b4830cdf 100644 --- a/docs/security/shepherd.md +++ b/docs/security/shepherd.md
@@ -1,139 +1,178 @@ # Security Shepherd +## What is Security Shepherding? +Security Shepherding is a rotational assignment for security bug triage +(Primary Shepherd) and managing the flow of incoming inquiries and progressing +security issues (Secondary Shepherd). The Shepherding rota pool is made up of +people actively working on security in Chrome. + +All Security Shepherds are Googlers; therefore, some links on this page may +not be externally accessible or even further restricted to just Chrome Security +Googlers. + +There is a Primary and Secondary Shepherd scheduled each rotation, with two +rotations each week, one Tuesday - Thursday and Friday - Monday. + +Security Shepherding is *not* an on-call rotation. There’s no pager duty, nor +are you expected to perform Shepherding duties outside of your usual working +hours, such as overnight or on holidays, weekends, or other off time. + +Shepherds are only responsible for triage of security bugs during your shift. +You are not responsible for bug triage or updating partially triaged bugs past +your shift, unless you have specifically taken ownership of an issue, such as +due to a complicated or OS-specific reproduction, and arranged that with the +oncoming shepherd. All shepherds should use the handoff doc to communicate items +for handover; however, the oncoming primary shepherd should operate on the +premise all new or _under_-triaged issues are your responsibility. Please do not +leave any unaddressed red cells in the dashboard at the end of your shift. + +# TL;DR Checklist for Primary Shepherding +(“I’m Primary Shepherd, what do I do???”) + +The Primary Security Shepherd is the front line of security bug triage during +their shift. The goal is to triage incoming security issues accurately, +thoroughly, and quickly (_as quickly as realistically possible_). + +Your PRIMARY DIRECTIVE as PRIMARY SHEPHERD is to tackle all the red cells on the +security bug dashboard. + +For [*every new incoming security bug*](#Every-New-Incoming-Security-Bug): +* Make sure it's [*self-contained*](#Ensure-self-contained-issue). +* Make sure the report is [*valid and actionable*](#Confirm-valid-and-actionable) + * Ideally, you’ll be able to do this by [reproducing the bug](#Reproduce-the-bug), + more ideally, [with ClusterFuzz](clusterfuzz-for-shepherds.md). +* Set [*severity*](#Set-Severity). +* Set [*oldest impacted active release channel*](#Set-oldest-impacted-active-release-channel) – AKA FoundIn. +* Set [*impacted-operating-systems*](#Set-impacted-operating-systems). +* [*Assign*](#Assign) to an appropriate or suitable owner or engineering team. + +All of the above should be completed as soon as possible during your shift, +and at least, by the [shift-handoff](#shift-handoff). + +One or more of the above actions may necessary to complete the triage of an +under-triaged bug, i.e. covering any of the open red cells in the dashboard that +were not completed from ClusterFuzz auto-triage or previous work on the bug. + +All this is hard, so please remember to [ask for help](#Ask-for-help). +[Yell if you must](https://www.youtube.com/watch?v=5y_SbnPx_cE&t=37s)! + +# TL;DR Checklist for Secondary Shepherding +(“I’m Secondary Shepherd, what do I do???”) + +* [*Check in on triaged issues*](#Check-In-On-Triaged-Issues] to ensure progress + is being made on medium+ severity security bugs. +* [*Manage incoming security email*](#Manage-incoming-security-email). + + [TOC] -## Important Links +## Links to Helpful Resources -[Chrome Open Security Bugs dashboard, -go/chrome-security-bugs](http://go/chrome-security-bugs). +Here are some of the importance references and resources you need or may need +during your shepherding shift: -[Vulnerability Severity Guidelines](severity-guidelines.md). +* [Current Shepherds](https://script.google.com/a/macros/google.com/s/AKfycbz02xD4ghSzZu_tXyNRgjC95wFURATZeD_FHq0KRMHeqA-b0b9sow4NV1lhi0P2vy1j/exec) +* [Chrome Security Bug Dashboard](https://goto.google.com/chrome-security-bugs} +* [Security Severity Guidelines](severity-guidelines.md) +* [Security Labels](security-labels.md) +* FAQs addressing commonly-raised questions about security and what is / is not + considered a security bug, to see if there is an existing stance: + * [Chrome Security FAQ](faq.md) + * [Extensions Security FAQ](https://chromium.googlesource.com/chromium/src/+/refs/heads/main/extensions/docs/security_faq.md) + * [Service Worker Security FAQ](service-worker-security-faq.md) +* [Redshell for Security Shepherds](https://goto.google.com/redshell-for-chrome-shepherds) +* [Shepherding Guidelines Changelog](https://goto.google.com/shepherding-changelog) for highlighting + any process or policy changes since your last shift. +* [Guidance for triage of theoretical or speculative issues](https://goto.google.com/chrome-speculative-bug-triage) +* [Reference for common questions about security bug lifecycle](life-of-a-security-issue.md) +[Reference for questions related to security fix merge process](https://chromium.googlesource.com/chromium/src/+/HEAD/docs/process/merge_request.md#Security-merge-triage) + for answering questions (you do not need to approve merges). +* [Shepherding Handoff Log](https://goto.google.com/chrome-security-shepherd-handoff) -[Security Labels](security-labels.md). +### Every New Incoming Security Bug -[Current Shepherds](http://go/whos-the-shepherd). +Monitor the [Chrome open security bugs dashboard](http://go/chrome-security-bugs). +Tackle all the empty red cells. New bugs populate at the top of the sheet and +will need full triage. Partially triaged bugs, such as those triaged by +ClusterFuzz or ones pending updates from a prior shift, may be lower in the +sheet. Please check the sheet for any red cells and do your best to get any bugs +to a fully triaged state. -[Shepherd Handoff Log](http://go/chrome-security-shepherd-handoff). +We aim to have every bug triaged and assigned **within two business days, +preferably one.** This does not include weekends, but please ensure you leave a +clear queue before the weekend or a holiday. -You might also like the [HOWTO: Be A Security Shepherd -deck](https://docs.google.com/presentation/d/1eISJXxyv7dUCGUKk_rvUI9t9s2xb98QY4d_-dZSa7Wg/edit#slide=id.p). +### Ensure self-contained issue -The [Chrome Security FAQ](faq.md), [Extensions Security -FAQ](/extensions/docs/security_faq.md), and [Service Worker Security -FAQ](service-worker-security-faq.md) include commonly-raised questions about -security and what is or is not considered a security bug. When triaging new -bugs, you may want to reference these to see if there's an established stance. +There should be one complete, self-contained report, per root cause. To ensure +this is the case when assigning security bugs to engineering teams, you may +need to take some specific actions here: +* If the report is a bug chain with several underlying causes, **open one new + bug per root cause** and marked the parent bug as `blocked on` each. The parent + bug should be set to the severity of the full chain. Each child bug may have a + lower severity. + * If taking these actions for a VRP reported issue, add the `reward_to` + label with that reporter's email address and cc: them on the parent issue so + they have access. +* Get everything you need from a reporter before you try and reproduce - do not + feel bad about asking for a clear or minimized POC or repeatable steps before + attempting to reproduce. +* If complicated user gestures are required, encourage the reporter to upload a + short video. This will alleviate a lot of back and forth for both them and us. -## What Is A Security Shepherd? +## Confirm Valid and Actionable -A security shepherd is a member of a rotation that occurs in two different time -slots: Tues to Thurs or Fri to Mon. There is a primary and secondary shepherd on -each rotation. All shepherds are Googlers and so some links on this page might -not be externally accessible (or indeed locked down to just Chrome Security -Googlers). +We expect engineering teams to address security bugs promptly. In order to do +that, our goal is to pass them actionable reports with little ambiguity. -[Here is the rotation -schedule](https://docs.google.com/spreadsheets/d/10sLYZbi6QfLcXrhO-j5eSc82uc7NKnBz_o1pR9y8h7U/edit#gid=0). +*For each bug, please take the appropriate action, either:* -Shepherds ensure that all incoming security issues are triaged -quickly and correctly. We aim to have every bug triaged and assigned **within -two business days** (preferably one). This does not include weekends, but please -ensure you leave a clear queue before the weekend (i.e. on Friday, unless there -is a holiday) and check first thing after the weekend (i.e. on Monday morning, -unless there is a holiday). +* **WontFix it as invalid** (Many recurring types of invalid reports are covered + by the [Security FAQ](faq.md), such as those related physically local attacks + or inputting JavaScript in the URL bar or running Javascript directly in + DevTools not being an indication of an XSS vulnerability. Mark as WontFix and + remove the `Restrict-View-SecurityTeam` label. +* **Mark as duplicate** – we want exactly one bug per root cause problem. Please + check for duplicate issues of a given issue from that or other reporters / + sources (such as ClusterFuzz). + * Search for similar stack traces or sharing similar keyword traits in the bug + tracker. + * If there are two open reports of the same issue, please merge as a duplicate + in the direction of the oldest report. +* **Convert functional bugs to Type=Bug** For example, many reports are for + crashes of a functional nature, rather than an exploitable security condition, + such as most null pointer dereferences. Convert such reports from + Type=Bug-Security to Type=Bug. Remove `Restrict-View-SecurityTeam`, but + consider adding other view restrictions, such as ‘Restrict-View-EditIssue’ if + the immediate disclosure could result in potential abuse (e.g. denial of + service issue). +* **Convert to a privacy bug** - privacy issues (such as issues with incognito) + are not considered security bugs, but functional privacy issues. + Convert to Type=Bug and add the Privacy component. Add yourself and any other + security team members who may potentially need access to the cc: line. + Remove `Restrict-View-SecurityTeam` and add `Restrict-View-ChromePrivacy`. +* **Add `Needs-Feedback` and set a next action date of 24-48 hours for more + information** if there is no response, close the issue as `WontFix`. +* **Determine issue to be theoretical** - and follow the + [process for such issues](http://go/chrome-speculative-bug-triage) – theoretical + issues are ones that appear to be potentially real bugs, but there the report + is lacking evidence of exploitability or reachability. These cases can be + shared with engineering teams with a very clear message conveying the + speculative nature of the issue. These reports should generally not be + prioritized as a Pri-1 as they do not warrant disruption to the engineering + teams to investigate and prioritize without more or new information to + demonstrate conditions of exploitability. +None of these apply? Great – this means the bug may be valid and actionable! +It can take multiple discussions with a reporter to understand a bug. Try really +hard to reach a conclusion by the end of your shift. If this isn’t possible, +please discuss outstanding cases with the next shepherd and don’t let bugs fall +through the cracks. You are responsible for any bug reported or in an un-triaged +state during your shift. -## When Am I The Primary or Secondary Shepherd? - -You should get a calendar invite. Please accept it to acknowledge. If you need -to swap shifts, ask around for a volunteer and then just update the -[rotation sheet](https://docs.google.com/spreadsheets/d/10sLYZbi6QfLcXrhO-j5eSc82uc7NKnBz_o1pR9y8h7U/edit#gid=0) -and wait 10 minutes for the calendar invites to be updated. - -## I'm The Security Primary or Secondary Shepherd. What Do I Do? - -Each week has a primary and secondary, and during their rotation both have -various important responsibilities: - -### Primary Shepherd - -* Look at every incoming security bug report on the - [dashboard](http://go/chrome-security-bugs). Ensure each is accurately - triaged, and actively progressing towards getting fixed. -* Don't forget to fully triage the low severity bugs. Once a bug is labeled with - `Security_Severity-Low `, it disappears from the first sheet and may slip - under your radar. -* Keep the [Shepherd Handoff Log](http://go/chrome-security-shepherd-handoff) up - to date. -* Shout for help if the incoming bug rate is too high ([suggested vocal - exercises](https://youtu.be/5y_SbnPx_cE?t=37s)). The first person to ask is - the secondary. -* Make sure all **new bug reports** are triaged completely. That means no red - cells on the top of the dashboard. Double-check that OS flags are set - properly. For most of the bugs, typically more than one OS is affected, but - the dashboard will not highlight it in red. -* Stay sharp, keep in shape ([hand-stand - pushups](https://www.youtube.com/watch?v=jZ1ZDlLImF8#t=50) are standard for - the primary shepherd), and remember you may be [called upon during - emergencies](https://www.youtube.com/watch?v=buHaKYL9Jhg). - -### Secondary Shepherd - -* Ensure that all incoming queries to the - [security@chromium.org](https://groups.google.com/a/chromium.org/forum/#!forum/security), - [security-dev@chromium.org](https://groups.google.com/a/chromium.org/forum/#!forum/security-dev), - and - [chrome-security@google.com](https://groups.google.com/a/google.com/forum/#!forum/chrome-security) - lists get a reply (by someone; not necessarily the secondary themselves). See - [go/chrome-security-emails](https://goto.google.com/chrome-security-emails) - for a dashboard. - * Note: external emails will always come in on security@chromium.org or - security-dev@chromium.org, as chrome-security@google.com is a Google-only - list, but all need to be triaged. - * When triaging an email to be handled off of the list, make sure to bcc: the - list that it arrived on, so that other people including future secondaries can - see that it has been handled. - * Some of these emails are requests for inclusion of third party code. - By the time you hand over to the next Secondary, please - ensure these are either completed or have been acknowledged by some other - owner. If not, you may need to do them yourself. Please see - [How to do Chrome Third-Party Security Reviews](https://goto.google.com/how-to-do-chrome-third-party-security-reviews) - for hints. -* Look at the open security bug reports and check that progress is occurring. - This does not apply to the **new bug reports** (these are handled by the - primary shepherd). The rule of thumb is *if there is any red cell on the dashboard, it - needs your attention*: that especially includes the "last updated" column. - (Our [severity guidelines](severity-guidelines.md) contain the expected duration - for shipping fixes, but remember, to get a fix to all users in - say - 60 - days may require us to land a fix in a week or two). - Hints: - * Don't just add a comment to the bug: sometimes they can disappear into spam. - (Although a hand-crafted, meaningful comment can be effective). - * Contact via chat or e-mail (ideally, also comment on the bug so other secondaries - can see you did so). - * CC more people! - * Think about what you can do to unblock the bug. What would _you_ do next? - Perhaps you can bring in different experts, suggest a different way to - reproduce the bug, or even write a fuzzer? Sometimes your security perspective - can really help engineering see a different way forward. - * Consider whether it's better for you to make meaningful steps forward on - ten bugs than to add ignorable nag messages to twenty bugs. - * You can't possibly hope to meaningfully move all bugs forward. As a rule of - thumb, perhaps expect to spend a solid ten hours progressing bugs during - your shift. - * Use the 'last updated' column to avoid duplicating the work of the previous - secondary. -* Stay sharp, keep in shape ([finger - exercises](https://youtu.be/iV9vyacIeEY?t=47s) are standard for the secondary), - and remember you may be called upon during emergencies. - -## Life Of A Security Bug - -Do as much as you can for the week to triage, shepherd, and wrap up open -security bugs. What follows are the details of what that entails, but it -practically means turning all the red cells in the dashboard to green. **If -you're ever stuck or in doubt, ask for help on #chrome-security! or the -[Chrome Security Chat](http://go/chrome-security-chat).** +The best way determine the validity of a security bug is to [*reproduce it*](#Reproduce-the-bug). +It’s helpful to remember that reporters invested time and energy in their bug +reports:  -### Diagnose The Issue - +If you have to close it, please give an explanation as to why. -* **If the report is invalid**, remove the **Restrict-View-SecurityTeam** label - and mark it **WontFix**. -* **If the report is a duplicate**, mark it **Duplicate**. If the issue this is - a duplicate of is public, remove the **Restrict-View-SecurityTeam** label. -* **If the report is primarily a privacy issue**, send it to the privacy team: - * Add the **Privacy** component so that it enters their triage queue. - * Change **Type-Bug-Security** to **Type-Bug**. - * CC any security team members, including yourself, who may be interested in - the privacy issue. - * Change the **Restrict-View-SecurityTeam** label to - **Restrict-View-ChromePrivacy**. - * Note that security team members don't automatically have privacy bug - access, so this will probably make the issue inaccessible to you. -* **If the report is asking about why something is or is not on the Safe - Browsing list:** - * Close the bug and request the reporter submit the URL to SafeBrowsing. - * See below for reporting URLs to SafeBrowsing. -* **If the report is a potentially valid bug but is not a security - vulnerability:** - * remove the **Restrict-View-SecurityTeam** label. If necessary, add one of - the other **Restrict-View-?** labels: - * **Restrict-View-Google** if this is a crash report. - * **Restrict-View-EditIssue** if the bug can be abused (e.g. denial of - service) - * Change **Type-Bug-Security** label to **Type-Bug** (or whatever **Type-?** - is appropriate). - * Add appropriate component or CCs to ensure it does get triaged. - * Add the **Security** component or the **Team-Security-UX** label if the - security team should still track the issue (e.g. security features). - * Please do not remove the **external_security_report** label. -* **If the report doesn't have enough information**, ask the reporter for more - information, add the **Needs-Feedback** label and wait for 24 hours for a - response. -* The [security bug template](https://bugs.chromium.org/p/chromium/issues/entry?template=Security+Bug) - asks reporters to **attach files directly**, not in zip or other archives, and - not hosted at an external resource (e.g. Google Cloud Storage). If the report - mentions an online demo hosted somewhere, make sure the reporters attach the - source code for the demo as well. -* **If the bug is a security bug, but is only applicable to Chrome OS**: - * The Chrome OS Security team now has their own sheriffing rotation. To get - bugs into their triage queue, just set OS to the single value of "Chrome". - No other steps or labels are needed. - * If you need to ping or ask about Chrome OS bug, [ask their current - sheriff](http://go/whos-the-chromeos-sheriff). -* **If the report smells like a vulnerability, keep going.** +### Reproduce the bug -### Verify And Label The Bug +Reproducing the bug isn’t always required, but often it’s needed and the only +way to: -#### Step 1. Reproduce legitimate-sounding issues. +* Understand a report and validate the issue being presented. +* Provide actionable information to the engineering team responsible for fixing + the bug. +* Setting the oldest impacted release channel correctly. -Ideally, primary shepherds should reproduce each bug before triaging, but being efficient -is also important. It's fine to delegate reproducing bugs in the following -cases: +These things must be done correctly, so as Security Shepherd, you’ll spend a lot +of time reproducing bugs. Here are some tips in doing so: -* A bug comes from an automated infrastructure (such as ClusterFuzz or Vomit). -* A bug comes from a reporter with a solid track record of vulnerabilities (e.g. - prolific external researchers or Google Project Zero team). -* A bug requires a particular device that you don't have available, or any other - environment which you don't have ready but a potential code owner would have. +* Assume that test cases may be malicious. You should only reproduce bugs + on your local machine if you're completely certain that you understand + 100% of the test case. If not, use a disposable virtual machine. If you're + inside Google, a good way to do this is using + [Redshell](https://goto.google.com/redshell-for-chrome-shepherds). +* For any sort of a crash, CHECK/DCHECK or memory safety problem + [use ClusterFuzz](clusterfuzz-for-shepherds.md). As well as reproducing bugs, + ClusterFuzz will help you with lots of subsequent bisection and labelling + tasks. Currently ClusterFuzz cannot guard against malicious test cases, + so be just as paranoid as if you were running a test case locally. +* [Instructions for using an Android emulator can be found + here](/docs/android_emulator.md). If you're inside Google, we have a + [guide for testing using Google infrastructure](https://goto.google.com/android-for-chrome-shepherds). +* When you can't just build from a specific branch locally, see + [https://dev.chromium.org/getting-involved/dev-channel](https://dev.chromium.org/getting-involved/dev-channel) + or + [https://commondatastorage.googleapis.com/chromium-browser-asan/index.html](https://commondatastorage.googleapis.com/chromium-browser-asan/index.html) + for the latest release of a specific version. +* The [get_asan_chrome.py](https://source.chromium.org/chromium/chromium/src/+/main:tools/get_asan_chrome/get_asan_chrome.py) + helper script is a handy way to download ASAN Chrome. The --help flag + provides usage instructions, e.g. to fetch builds for various versions and + platforms. +* If you run into issues with a reproducible ClusterFuzz test case (like + missing symbols, or if anything else seems off), try uploading the test case + again using a different job type with a more mature tool (e.g. ASan on Linux). + It may give more complete information. -Mention explicitly in your comment that you didn't reproduce a bug before -assigning it to someone else. +### Set severity -A few components have their own triage processes or points of contact who can -help. +Use the [Security Severity Guidelines](severity-guidelines.md). +If you can, [*reproduce it using ClusterFuzz*](clusterfuzz-for-shepherds.md), as +the severity is usually set automatically. + +For V8 issues, you can tentatively set the issue as High severity – see [Assign, +below](#Assign). + +Please adjust severity as your understanding of the bug evolves - but please +always add a comment explaining the change. Higher severity bugs involve +significant disruption for multiple teams; lower severity issues may not be +fixed and a fix released to users as quickly as may be warranted. That’s why +it’s important to get the severity as correct as possible. + +### Set oldest impacted active release channel + +We do not release severe security regressions, so we need to know the earliest +impacted Chrome release branch. + +First, if an issue [doesn’t impact Chrome users by default, add the label +**`Security_Impact-None`**](security-labels.md#when-to-use-security_impact_none-toc_security_impact_none); +otherwise, set a **FoundIn** label as follows: + +Check [ChromiumDash](https://chromiumdash.appspot.com/releases?platform=Windows) for the earliest relevant milestone number +(Extended Stable or Stable – sometimes they are the same). +* If that branch is affected, set `FoundIn-MMM` in where `MMM` is that milestone + number. +* Otherwise, move forward through milestone numbers. Set `FoundIn-MMM` to the + oldest impacted branch you find. + +There is no general reason to test versions older than the current Extended +Stable milestone. If you can [*reproduce using ClusterFuzz*](clusterfuzz-for-shepherds.md) +the `FoundIn` can often be set automatically if ClusterFuzz can identify the +culprit CL. + +Otherwise, you may need to [reproduce the bug](#Reproduce-the-bug) manually to +determine the impacted branches. + +If you have a bisection or other convincing evidence, that’s sufficient. You can +manually check which milestone has a given commit in +[ChromiumDash commits check](https://chromiumdash.appspot.com/commits). + +Please *do not* base FoundIn- on the Chrome version number provided in the +original report. This is often based on the version number the individual is +using when discovering this issue or is automatically set in the report by the +tracker’s report wizard and is not correct in terms of coverage of all active +release channels. + +For V8 bugs, you can set `FoundIn-<current extended stable>` unless you have +reproduced the issue or an accurate bisection has been provided. +(See [Assign, below](#Assign).) + +### Set impacted operating systems + +Set the `OS` field as best you can based on [these guidelines](security-labels.md#OS-Labels). +You do not need to reproduce the bug on each platform, but it really helps if +you set this field roughly right to ensure the bug has the attention of the +different desktop and mobile release teams. + +Some issues may be specific to a particular platform, if you need to reproduce a +bug that is platform specific and you do not have access to a device with that +OS, please [ask for help](#Ask-for-help), there is likely someone on the team +that does and can help you. + +ChromeOS is in a separate issue tracker. VRP reports for ChromeOS should be +[directly reported to ChromeOS](https://bughunters.google.com/report). Please +request the reporter submit direct to ChromeOS via that reporting route to +ensure it is received by the appropriate team. + +### Assign + +Security bugs are not automatically visible, so you must add people to get them +fixed. For each bug, set: + +* The **component** – due to a limited set of auto-cc rules, this may add some + visibility. +* An **assignee/owner**. Use `git blame` or look for similar past bugs in the + tracker. +* Lots of **cc**s. Copy everyone who could possibly be relevant. Use the owners + file for a particular feature to help achieve this. +* Add a **comment** so that recipients know what’s expected, and why you think + they’re the right person to take action. + * Be sure to convey if you have reproduced this issue and your determinations + about security relevance or diagnosis. + +It’s okay if you cannot determine or know the exact right assignee, but please +pass it along to / include someone who can direct it more precisely. + +*Some types of bugs have specific assignment needs:* * **V8 bugs**. First, [upload benign-looking test cases to ClusterFuzz](clusterfuzz-for-shepherds.md) if it isn't already there (please keep an eye out for any special flags and debug vs release). @@ -243,142 +346,6 @@ mfoltz@chromium.org. They are also working on holistic solutions to improving the security of fullscreen, so please remember to look for potential duplicates of ongoing work. - -Note that **even when you are handing off triage to another team or point of -contact**, it is your responsibility to ensure that the `Security_Severity` and -`FoundIn` fields are set as soon as possible (and definitely before the end of -your shepherding shift). Work with your point of contact to set these. For -instance, you may want to set initial/provisional values for these fields and -ask them whether it matches their understanding. - -Tips for reproducing bugs: - -* Assume that test cases may be malicious. You should only reproduce bugs - on your local machine if you're completely certain that you understand - 100% of the test case. If not, use a disposable virtual machine. If you're - inside Google, a good way to do this is using - [Redshell](https://goto.google.com/redshell-for-chrome-shepherds). -* For any sort of a crash, CHECK/DCHECK or memory safety problem - [use ClusterFuzz](clusterfuzz-for-shepherds.md). As well as reproducing bugs, - ClusterFuzz will help you with lots of subsequent bisection and labelling - tasks. Currently ClusterFuzz cannot guard against malicious test cases, - so be just as paranoid as if you were running a test case locally. -* [Instructions for using an Android emulator can be found - here](/docs/android_emulator.md). If you're inside Google, we have a - [guide for testing using Google infrastructure](https://goto.google.com/android-for-chrome-shepherds). -* When you can't just build from a specific branch locally, check out - [https://dev.chromium.org/getting-involved/dev-channel](https://dev.chromium.org/getting-involved/dev-channel) - or - [https://commondatastorage.googleapis.com/chromium-browser-asan/index.html](https://commondatastorage.googleapis.com/chromium-browser-asan/index.html) - for the latest release of a specific version. -* There are many tools available to help you reproduce various memory issues - reliably. If you aren't already familiar with them, check out - [AddressSanitizer](https://www.chromium.org/developers/testing/addresssanitizer), - [MemorySanitizer](https://www.chromium.org/developers/testing/memorysanitizer), - [ThreadSanitizer](https://www.chromium.org/developers/testing/threadsanitizer-tsan-v2), - and - [UndefinedBehaviorSanitizer](https://www.chromium.org/developers/testing/undefinedbehaviorsanitizer). -* The [get_asan_chrome](https://source.chromium.org/chromium/chromium/src/+/main:tools/get_asan_chrome/get_asan_chrome.py) - helper script is a handy way to download ASAN Chrome. The --help flag - provides usage instructions, e.g. to fetch builds for various versions and - platforms. -* If you run into issues with a reproducible ClusterFuzz test case (like - missing symbols, or if anything else seems off), try uploading the test case - again using a different job type with a more mature tool (e.g. ASan on Linux). - It may give more complete information. - -#### Step 2. Assess the severity. - -[See the severity guidelines](severity-guidelines.md). If it's a critical -vulnerability, act quick! We aim to get users patched in < 30 days. Remember -that if something requires an unusual configuration or complicated user -interaction, the severity rating should be lowered. - -Bug chains are typically composed of several individual security bugs and -should be split into a new bug for each potential fix required, so this allows -each team to work on fixing their part of the chain. In cases like this, leave -the main bug as the severity/priority of the full chain, and mark child bugs as -being blockers of the parent bug each with their own separate severity. Each -child bug can have its own priority. Examples of this in action are [issue -352369](https://crbug.com/352369) and [issue 453937](https://crbug.com/453937). - -Even after initial triage, re-assess the severity while you're looking at a -security bug update: does it have new information in the bug that could change -the assessment? Be especially on the lookout for Highs that are really -Criticals, and Lows that are really Mediums (make sure to account for process -types and sandbox boundaries). - -For V8 issues, it can be hard to identify the correct security severity. -Always set the severity to High unless there's strong evidence of an obvious -mitigation. Please add the `Security_Needs_Attention-Severity` label alongside -the regular `Security_Severity-*` label. If the bug is not exploitable, or is -mitigated, the V8 team will reduce the security severity (to avoid unnecessary -risk of merging the bug into stable branches). - -If an issue is found that can't affect any users running a default configuration -of Chrome (e.g. an issue in code guarded by a command-line flag that is off by -default), the `Security_Severity-*` label should still be set as if the issue -is affecting users running a default configuration of Chrome (but see the next -section about `FoundIn` and `Security_Impact-None`). - -#### Step 3. Set FoundIn - -Identify the earliest affected branch (Extended Stable, Stable, Beta or Head) -and set the corresponding `FoundIn` label (for example `FoundIn-66` if the -extended stable milestone is 66 and you've confirmed it's reproducible on M66). -If you reproduced the bug with ClusterFuzz, it should do this on your behalf. - -If you performed a bisection or were provided one with the commit that -introduced the problem, you can check which milestone has that commit by -navigating to https://chromiumdash.appspot.com/commit/COMMIT_HASH_HERE. - -Sometimes Extended Stable is the same milestone as Stable; sometimes it -differs. If in doubt about the currently active milestones, check -[ChromiumDash](https://chromiumdash.appspot.com/releases?platform=Windows). -(It's fine to just check the Windows platform, via that link - there's no need -to look at all the different platforms). There's no need to check for -reproducibility on milestones earlier than the current Stable milestone. - -If an issue is found that can't affect any users running a default configuration -of Chrome (e.g. an issue in code guarded by a command-line flag that is off by -default), then do not set the `FoundIn` label; instead, set the impact to -`Security_Impact-None` (but see -[here](security-labels.md#when-to-use-security_impact_none-toc_security_impact_none) -for additional nuances around using `Security_Impact-None`). - -#### Step 4. [Check other labels](security-labels.md). - -Much of Chrome's development and release process depends on bugs having the -right labels and components. Labels and components are vitally important for -merging the fix to the right releases, and ensuring reporters are credited -correctly. They also help with metrics and visibility. - -Labels to **double-check** (the first two should already be there if the bug -was filed using the Security template): - -* **Restrict-View-SecurityTeam** -* **Type-Bug-Security** -* If you want to prevent the bug from becoming unrestricted after it has been - closed, add **Restrict-View-SecurityEmbargo**. This should be done if the - reporter wishes to remain anonymous, if the description or comments contain - PII, or if the bug contains malware samples. -* **Security_Severity** - your responsibility as Shepherd. -* **FoundIn** - your responsibility as Shepherd. -* **reward_to** - if the bug was filed internally on behalf of somebody - external (for instance, a @chromium.org email reporting "I'm filing this on - behalf of" and the like). This is also very important; please check. - -You can expect Sheriffbot to fill in lots of other labels; for example, -the `M-` label to indicate the target milestone. It's best to allow -Sheriffbot to add the rest, as its rules have congealed from years of -accumulated security wisdom. See -[the Security Labels document](security-labels.md) for an explanation of what -the labels mean. - -**If you change anything, add a comment which explains any status -changes.** Severity, milestone, and priority assignment generally require -explanatory text. - * Report suspected malicious URLs to SafeBrowsing: * Public URLs: * [Report malware](https://safebrowsing.google.com/safebrowsing/report_badware/?hl=en) @@ -387,105 +354,181 @@ * Googlers: see instructions at [go/safebrowsing-escalation](https://goto.google.com/safebrowsing-escalation) * Report suspected malicious file attachments to SafeBrowsing. * Make sure the report is properly forwarded when the vulnerability is in an - upstream project, the OS, or some other dependency. + **upstream project**, the OS, or some other dependency. * For vulnerabilities in services Chrome uses (e.g. Omaha, Chrome Web Store, SafeBrowsing), make sure the affected team is informed and has access to the necessary bugs. +* Chrome for iOS - bugs suspected to be in **WebKit**: + * Reproduce using an iOS device or desktop Safari. + * Assign severity, impact, and component labels. + * If the issue is in Webkit + * Label `ExternalDependency` and `Hotlist-WebKit`. This label is monitored + by Apple. + * If reported by an external VRP reporter, request they report the issue + directly to Webkit and provide us the WebKit issue ID after they have done + so. + * If this is an internally discovered issue, file a security bug in the + Security product at [bugs.webkit.org](https://bugs.webkit.org) and + cc:chrome-ios-security-bugs@google.com. This alias is monitored by the iOS + Chrome team so they can be notified when the WebKit bug is fixed. + * Note the WebKit bug ID in the Chromium issue report. + * All security issues need owners, the WebKit ones can be assigned to ajuma@. -##### Labeling For Chrome On iOS +### Shift handoff -* Reproduce using iOS device or desktop Safari. -* Assign severity, impact, and component labels. -* If the issue is in WebKit: - * Label **ExternalDependency**. - * Label **Hotlist-WebKit**. This label is monitored by Apple friends. - * Do not fill **FoundIn**. It is applicable to Chrome versions and we can't - backmerge WebKit fixes. - * File a security bug at [bugs.webkit.org](https://bugs.webkit.org), and CC - chrome-ios-security-bugs@google.com. This alias is monitored by the iOS - Chrome team so they can be notified when the WebKit bug is fixed. Even - better: suggest the reporter to do it themselves and CC you. This way they - are getting a better visibility and credit. - * Note the WebKit bug ID in the crbug report. - * All security issues need owners, the WebKit ones can be assigned to ajuma@. +As you work through the queue each day, please manage your time and ensure you +have addressed all red rows and cells in the sheet to the best of your ability. +Make sure there are no red cells at the top of your sheet before the end of your +shift. It’s not okay to leave a backlog for the next oncoming security shepherd. -### Find An Owner To Fix The Bug +Please fill out the [Shepherding Handoff +Log](https://goto.google.com/chrome-security-shepherd-handoff) to communicate +issues from your shift that may be helpful to the oncoming shift. -That owner can be you! Otherwise, this is one of the more grey areas of -shepherding. With experience, you'll figure out good goto people for certain -areas. Until then, here are some tips. +### Ask for help -**Determine the correct component before continuing.** It's not enough on its -own, but it's a good starting point. Many components will automatically apply -some CCs who may be able to help you out. If it's a crash bug, see if -ClusterFuzz is able to provide one (will appear in the same card as the culprit -CL). You can also use `git hyper-blame` and check OWNERS files to see who might -own the relevant code. +Security bug triage is hard. We receive around 75 bug reports per week on +average. **If you are ever stuck or in doubt**, please ask for help from the +[Chrome Security Shepherds chat](https://goto.google.com/chrome-security-shepherds-chat) +or the [Chrome Security Chat](https://goto.google.com/chrome-security-chat). +During some shifts, there are just too many incoming bugs. It’s okay to ask for +help, please do! -**For crashes, check to see if ClusterFuzz provides a culprit CL.** Before you -assign a bug based on this, do a quick sanity check to ensure the CL could have -caused the bug. If the result seems wrong, apply the Test-Predator-Wrong label -to the bug and keep going. +You may also like the classic [HOWTO: Be a Security Shepherd deck](https://docs.google.com/presentation/d/1eISJXxyv7dUCGUKk_rvUI9t9s2xb98QY4d_-dZSa7Wg/edit#slide=id.p) -If you're able to narrow this to a specific regression range, usually from -ClusterFuzz for crash bugs, do a quick pass over the git log to see if any CLs -stand out. If you aren't sure, don't be afraid to add CCs to the bug and ask! +Because shepherding is fun. You like fun. Don't you? Fun is great. -At this point, you'll probably need to dive in and attempt to root cause the -bug, which is another complicated grey area that you'll figure out with -experience. Try not to spend too much time on this for any given bug, as some -cases will simply be too difficult without a deep understanding of certain -portions of the codebase. +## Secondary Shepherd -* If you can narrow the bug to a specific file or block of code, or if something - stands out as suspicious, try to assign an owner based on `git hyper-blame` or - add some CCs based on OWNERS files. -* If not, consider searching in the issue tracker for people that fixed similar - bugs or bugs in similar areas of the code base, such as issues with the same - components, recently. For example, let's say you were trying to figure out a - good person to assign a Content>Fonts issue. Look for `status=fixed,verified` - and query by when the issues were closed after (i.e. w/ in the last 30 days == - `closed>today-30`). +### Check in on triaged issues -Got stuck? Ask #chrome-security or someone from -[go/chrome-security-sheriff-mentors](https://goto.google.com/chrome-security-sheriff-mentors) -for help! That's why we're here. Don't be afraid to do this! +Review open security bug reports and check that progress is occurring. This does +not apply to the new bug reports as these are handled by the primary shepherd. +The rule of thumb is *if there is any red cell on the dashboard, it needs your +attention*: that especially includes the `last updated` column. Our [severity +guidelines](severity-guidelines.md) contain the expected duration for shipping +fixes, but it’s important to remember that to get a fix to all users in 60 days +or so, this may require us to land a fix in a week or two. -Make sure that the person you assign to handle a bug is not OOO. And, generally, -explicitly CC more than one person on the bug, if possible, and preferably -people from more than one geographic region. (See the OWNERS file(s) that -affect(s) the relevant area of code.) +*Suggestions for cultivating progress on security bugs:* +* Don’t just add a comment to the bug as these can disappear into spam (though a + well-crafted, meaningful, actionable comment can be effective). +* Contact the owner via chat or email in addition to commenting on the bug (so + others on the bug can see an update is needed). +* cc: more relevant people +* Think about what you can do to unblock the bug. What would _you_ do next? + Perhaps you bring in a subject matter expert of some aspect of the bug that is + a particular sticking point or suggest a different approach to reproduce the + bug. Sometimes a security perspective can help shed light on a different way + forward. +* Are there old, open `Security_Impact-None` bugs in unlaunched features, where + the response has been that there are no plans to launch that feature? Perhaps + inquire as to if that code can be removed rather than keeping vulnerable code + production code base. (Removing code that is not being used is a win!) +* Consider if it is better for you to make meaningful steps forward on three + bugs versus simple pings on many bugs. -**Sometimes, finding an owner isn't enough to ensure that a bug will get -fixed.** Check the stale bug list on the security dashboard and try resolve -some of the problems that might be blocking these issues. If you get in touch -with a bug owner off of the issue tracker, be sure to have them update the bug -so that future shepherds are aware of the status. +You can’t possibly usher all bugs toward meaningful progress during your shift. +As a general rule, expect to spend a solid ten hours ushering bugs toward +progress during your shift. Use the `last updated` column to avoid duplicating +the work of the previous secondary. -> Q: Why isn’t setting the component alone good enough? -> -> A: CCs are critical because just assigning to a component is ineffective -> because the component’s team cannot see the issues unless they have the -> Security View permissions. +### Handle incoming security emails -### Using The Permission API Kill Switch +Ensure that all incoming inquiries to the [security@chromium.org](https://groups.google.com/a/chromium.org/forum/#!forum/security), +[security-dev@chromium.org](https://groups.google.com/a/chromium.org/forum/#!forum/security-dev), +and +[chrome-security@google.com](https://groups.google.com/a/google.com/forum/#!forum/chrome-security) +lists get a reply (by someone; not necessarily you). See +[go/chrome-security-emails](https://goto.google.com/chrome-security-emails) +for a dashboard. -If you find a vulnerability in a Permission API and need to use the Global -Permissions Kill Switch, then follow [the -instructions](https://docs.google.com/document/d/17JeYt3c1GgghYoxy4NKJnlxrteAX8F4x-MAzTeXqP4U) +* When triaging an email to be handled off of the list, make sure to bcc: the +list that it arrived on, so that others (including future secondary shepherds) +can see that it has been handled. +* Some of these emails are requests for the inclusion of third-party code. +By the time you do shift handoff, please ensure these are either completed or +have been acknowledged by some other owner. If not, you may need to do them +yourself. + * Please see [How to do Chrome Third-Party Security Reviews](https://goto.google.com/how-to-do-chrome-third-party-security-reviews) for tips. -### Vulnerabilities in Chromium's dependencies +## Other Helpful Info -If you are handling a bug in one of Chromium's dependencies, see -[go/howto-investigate-autovm-chromium-bugs](https://goto.google.com/howto-investigate-autovm-chromium-bugs) -(Google-only, sorry) for some hints. +### What do all these bug labels mean? -### Wrapping Up The Fixed Issue +[Security Labels](security-labels.md). -1. Check with the developer that the issue can be closed as Fixed to allow - Sheriffbot to add the appropriate merge-review labels based on - Security_Severity and Security_Impact. +### A bug owner is asking for security input on backporting a fix on a security +bug I’ve shepherded. What do I do here? -## End Of Rotation +You are not responsible for handling merges or approving a fix for backmerge. +If the issue is resolved and there is a landed CL, please ensure the bug is +closed as Fixed. Please also make sure the bug has a severity and FoundIn set. +This will allow the bot (Sheriffbot) to add the appropriate merge review labels +(based on rules driven by severity and security_impact, derived from FoundIn). +See [security merge triage](../process/merge_request.md#Security-merge-triage) +for more information. -Update the [Shepherd Handoff Log](http://go/chrome-security-shepherd-handoff). +That issue will be visible to the security merge review queue. There are +designated members of the security team who have the hefty responsibility of +reviewing security issues for backmerge. Merge approvals will be handled by them +after at least the fix has had sufficient bake time on Canary. + +### When / how does X happen to a security bug? + +(e.g. how and when does a VRP bug get to the Chrome VRP Panel?) +[See Life of a Security Issue](life-of-a-security-issue.md). + +### I have questions related to Chrome VRP policy and scope. + +[Chrome VRP policies and rewards page](https://g.co/chrome/vrp). You can also +reach out directly to the Chrome VRP TL or ask questions in the +[Chrome Security Shepherds chat](http://go/chrome-security-shepherds-chat), all +VRP Panel members are also members of that chat. + +### There is PII or other data in this report we may not want to publicly +disclose (either now or in the future). + +For these cases, please add the `Restrict-View-SecurityEmbargo` label to the +report. For cases of PII that can’t be permanently deleted for the report, this +label should remain indefinitely. + +For cases in which we are just delaying public disclosure (such as when a +security issue impacts other products or vendors), please use this label and set +a next-action date so that disclosure can be re-evaluated at that time. + +### Protecting researcher identities + +Many researchers report security issues under a pseudonym and from a specific +email address pertaining to that pseudonym. Please do not refer to the +researcher by the email username directly in any comments of the report. +When reports are publicly disclosed, that becomes visible to all and we have to +delete those comments to protect that information. To direct a comment at an +external security researcher, please use “OP”, “reporter”, or "researcher”. + +### Shepherding Scheduling + +* [Current Shepherds](http://go/whos-the-shepherd) +* [Rotation schedule](https://docs.google.com/spreadsheets/d/10sLYZbi6QfLcXrhO-j5eSc82uc7NKnBz_o1pR9y8h7U/edit#gid=0) +* If you're a Shepherd, you should get a calendar invite. + Please accept it to acknowledge your upcoming shepherding duty. +* If you need to swap shifts, ask around for a volunteer and then just update + the [rotation sheet](https://docs.google.com/spreadsheets/d/10sLYZbi6QfLcXrhO-j5eSc82uc7NKnBz_o1pR9y8h7U/edit#gid=0) and wait 10 minutes for the calendar invites to be updated. + +### Incident response + +Sometimes you’ll need to handle a security emergency, such as a critical +severity bug or bug known or under active exploitation in the wild. In such +cases: +* As soon as possible, reach out the Shepherds chat for a Chrome Security + Incident Responder, so they can take on IR Commander responsibilities. +* Sometimes features can be switched off using feature flags – for example + [in permissions] ((https://docs.google.com/document/d/17JeYt3c1GgghYoxy4NKJnlxrteAX8F4x-MAzTeXqP4U). + Check with the engineer if that is a possibility in the case of this issue. + + +That's a lot of stuff! You have this resource and your peers to lean on +for questions and expertise. Hopefully this doc helps. +You're gonna do great! + +
diff --git a/extensions/browser/api/declarative_net_request/constants.cc b/extensions/browser/api/declarative_net_request/constants.cc index eb90b1a1..674acd8 100644 --- a/extensions/browser/api/declarative_net_request/constants.cc +++ b/extensions/browser/api/declarative_net_request/constants.cc
@@ -56,8 +56,10 @@ "\"resourceTypes\" key. It may only include the \"main_frame\" and " "\"sub_frame\" resource types."; const char kErrorRegexTooLarge[] = - "Rule with id * specified a more complex regex than allowed as part of the " - "\"*\" key."; + "Rule with id * was skipped as the \"*\" value exceeded the 2KB memory " + "limit when compiled. Learn more: " + "https://developer.chrome.com/docs/extensions/reference/api/" + "declarativeNetRequest#regex-rules"; const char kErrorNoHeaderListsSpecified[] = "Rule with id * does not specify a value for \"*\" or \"*\" key. At least " "one of these keys must be specified with a non-empty list.";
diff --git a/extensions/browser/api/declarative_net_request/constants.h b/extensions/browser/api/declarative_net_request/constants.h index cbe2f5d..b0ab7fff 100644 --- a/extensions/browser/api/declarative_net_request/constants.h +++ b/extensions/browser/api/declarative_net_request/constants.h
@@ -264,6 +264,10 @@ // The per-extension maximum amount of disabled static rules. inline constexpr int kMaxDisabledStaticRules = 5000; +// Maximum size of a compiled RegEx rule in KB. Limited to 2 KB which means +// that given 1024 rules, the total usage would be 2 MB. +inline constexpr int kRegexMaxMemKb = 2; + // Identifier for a Flatbuffer containing `flat::EmbedderConditions` as the // root. extern const char kEmbedderConditionsBufferIdentifier[];
diff --git a/extensions/browser/api/declarative_net_request/utils.cc b/extensions/browser/api/declarative_net_request/utils.cc index 7363570..87320283 100644 --- a/extensions/browser/api/declarative_net_request/utils.cc +++ b/extensions/browser/api/declarative_net_request/utils.cc
@@ -317,9 +317,8 @@ options.set_log_errors(false); - // Limit the maximum memory per regex to 2 Kb. This means given 1024 rules, - // the total usage would be 2 Mb. - options.set_max_mem(2 << 10); + // Limit the maximum memory per regex. + options.set_max_mem(kRegexMaxMemKb << 10); return options; }
diff --git a/extensions/components/native_app_window/native_app_window_views.cc b/extensions/components/native_app_window/native_app_window_views.cc index 00087f2..40b1543 100644 --- a/extensions/components/native_app_window/native_app_window_views.cc +++ b/extensions/components/native_app_window/native_app_window_views.cc
@@ -397,7 +397,7 @@ } bool NativeAppWindowViews::CanHaveAlphaEnabled() const { - return widget_->IsTranslucentWindowOpacitySupported(); + return views::Widget::IsWindowCompositingSupported(); } void NativeAppWindowViews::SetVisibleOnAllWorkspaces(bool always_visible) {
diff --git a/fuchsia_web/runners/cast/cast_runner.cml b/fuchsia_web/runners/cast/cast_runner.cml index f29f9a5b..59946c3e 100644 --- a/fuchsia_web/runners/cast/cast_runner.cml +++ b/fuchsia_web/runners/cast/cast_runner.cml
@@ -66,7 +66,7 @@ { directory: "tzdata-icu", rights: [ "r*" ], - path: "/config/tzdata", + path: "/config/tzdata/icu", }, { // Capabilities used by the Runner itself.
diff --git a/fuchsia_web/runners/cast/cast_runner_integration_test.shard.test-cml b/fuchsia_web/runners/cast/cast_runner_integration_test.shard.test-cml index 0db1f458..81ac1c3 100644 --- a/fuchsia_web/runners/cast/cast_runner_integration_test.shard.test-cml +++ b/fuchsia_web/runners/cast/cast_runner_integration_test.shard.test-cml
@@ -5,7 +5,7 @@ offer: [ { directory: [ - "config-data", + "config-data", "tzdata-icu", ], from: "parent",
diff --git a/fuchsia_web/webengine/browser/frame_permission_controller.cc b/fuchsia_web/webengine/browser/frame_permission_controller.cc index 5d0c4e7f..b4d5a30f 100644 --- a/fuchsia_web/webengine/browser/frame_permission_controller.cc +++ b/fuchsia_web/webengine/browser/frame_permission_controller.cc
@@ -114,7 +114,6 @@ void FramePermissionController::RequestPermissions( const std::vector<PermissionType>& permissions, const url::Origin& requesting_origin, - bool user_gesture, base::OnceCallback<void(const std::vector<PermissionStatus>&)> callback) { std::vector<PermissionStatus> result; result.reserve(permissions.size());
diff --git a/fuchsia_web/webengine/browser/frame_permission_controller.h b/fuchsia_web/webengine/browser/frame_permission_controller.h index 3e89cce8..8280cfad 100644 --- a/fuchsia_web/webengine/browser/frame_permission_controller.h +++ b/fuchsia_web/webengine/browser/frame_permission_controller.h
@@ -61,7 +61,6 @@ void RequestPermissions( const std::vector<blink::PermissionType>& permissions, const url::Origin& requesting_origin, - bool user_gesture, base::OnceCallback< void(const std::vector<blink::mojom::PermissionStatus>&)> callback);
diff --git a/fuchsia_web/webengine/browser/web_engine_permission_delegate.cc b/fuchsia_web/webengine/browser/web_engine_permission_delegate.cc index e3a60fe..7541de8cb 100644 --- a/fuchsia_web/webengine/browser/web_engine_permission_delegate.cc +++ b/fuchsia_web/webengine/browser/web_engine_permission_delegate.cc
@@ -28,7 +28,7 @@ frame->permission_controller()->RequestPermissions( request_description.permissions, url::Origin::Create(request_description.requesting_origin), - request_description.user_gesture, std::move(callback)); + std::move(callback)); } void WebEnginePermissionDelegate::ResetPermission( @@ -50,7 +50,7 @@ frame->permission_controller()->RequestPermissions( request_description.permissions, render_frame_host->GetLastCommittedOrigin(), - request_description.user_gesture, std::move(callback)); + std::move(callback)); } blink::mojom::PermissionStatus WebEnginePermissionDelegate::GetPermissionStatus(
diff --git a/infra/config/generated/builders/try/lacros-amd64-generic-rel-compilator/properties.json b/infra/config/generated/builders/try/lacros-amd64-generic-rel-compilator/properties.json index 26e70ba9..f9b70e39 100644 --- a/infra/config/generated/builders/try/lacros-amd64-generic-rel-compilator/properties.json +++ b/infra/config/generated/builders/try/lacros-amd64-generic-rel-compilator/properties.json
@@ -52,10 +52,6 @@ ] } }, - "$build/flakiness": { - "check_for_flakiness": true, - "check_for_flakiness_with_resultdb": true - }, "$build/reclient": { "instance": "rbe-chromium-untrusted", "jobs": 500,
diff --git a/infra/config/generated/builders/try/lacros-amd64-generic-rel/properties.json b/infra/config/generated/builders/try/lacros-amd64-generic-rel/properties.json index 93d9d96..2dde72b5 100644 --- a/infra/config/generated/builders/try/lacros-amd64-generic-rel/properties.json +++ b/infra/config/generated/builders/try/lacros-amd64-generic-rel/properties.json
@@ -56,10 +56,6 @@ ] } }, - "$build/flakiness": { - "check_for_flakiness": true, - "check_for_flakiness_with_resultdb": true - }, "$recipe_engine/resultdb/test_presentation": { "column_keys": [], "grouping_keys": [ @@ -68,6 +64,5 @@ ] }, "builder_group": "tryserver.chromium.chromiumos", - "cq": "required", "recipe": "chromium/orchestrator" } \ No newline at end of file
diff --git a/infra/config/generated/cq-builders.md b/infra/config/generated/cq-builders.md index 22f12a6..9d028f7 100644 --- a/infra/config/generated/cq-builders.md +++ b/infra/config/generated/cq-builders.md
@@ -49,8 +49,6 @@ * [ios-simulator](https://ci.chromium.org/p/chromium/builders/try/ios-simulator) ([definition](https://cs.chromium.org/search?q=+file:/try/.*\.star$+""ios-simulator"")) -* [lacros-amd64-generic-rel](https://ci.chromium.org/p/chromium/builders/try/lacros-amd64-generic-rel) ([definition](https://cs.chromium.org/search?q=+file:/try/.*\.star$+""lacros-amd64-generic-rel"")) - * [lacros-arm-generic-rel](https://ci.chromium.org/p/chromium/builders/try/lacros-arm-generic-rel) ([definition](https://cs.chromium.org/search?q=+file:/try/.*\.star$+""lacros-arm-generic-rel"")) * [linux-chromeos-compile-dbg](https://ci.chromium.org/p/chromium/builders/try/linux-chromeos-compile-dbg) ([definition](https://cs.chromium.org/search?q=+file:/try/.*\.star$+""linux-chromeos-compile-dbg""))
diff --git a/infra/config/generated/cq-usage/default.cfg b/infra/config/generated/cq-usage/default.cfg index 91c3df3b..03f39871 100644 --- a/infra/config/generated/cq-usage/default.cfg +++ b/infra/config/generated/cq-usage/default.cfg
@@ -62,9 +62,6 @@ name: "chromium/try/ios-simulator" } builders { - name: "chromium/try/lacros-amd64-generic-rel" - } - builders { name: "chromium/try/lacros-arm-generic-rel" } builders {
diff --git a/infra/config/generated/cq-usage/full.cfg b/infra/config/generated/cq-usage/full.cfg index 59391b9..e08f17d 100644 --- a/infra/config/generated/cq-usage/full.cfg +++ b/infra/config/generated/cq-usage/full.cfg
@@ -1752,26 +1752,6 @@ } } builders { - name: "chromium/try/lacros-amd64-generic-rel" - location_filters { - gerrit_host_regexp: ".*" - gerrit_project_regexp: ".*" - path_regexp: "docs/.+" - exclude: true - } - location_filters { - gerrit_host_regexp: ".*" - gerrit_project_regexp: ".*" - path_regexp: "infra/config/.+" - exclude: true - } - location_filters { - gerrit_host_regexp: ".*" - gerrit_project_regexp: ".*" - path_regexp: "infra/config/generated/builders/try/lacros-amd64-generic-rel/.+" - } - } - builders { name: "chromium/try/lacros-arm-generic-rel" location_filters { gerrit_host_regexp: ".*"
diff --git a/infra/config/generated/luci/commit-queue.cfg b/infra/config/generated/luci/commit-queue.cfg index 7e60353..60b0ab5 100644 --- a/infra/config/generated/luci/commit-queue.cfg +++ b/infra/config/generated/luci/commit-queue.cfg
@@ -3085,25 +3085,7 @@ } builders { name: "chromium/try/lacros-amd64-generic-rel" - location_filters { - gerrit_host_regexp: ".*" - gerrit_project_regexp: ".*" - path_regexp: "docs/.+" - exclude: true - } - location_filters { - gerrit_host_regexp: ".*" - gerrit_project_regexp: ".*" - path_regexp: "infra/config/.+" - exclude: true - } - location_filters { - gerrit_host_regexp: ".*" - gerrit_project_regexp: ".*" - path_regexp: "infra/config/generated/builders/try/lacros-amd64-generic-rel/.+" - } - mode_allowlist: "DRY_RUN" - mode_allowlist: "FULL_RUN" + includable_only: true } builders { name: "chromium/try/lacros-amd64-generic-rel-compilator"
diff --git a/infra/config/generated/luci/cr-buildbucket.cfg b/infra/config/generated/luci/cr-buildbucket.cfg index a98ad24..11758f7 100644 --- a/infra/config/generated/luci/cr-buildbucket.cfg +++ b/infra/config/generated/luci/cr-buildbucket.cfg
@@ -18742,7 +18742,7 @@ swarming_host: "chromium-swarm.appspot.com" dimensions: "builder:Mac Builder Next" dimensions: "cpu:arm64" - dimensions: "os:Mac-13" + dimensions: "os:Mac-14" dimensions: "pool:luci.chromium.ci" exe { cipd_package: "infra/chromium/bootstrapper/${platform}" @@ -82222,7 +82222,6 @@ ' }' ' },' ' "builder_group": "tryserver.chromium.chromiumos",' - ' "cq": "required",' ' "led_builder_is_bootstrapped": true,' ' "recipe": "chromium/orchestrator"' '}' @@ -93829,7 +93828,7 @@ swarming_host: "chromium-swarm.appspot.com" dimensions: "builder:mac-builder-next" dimensions: "cpu:arm64" - dimensions: "os:Mac-13" + dimensions: "os:Mac-14" dimensions: "pool:luci.chromium.try" dimensions: "ssd:1" exe {
diff --git a/infra/config/lib/builders.star b/infra/config/lib/builders.star index fc0e5a4..e0c9dde8 100644 --- a/infra/config/lib/builders.star +++ b/infra/config/lib/builders.star
@@ -83,6 +83,7 @@ MAC_14 = os_enum(os_category.MAC, "Mac-14"), MAC_DEFAULT = os_enum(os_category.MAC, "Mac-13"), MAC_ANY = os_enum(os_category.MAC, "Mac"), + MAC_BETA = os_enum(os_category.MAC, "Mac-14"), WINDOWS_10 = os_enum(os_category.WINDOWS, "Windows-10"), WINDOWS_11 = os_enum(os_category.WINDOWS, "Windows-11"), WINDOWS_DEFAULT = os_enum(os_category.WINDOWS, "Windows-10"),
diff --git a/infra/config/subprojects/chromium/ci/chromium.fyi.star b/infra/config/subprojects/chromium/ci/chromium.fyi.star index 341304b..e86f3d0 100644 --- a/infra/config/subprojects/chromium/ci/chromium.fyi.star +++ b/infra/config/subprojects/chromium/ci/chromium.fyi.star
@@ -2522,7 +2522,7 @@ ], ), cores = None, - os = os.MAC_13, + os = os.MAC_BETA, cpu = cpu.ARM64, console_view_entry = consoles.console_view_entry( category = "mac",
diff --git a/infra/config/subprojects/chromium/try/tryserver.chromium.chromiumos.star b/infra/config/subprojects/chromium/try/tryserver.chromium.chromiumos.star index b34c072..ce94d42f 100644 --- a/infra/config/subprojects/chromium/try/tryserver.chromium.chromiumos.star +++ b/infra/config/subprojects/chromium/try/tryserver.chromium.chromiumos.star
@@ -298,7 +298,6 @@ compilator = "lacros-amd64-generic-rel-compilator", contact_team_email = "chrome-desktop-engprod@google.com", main_list_view = "try", - tryjob = try_.job(), ) try_.compilator_builder(
diff --git a/infra/config/subprojects/chromium/try/tryserver.chromium.mac.star b/infra/config/subprojects/chromium/try/tryserver.chromium.mac.star index 7da31bb..ebdedcb 100644 --- a/infra/config/subprojects/chromium/try/tryserver.chromium.mac.star +++ b/infra/config/subprojects/chromium/try/tryserver.chromium.mac.star
@@ -119,7 +119,7 @@ mirrors = ["ci/Mac Builder Next"], gn_args = "ci/Mac Builder Next", builderless = False, - os = os.MAC_13, + os = os.MAC_BETA, cpu = cpu.ARM64, reclient_jobs = reclient.jobs.HIGH_JOBS_FOR_CQ, )
diff --git a/internal b/internal index 4baa1ab..7bc0f56 160000 --- a/internal +++ b/internal
@@ -1 +1 @@ -Subproject commit 4baa1abaa62ee7bde3412e8dbef614134978edab +Subproject commit 7bc0f561fe056c19918d9c9efef049525389066e
diff --git a/ios/chrome/app/strings/ios_strings.grd b/ios/chrome/app/strings/ios_strings.grd index bfcc7f1..9c6d2b7 100644 --- a/ios/chrome/app/strings/ios_strings.grd +++ b/ios/chrome/app/strings/ios_strings.grd
@@ -3258,10 +3258,10 @@ To stop others from using your password, open the <ph name="APP">$1<ex>Netflix</ex></ph> app to change your password </message> <message name="IDS_IOS_PASSWORD_SHARING_SUCCESS_SUBTITLE" desc="Subtitle text on the sharing status view when it succeeds describing that the recipient can now use the shared password. [iOS only]"> - <ph name="BEGIN_BOLD">BEGIN_BOLD</ph><ph name="USERNAME">$1<ex>johndoe</ex></ph><ph name="END_BOLD">END_BOLD</ph> can now use your username and password when they use Google Password Manager to sign in to <ph name="BEGIN_BOLD">BEGIN_BOLD</ph><ph name="WEBSITE">$2<ex>amazon.com</ex></ph><ph name="END_BOLD">END_BOLD</ph>. <ph name="BEGIN_LINK">BEGIN_LINK</ph>Learn more<ph name="END_LINK">END_LINK</ph> + <ph name="BEGIN_BOLD">BEGIN_BOLD</ph><ph name="USERNAME">$1<ex>johndoe</ex></ph><ph name="END_BOLD">END_BOLD</ph> can now use your username and password when they use Google Password Manager to sign in to <ph name="BEGIN_BOLD">BEGIN_BOLD</ph><ph name="WEBSITE">$2<ex>amazon.com</ex></ph><ph name="END_BOLD">END_BOLD</ph>. </message> <message name="IDS_IOS_PASSWORD_SHARING_SUCCESS_SUBTITLE_MULTIPLE_RECIPIENTS" desc="Subtitle text on the sharing status view when it succeeds describing that the recipient can now use the shared password. [iOS only]"> - Your family members can now use your username and password when they use Google Password Manager to sign in to <ph name="BEGIN_BOLD">BEGIN_BOLD</ph><ph name="WEBSITE">$1<ex>amazon.com</ex></ph><ph name="END_BOLD">END_BOLD</ph>. <ph name="BEGIN_LINK">BEGIN_LINK</ph>Learn more<ph name="END_LINK">END_LINK</ph> + Your family members can now use your username and password when they use Google Password Manager to sign in to <ph name="BEGIN_BOLD">BEGIN_BOLD</ph><ph name="WEBSITE">$1<ex>amazon.com</ex></ph><ph name="END_BOLD">END_BOLD</ph>. </message> <message name="IDS_IOS_PASSWORD_SHARING_SUCCESS_TITLE" desc="Title text on the sharing status view when it succeeded. [iOS only]"> Password Shared
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_PASSWORD_SHARING_SUCCESS_SUBTITLE.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_PASSWORD_SHARING_SUCCESS_SUBTITLE.png.sha1 index 164b3820..a5f2707 100644 --- a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_PASSWORD_SHARING_SUCCESS_SUBTITLE.png.sha1 +++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_PASSWORD_SHARING_SUCCESS_SUBTITLE.png.sha1
@@ -1 +1 @@ -7c96c422a707b02e20b426c9dee51cedd3087112 \ No newline at end of file +35c3acafc9c9173b0747eef6b7d906b1216a4b27 \ No newline at end of file
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_PASSWORD_SHARING_SUCCESS_SUBTITLE_MULTIPLE_RECIPIENTS.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_PASSWORD_SHARING_SUCCESS_SUBTITLE_MULTIPLE_RECIPIENTS.png.sha1 index 4d29693..c14ab9fa 100644 --- a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_PASSWORD_SHARING_SUCCESS_SUBTITLE_MULTIPLE_RECIPIENTS.png.sha1 +++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_PASSWORD_SHARING_SUCCESS_SUBTITLE_MULTIPLE_RECIPIENTS.png.sha1
@@ -1 +1 @@ -68938358a1758a083cfcc6a3449ec30fa8ade495 \ No newline at end of file +9fd8e05a6ba776106da214426b6387509baa9fe6 \ No newline at end of file
diff --git a/ios/chrome/browser/flags/about_flags.mm b/ios/chrome/browser/flags/about_flags.mm index c448ed52..b1f1d83 100644 --- a/ios/chrome/browser/flags/about_flags.mm +++ b/ios/chrome/browser/flags/about_flags.mm
@@ -1405,10 +1405,6 @@ flag_descriptions::kAppStoreRatingLoosenedTriggersName, flag_descriptions::kAppStoreRatingLoosenedTriggersDescription, flags_ui::kOsIos, FEATURE_VALUE_TYPE(kAppStoreRatingLoosenedTriggers)}, - {"ios-password-auth-on-entry", - flag_descriptions::kIOSPasswordAuthOnEntryName, - flag_descriptions::kIOSPasswordAuthOnEntryDescription, flags_ui::kOsIos, - FEATURE_VALUE_TYPE(password_manager::features::kIOSPasswordAuthOnEntry)}, {"tab-resumption", flag_descriptions::kTabResumptionName, flag_descriptions::kTabResumptionDescription, flags_ui::kOsIos, FEATURE_WITH_PARAMS_VALUE_TYPE(kTabResumption,
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc index cf650d0..bb51eb9 100644 --- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc +++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
@@ -510,18 +510,11 @@ const char kIOSParcelTrackingDescription[] = "When enabled, the user will be able to track their packages."; -const char kIOSPasswordAuthOnEntryName[] = "Password Manager Auth on Entry"; -const char kIOSPasswordAuthOnEntryDescription[] = - "Requires Local Authentication before showing saved credentials in " - "the Password Manager Main Page. Ignored if 'Password Manager Auth on " - "Entry V2' is enabled."; - const char kIOSPasswordAuthOnEntryV2Name[] = "Password Manager Auth on Entry V2"; const char kIOSPasswordAuthOnEntryV2Description[] = "Requires Local Authentication before showing saved credentials in " - "Password Manager subpages. Supersedes `Password Manager Auth on Entry` if " - "enabled."; + "Password Manager subpages."; const char kIOSSaveToDriveName[] = "IOS Save to Drive"; const char kIOSSaveToDriveDescription[] =
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h index cc15f960..929aa8e 100644 --- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h +++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
@@ -438,11 +438,6 @@ extern const char kIOSParcelTrackingDescription[]; // Title and description for the flag to require Local Authentication before -// accessing the Password Manager Main Page. -extern const char kIOSPasswordAuthOnEntryName[]; -extern const char kIOSPasswordAuthOnEntryDescription[]; - -// Title and description for the flag to require Local Authentication before // accessing the any of the Password Manager surfaces. extern const char kIOSPasswordAuthOnEntryV2Name[]; extern const char kIOSPasswordAuthOnEntryV2Description[];
diff --git a/ios/chrome/browser/push_notification/model/BUILD.gn b/ios/chrome/browser/push_notification/model/BUILD.gn index d162cfc3..802db26 100644 --- a/ios/chrome/browser/push_notification/model/BUILD.gn +++ b/ios/chrome/browser/push_notification/model/BUILD.gn
@@ -101,6 +101,7 @@ "push_notification_account_context_manager+testing.h", "push_notification_account_context_manager_unittest.mm", "push_notification_client_manager_unittest.mm", + "push_notification_settings_util_unittest.mm", "push_notification_util+testing.h", "push_notification_util_unittest.mm", ] @@ -110,9 +111,16 @@ ":test_support", "//base", "//base/test:test_support", + "//components/commerce/core:pref_names", + "//components/prefs", + "//components/prefs:test_support", + "//ios/chrome/browser/push_notification/model:constants", "//ios/chrome/browser/shared/model/application_context", "//ios/chrome/browser/shared/model/browser_state", "//ios/chrome/browser/shared/model/browser_state:test_support", + "//ios/chrome/browser/shared/model/prefs:pref_names", + "//ios/chrome/browser/shared/public/features:features", + "//ios/chrome/browser/signin/model:fake_system_identity", "//ios/chrome/test:test_support", "//ios/web/public/test", "//testing/gtest",
diff --git a/ios/chrome/browser/push_notification/model/push_notification_settings_util.h b/ios/chrome/browser/push_notification/model/push_notification_settings_util.h index a0fc640..1a5ceede 100644 --- a/ios/chrome/browser/push_notification/model/push_notification_settings_util.h +++ b/ios/chrome/browser/push_notification/model/push_notification_settings_util.h
@@ -34,6 +34,11 @@ const std::string& gaia_id, PrefService* pref_service); +// Returns whether the push notification permission status is enabled for any +// client for mobile notifications. +BOOL IsMobileNotificationsEnabledForAnyClient(const std::string& gaia_id, + PrefService* pref_service); + // Returns whether the push notification client's, `client_id`, // permission status for mobile notifications is enabled or disabled for the // current user.
diff --git a/ios/chrome/browser/push_notification/model/push_notification_settings_util.mm b/ios/chrome/browser/push_notification/model/push_notification_settings_util.mm index 780ca37..fcc7674 100644 --- a/ios/chrome/browser/push_notification/model/push_notification_settings_util.mm +++ b/ios/chrome/browser/push_notification/model/push_notification_settings_util.mm
@@ -77,6 +77,18 @@ } } +BOOL IsMobileNotificationsEnabledForAnyClient(const std::string& gaia_id, + PrefService* pref_service) { + static std::vector<PushNotificationClientId> client_ids = + PushNotificationClientManager::GetClients(); + for (PushNotificationClientId client_id : client_ids) { + if (GetMobileNotificationPermissionStatusForClient(client_id, gaia_id)) { + return true; + } + } + return false; +} + BOOL GetMobileNotificationPermissionStatusForClient( PushNotificationClientId client_id, const std::string& gaia_id) {
diff --git a/ios/chrome/browser/push_notification/model/push_notification_settings_util_unittest.mm b/ios/chrome/browser/push_notification/model/push_notification_settings_util_unittest.mm new file mode 100644 index 0000000..16fe00e --- /dev/null +++ b/ios/chrome/browser/push_notification/model/push_notification_settings_util_unittest.mm
@@ -0,0 +1,189 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/chrome/browser/push_notification/model/push_notification_settings_util.h" + +#import "base/files/file_path.h" +#import "base/strings/sys_string_conversions.h" +#import "base/test/scoped_feature_list.h" +#import "components/commerce/core/pref_names.h" +#import "components/prefs/pref_service.h" +#import "components/prefs/scoped_user_pref_update.h" +#import "ios/chrome/browser/push_notification/model/constants.h" +#import "ios/chrome/browser/push_notification/model/push_notification_account_context_manager.h" +#import "ios/chrome/browser/push_notification/model/push_notification_client_id.h" +#import "ios/chrome/browser/push_notification/model/push_notification_client_manager.h" +#import "ios/chrome/browser/push_notification/model/push_notification_service.h" +#import "ios/chrome/browser/shared/model/application_context/application_context.h" +#import "ios/chrome/browser/shared/model/browser_state/browser_state_info_cache.h" +#import "ios/chrome/browser/shared/model/browser_state/chrome_browser_state.h" +#import "ios/chrome/browser/shared/model/browser_state/test_chrome_browser_state.h" +#import "ios/chrome/browser/shared/model/browser_state/test_chrome_browser_state_manager.h" +#import "ios/chrome/browser/shared/model/prefs/pref_names.h" +#import "ios/chrome/browser/shared/public/features/features.h" +#import "ios/chrome/browser/signin/model/fake_system_identity.h" +#import "ios/chrome/test/testing_application_context.h" +#import "ios/web/public/test/web_task_environment.h" +#import "testing/gtest/include/gtest/gtest.h" +#import "testing/gtest_mac.h" +#import "testing/platform_test.h" + +namespace push_notification_settings { + +class PushNotificationSettingsUtilTest : public PlatformTest { + public: + PushNotificationSettingsUtilTest() { + test_chrome_browser_state_ = TestChromeBrowserState::Builder().Build(); + pref_service_ = test_chrome_browser_state_.get()->GetPrefs(); + default_browser_state_file_path_ = + test_chrome_browser_state_->GetStatePath(); + test_manager_ = std::make_unique<TestChromeBrowserStateManager>( + std::move(test_chrome_browser_state_)); + TestingApplicationContext::GetGlobal()->SetChromeBrowserStateManager( + test_manager_.get()); + browser_state_info()->RemoveBrowserState(default_browser_state_file_path_); + manager_ = [[PushNotificationAccountContextManager alloc] + initWithChromeBrowserStateManager:test_manager_.get()]; + fake_id_ = [FakeSystemIdentity fakeIdentity1]; + // TODO(b/318863934): Remove flag when enabled by default. + feature_list_.InitWithFeatures({/*enabled=*/kContentPushNotifications}, + {/*disabled=*/}); + AddTestCasesToManager(manager_, browser_state_info(), + base::SysNSStringToUTF8(fake_id_.gaiaID), + default_browser_state_file_path_); + } + BrowserStateInfoCache* browser_state_info() const { + return GetApplicationContext() + ->GetChromeBrowserStateManager() + ->GetBrowserStateInfoCache(); + } + void TurnNotificationForKey(BOOL on, + const std::string key, + PrefService* pref_service) { + ScopedDictPrefUpdate update(pref_service, + prefs::kFeaturePushNotificationPermissions); + update->Set(key, on); + } + void TurnEmailNotifications(BOOL on, PrefService* pref_service) { + pref_service->SetBoolean(commerce::kPriceEmailNotificationsEnabled, on); + } + void AddTestCasesToManager(PushNotificationAccountContextManager* manager, + BrowserStateInfoCache* info_cache, + const std::string& gaia_id, + base::FilePath path) { + // Construct the BrowserStates with the given gaia id and add the gaia id + // into the AccountContextManager. + info_cache->AddBrowserState(path, gaia_id, std::u16string()); + [manager addAccount:gaia_id]; + } + + protected: + PrefService* pref_service_; + web::WebTaskEnvironment task_environment_; + FakeSystemIdentity* fake_id_; + PushNotificationAccountContextManager* manager_; + std::unique_ptr<ChromeBrowserState> test_chrome_browser_state_; + std::unique_ptr<ios::ChromeBrowserStateManager> test_manager_; + base::FilePath default_browser_state_file_path_; + base::test::ScopedFeatureList feature_list_; +}; + +#pragma mark - All Clients Test + +// Tests the overall permission state, which checks the notification state for +// all clients available on the device. This may include notification types +// other than push notifications. +// When 0 clients are enabled, the state is DISABLED. +// When `enabled` >= 1 AND `disabled` >= 1, the state is INDETERMINANT +// When `enabled` >=1 and `disabled` == 0, then state is ENABLED. +TEST_F(PushNotificationSettingsUtilTest, TestPermissionState) { + // Enable Notifications in random order. + ClientPermissionState state = GetNotificationPermissionState( + base::SysNSStringToUTF8(fake_id_.gaiaID), pref_service_); + EXPECT_EQ(ClientPermissionState::DISABLED, state); + TurnNotificationForKey(YES, kCommerceNotificationKey, pref_service_); + state = GetNotificationPermissionState( + base::SysNSStringToUTF8(fake_id_.gaiaID), pref_service_); + EXPECT_EQ(ClientPermissionState::INDETERMINANT, state); + TurnEmailNotifications(YES, pref_service_); + state = GetNotificationPermissionState( + base::SysNSStringToUTF8(fake_id_.gaiaID), pref_service_); + EXPECT_EQ(ClientPermissionState::INDETERMINANT, state); + TurnNotificationForKey(YES, kContentNotificationKey, pref_service_); + state = GetNotificationPermissionState( + base::SysNSStringToUTF8(fake_id_.gaiaID), pref_service_); + EXPECT_EQ(ClientPermissionState::ENABLED, state); + // Start disabling in a different order. + TurnNotificationForKey(NO, kContentNotificationKey, pref_service_); + state = GetNotificationPermissionState( + base::SysNSStringToUTF8(fake_id_.gaiaID), pref_service_); + EXPECT_EQ(ClientPermissionState::INDETERMINANT, state); + TurnNotificationForKey(NO, kCommerceNotificationKey, pref_service_); + state = GetNotificationPermissionState( + base::SysNSStringToUTF8(fake_id_.gaiaID), pref_service_); + EXPECT_EQ(ClientPermissionState::INDETERMINANT, state); + TurnEmailNotifications(NO, pref_service_); + state = GetNotificationPermissionState( + base::SysNSStringToUTF8(fake_id_.gaiaID), pref_service_); + EXPECT_EQ(ClientPermissionState::DISABLED, state); +} + +#pragma mark - Price Tracking Notification Tests + +TEST_F(PushNotificationSettingsUtilTest, + TestMobileNotificationsEnabledForCommerce) { + BOOL isMobileNotificationsEnabled = IsMobileNotificationsEnabledForAnyClient( + base::SysNSStringToUTF8(fake_id_.gaiaID), pref_service_); + EXPECT_FALSE(isMobileNotificationsEnabled); + TurnNotificationForKey(YES, kCommerceNotificationKey, pref_service_); + isMobileNotificationsEnabled = IsMobileNotificationsEnabledForAnyClient( + base::SysNSStringToUTF8(fake_id_.gaiaID), pref_service_); + EXPECT_TRUE(isMobileNotificationsEnabled); +} + +TEST_F(PushNotificationSettingsUtilTest, + TestGetClientPermissionStateForCommerce) { + ClientPermissionState state = GetClientPermissionState( + PushNotificationClientId::kCommerce, + base::SysNSStringToUTF8(fake_id_.gaiaID), pref_service_); + EXPECT_EQ(ClientPermissionState::DISABLED, state); + TurnNotificationForKey(YES, kCommerceNotificationKey, pref_service_); + state = GetClientPermissionState(PushNotificationClientId::kCommerce, + base::SysNSStringToUTF8(fake_id_.gaiaID), + pref_service_); + EXPECT_EQ(ClientPermissionState::INDETERMINANT, state); + TurnEmailNotifications(YES, pref_service_); + state = GetClientPermissionState(PushNotificationClientId::kCommerce, + base::SysNSStringToUTF8(fake_id_.gaiaID), + pref_service_); + EXPECT_EQ(ClientPermissionState::ENABLED, state); +} + +#pragma mark - Content Notification Tests + +TEST_F(PushNotificationSettingsUtilTest, + TestMobileNotificationsEnabledForContent) { + BOOL isMobileNotificationsEnabled = IsMobileNotificationsEnabledForAnyClient( + base::SysNSStringToUTF8(fake_id_.gaiaID), pref_service_); + EXPECT_FALSE(isMobileNotificationsEnabled); + TurnNotificationForKey(YES, kContentNotificationKey, pref_service_); + isMobileNotificationsEnabled = IsMobileNotificationsEnabledForAnyClient( + base::SysNSStringToUTF8(fake_id_.gaiaID), pref_service_); + EXPECT_TRUE(isMobileNotificationsEnabled); +} + +TEST_F(PushNotificationSettingsUtilTest, + TestGetClientPermissionStateForContent) { + ClientPermissionState state = GetClientPermissionState( + PushNotificationClientId::kContent, + base::SysNSStringToUTF8(fake_id_.gaiaID), pref_service_); + EXPECT_EQ(ClientPermissionState::DISABLED, state); + TurnNotificationForKey(YES, kContentNotificationKey, pref_service_); + state = GetClientPermissionState(PushNotificationClientId::kContent, + base::SysNSStringToUTF8(fake_id_.gaiaID), + pref_service_); + EXPECT_EQ(ClientPermissionState::ENABLED, state); +} + +} // namespace push_notification_settings
diff --git a/ios/chrome/browser/safe_browsing/model/safe_browsing_egtest.mm b/ios/chrome/browser/safe_browsing/model/safe_browsing_egtest.mm index fe255f8b..a20e59a 100644 --- a/ios/chrome/browser/safe_browsing/model/safe_browsing_egtest.mm +++ b/ios/chrome/browser/safe_browsing/model/safe_browsing_egtest.mm
@@ -613,7 +613,15 @@ // Tests that performing session restoration to a Safe Browsing warning page // preserves navigation history. -- (void)testRestoreToWarningPagePreservesHistory { +// TODO(crbug.com/1516583): Test is flaky on device. Re-enable the test. +#if !TARGET_OS_SIMULATOR +#define MAYBE_testRestoreToWarningPagePreservesHistory \ + FLAKY_testRestoreToWarningPagePreservesHistory +#else +#define MAYBE_testRestoreToWarningPagePreservesHistory \ + testRestoreToWarningPagePreservesHistory +#endif +- (void)MAYBE_testRestoreToWarningPagePreservesHistory { // Build up navigation history that consists of a safe URL, a warning page, // and another safe URL. [ChromeEarlGrey loadURL:_safeURL1];
diff --git a/ios/chrome/browser/ui/autofill/form_input_accessory/BUILD.gn b/ios/chrome/browser/ui/autofill/form_input_accessory/BUILD.gn index aa42291..2287f5e 100644 --- a/ios/chrome/browser/ui/autofill/form_input_accessory/BUILD.gn +++ b/ios/chrome/browser/ui/autofill/form_input_accessory/BUILD.gn
@@ -57,7 +57,6 @@ "//ios/chrome/browser/ui/autofill/manual_fill", "//ios/chrome/browser/ui/autofill/manual_fill:manual_fill_ui", "//ios/chrome/browser/ui/bubble", - "//ios/chrome/browser/ui/settings/password:features", "//ios/chrome/browser/ui/toolbar/public", "//ios/chrome/common:button_config", "//ios/chrome/common/ui/colors:colors",
diff --git a/ios/chrome/browser/ui/autofill/form_input_accessory/form_input_accessory_coordinator.mm b/ios/chrome/browser/ui/autofill/form_input_accessory/form_input_accessory_coordinator.mm index eac4ba6..d6e1113a 100644 --- a/ios/chrome/browser/ui/autofill/form_input_accessory/form_input_accessory_coordinator.mm +++ b/ios/chrome/browser/ui/autofill/form_input_accessory/form_input_accessory_coordinator.mm
@@ -57,7 +57,6 @@ #import "ios/chrome/browser/ui/autofill/manual_fill/manual_fill_password_coordinator.h" #import "ios/chrome/browser/ui/bubble/bubble_constants.h" #import "ios/chrome/browser/ui/bubble/bubble_view_controller_presenter.h" -#import "ios/chrome/browser/ui/settings/password/password_manager_ui_features.h" #import "ios/chrome/common/ui/reauthentication/reauthentication_module.h" #import "ios/chrome/grit/ios_branded_strings.h" #import "ios/chrome/grit/ios_strings.h" @@ -396,10 +395,7 @@ // authentication when entering the Password Manager. Resigning the first // responder here fixes the issue without removing the focus on the underlying // web view's field. See crbug.com/1494929. - if (password_manager::features::IsAuthOnEntryEnabled() || - password_manager::features::IsAuthOnEntryV2Enabled()) { [GetFirstResponder() resignFirstResponder]; - } UMA_HISTOGRAM_ENUMERATION( "PasswordManager.ManagePasswordsReferrer",
diff --git a/ios/chrome/browser/ui/ntp/feed_top_section/feed_top_section_mediator.mm b/ios/chrome/browser/ui/ntp/feed_top_section/feed_top_section_mediator.mm index 46cbc0a..577c54f 100644 --- a/ios/chrome/browser/ui/ntp/feed_top_section/feed_top_section_mediator.mm +++ b/ios/chrome/browser/ui/ntp/feed_top_section/feed_top_section_mediator.mm
@@ -4,10 +4,13 @@ #import "ios/chrome/browser/ui/ntp/feed_top_section/feed_top_section_mediator.h" +#import <UserNotifications/UserNotifications.h> + #import "base/feature_list.h" #import "base/metrics/histogram_functions.h" #import "base/metrics/user_metrics.h" #import "base/metrics/user_metrics_action.h" +#import "base/strings/sys_string_conversions.h" #import "base/time/time.h" #import "components/prefs/pref_service.h" #import "components/signin/public/identity_manager/identity_manager.h" @@ -16,6 +19,7 @@ #import "ios/chrome/browser/push_notification/model/notifications_alert_presenter.h" #import "ios/chrome/browser/push_notification/model/push_notification_client_id.h" #import "ios/chrome/browser/push_notification/model/push_notification_service.h" +#import "ios/chrome/browser/push_notification/model/push_notification_settings_util.h" #import "ios/chrome/browser/push_notification/model/push_notification_util.h" #import "ios/chrome/browser/shared/model/application_context/application_context.h" #import "ios/chrome/browser/shared/model/prefs/pref_names.h" @@ -263,6 +267,32 @@ return self.identityManager->HasPrimaryAccount(consent); } +// Returns true if notifications are enabled in Chime or at the OS level. +- (BOOL)isNotificationsEnabled { + DCHECK([self isUserSignedIn]); + id<SystemIdentity> identity = self.authenticationService->GetPrimaryIdentity( + signin::ConsentLevel::kSignin); + // Check if user has notifications enabled at the Chime level. + BOOL isChimeEnabled = + push_notification_settings::IsMobileNotificationsEnabledForAnyClient( + base::SysNSStringToUTF8(identity.gaiaID), self.prefService); + if (isChimeEnabled) { + return true; + } + // Check the user's OS notification permission status for Chrome. + __block UNAuthorizationStatus status; + [PushNotificationUtil + getPermissionSettings:^(UNNotificationSettings* settings) { + status = settings.authorizationStatus; + }]; + + if (status != UNAuthorizationStatusNotDetermined && + status != UNAuthorizationStatusDenied) { + return true; + } + return false; +} + // TODO(b/315161586): Disable notifications promo if DSE changes. - (BOOL)shouldShowNotificationsPromo { // Check feature flag. @@ -280,6 +310,11 @@ return true; } + // Check if notifications are enabled of any type at the Chime level. + if ([self isNotificationsEnabled]) { + return false; + } + int notificationsPromoTimesShown = self.prefService->GetInteger(prefs::kNotificationsPromoTimesShown); int notificationsPromoTimesDismissed =
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_view_controller.mm b/ios/chrome/browser/ui/ntp/new_tab_page_view_controller.mm index 1c85800..845909b 100644 --- a/ios/chrome/browser/ui/ntp/new_tab_page_view_controller.mm +++ b/ios/chrome/browser/ui/ntp/new_tab_page_view_controller.mm
@@ -462,10 +462,6 @@ _feedContainer.translatesAutoresizingMaskIntoConstraints = NO; _feedContainer.backgroundColor = [UIColor colorNamed:kBackgroundColor]; - // Reduce the zPosition so that the container appears behind the feed - // content. - _feedContainer.layer.zPosition = -1; - // Add corner radius to the top border. _feedContainer.clipsToBounds = YES; _feedContainer.layer.cornerRadius = kHomeModuleContainerCornerRadius;
diff --git a/ios/chrome/browser/ui/settings/password/password_details/password_details_coordinator.mm b/ios/chrome/browser/ui/settings/password/password_details/password_details_coordinator.mm index 1c88de3..0f208aa 100644 --- a/ios/chrome/browser/ui/settings/password/password_details/password_details_coordinator.mm +++ b/ios/chrome/browser/ui/settings/password/password_details/password_details_coordinator.mm
@@ -383,7 +383,7 @@ [self.passwordSharingFirstRunCoordinator stop]; self.passwordSharingFirstRunCoordinator = [[PasswordSharingFirstRunCoordinator alloc] - initWithBaseViewController:self.baseViewController + initWithBaseViewController:self.viewController browser:self.browser]; self.passwordSharingFirstRunCoordinator.delegate = self; [self.passwordSharingFirstRunCoordinator start]; @@ -459,7 +459,7 @@ // password details. [self dismissAlertCoordinator]; [self dismissActionSheetCoordinator]; - [self dismissPasswordSharingCoordinator]; + [self stopPasswordSharingCoordinator]; [self stopPasswordSharingFirstRunCoordinatorWithCompletion:nil]; } @@ -505,11 +505,6 @@ self.alertCoordinator = nil; } -- (void)dismissPasswordSharingCoordinator { - [_passwordSharingCoordinator stop]; - _passwordSharingCoordinator = nil; -} - // Starts reauthCoordinator. If Password Details was opened from outside the // Password Manager, Local Authentication is required. Once started // reauthCoordinator observes scene state changes and requires authentication
diff --git a/ios/chrome/browser/ui/settings/password/password_manager_egtest.mm b/ios/chrome/browser/ui/settings/password/password_manager_egtest.mm index 14bb2447..b4ab5f66 100644 --- a/ios/chrome/browser/ui/settings/password/password_manager_egtest.mm +++ b/ios/chrome/browser/ui/settings/password/password_manager_egtest.mm
@@ -714,16 +714,6 @@ (testOpenPasswordSettingsSubmenuWithFailedAuth)] || [self isRunningTest:@selector(testAddNewPasswordWithFailedAuth)]) { config.features_enabled.push_back( - password_manager::features::kIOSPasswordAuthOnEntry); - config.features_enabled.push_back( - password_manager::features::kIOSPasswordAuthOnEntryV2); - } - - if ([self isRunningTest:@selector - (testPasswordManagerVisitMetricWithoutAuthRequired)]) { - config.features_disabled.push_back( - password_manager::features::kIOSPasswordAuthOnEntry); - config.features_disabled.push_back( password_manager::features::kIOSPasswordAuthOnEntryV2); } @@ -755,8 +745,6 @@ password_manager::features:: kIOSPasswordSettingsBulkUploadLocalPasswords); config.features_disabled.push_back( - password_manager::features::kIOSPasswordAuthOnEntry); - config.features_disabled.push_back( password_manager::features::kIOSPasswordAuthOnEntryV2); } @@ -3368,9 +3356,6 @@ - (void)testSavePasswordsInAccountFlowAuthFailed { SavePasswordFormToProfileStore(@"password1", @"user1", @"https://example1.com"); - - [PasswordSettingsAppInterface mockReauthenticationModuleExpectedResult: - ReauthenticationResult::kFailure]; FakeSystemIdentity* fakeIdentity = [FakeSystemIdentity fakeIdentity1]; [SigninEarlGreyUI signinWithFakeIdentity:fakeIdentity enableSync:NO]; @@ -3386,6 +3371,9 @@ performAction:grey_tap()]; [ChromeEarlGreyUI waitForAppToIdle]; + [PasswordSettingsAppInterface mockReauthenticationModuleExpectedResult: + ReauthenticationResult::kFailure]; + // Tap on "Save in Account" (accept) button. [SaveInAccountConfirmationDialogButton() performAction:grey_tap()]; [ChromeEarlGreyUI waitForAppToIdle]; @@ -3399,8 +3387,6 @@ - (void)testSavePasswordsInAccountFlowNoAuthSetOnDevice { SavePasswordFormToProfileStore(@"password1", @"user1", @"https://example1.com"); - - [PasswordSettingsAppInterface mockReauthenticationModuleCanAttempt:NO]; FakeSystemIdentity* fakeIdentity = [FakeSystemIdentity fakeIdentity1]; [SigninEarlGreyUI signinWithFakeIdentity:fakeIdentity enableSync:NO]; @@ -3416,6 +3402,8 @@ performAction:grey_tap()]; [ChromeEarlGreyUI waitForAppToIdle]; + [PasswordSettingsAppInterface mockReauthenticationModuleCanAttempt:NO]; + // Tap on "Save in Account" (accept) button. [SaveInAccountConfirmationDialogButton() performAction:grey_tap()]; [ChromeEarlGreyUI waitForAppToIdle]; @@ -3575,16 +3563,6 @@ CheckPasswordManagerVisitMetricCount(0); } -// Tests that password manager visit histogram is recorded after opening -// password manager without authentication required. -- (void)testPasswordManagerVisitMetricWithoutAuthRequired { - OpenPasswordManager(); - - CheckPasswordManagerVisitMetricCount(1); - - CheckReauthenticationUIEventMetricTotalCount(0); -} - // Tests that the Password Manager is opened is search mode when opened from the // Search Passwords widget. - (void)testOpenSearchPasswordsWidget {
diff --git a/ios/chrome/browser/ui/settings/password/password_manager_ui_features.h b/ios/chrome/browser/ui/settings/password/password_manager_ui_features.h index c936970..8bc2064 100644 --- a/ios/chrome/browser/ui/settings/password/password_manager_ui_features.h +++ b/ios/chrome/browser/ui/settings/password/password_manager_ui_features.h
@@ -11,11 +11,6 @@ // components. namespace password_manager::features { -BASE_DECLARE_FEATURE(kIOSPasswordAuthOnEntry); - -// Helper function returning the status of `kIOSPasswordAuthOnEntry`. -bool IsAuthOnEntryEnabled(); - BASE_DECLARE_FEATURE(kIOSPasswordAuthOnEntryV2); // Helper function returning the status of `kIOSPasswordAuthOnEntry2`.
diff --git a/ios/chrome/browser/ui/settings/password/password_manager_ui_features.mm b/ios/chrome/browser/ui/settings/password/password_manager_ui_features.mm index e2453ec..ce4db27 100644 --- a/ios/chrome/browser/ui/settings/password/password_manager_ui_features.mm +++ b/ios/chrome/browser/ui/settings/password/password_manager_ui_features.mm
@@ -6,16 +6,6 @@ namespace password_manager::features { // When enabled, local authentication (Face ID, Touch ID or Passcode) is -// required to view saved credentials in the Password Manager Main Page. -BASE_FEATURE(kIOSPasswordAuthOnEntry, - "IOSPasswordAuthOnEntry", - base::FEATURE_ENABLED_BY_DEFAULT); - -bool IsAuthOnEntryEnabled() { - return base::FeatureList::IsEnabled(kIOSPasswordAuthOnEntry); -} - -// When enabled, local authentication (Face ID, Touch ID or Passcode) is // required to view saved credentials in all Password Manager Surfaces. BASE_FEATURE(kIOSPasswordAuthOnEntryV2, "IOSPasswordAuthOnEntryV2",
diff --git a/ios/chrome/browser/ui/settings/password/password_sharing/password_sharing_egtest.mm b/ios/chrome/browser/ui/settings/password/password_sharing/password_sharing_egtest.mm index 67ae84b0..f4f00bbf 100644 --- a/ios/chrome/browser/ui/settings/password/password_sharing/password_sharing_egtest.mm +++ b/ios/chrome/browser/ui/settings/password/password_sharing/password_sharing_egtest.mm
@@ -47,6 +47,16 @@ l10n_util::GetNSString(IDS_IOS_PASSWORD_SHARING_FIRST_RUN_TITLE)); } +// Matcher for the UITableView inside the Family Picker View. +id<GREYMatcher> FamilyPickerTableViewMatcher() { + return grey_accessibilityID(kFamilyPickerTableViewID); +} + +// Matcher for the Password Picker View. +id<GREYMatcher> PasswordPickerViewMatcher() { + return grey_accessibilityID(kPasswordPickerViewID); +} + } // namespace // Test case for the Password Sharing flow. @@ -124,7 +134,11 @@ } if ([self isRunningTest:@selector - (testFirstRunExperienceViewDismissedForAuthentication)]) { + (testFirstRunExperienceViewDismissedForAuthentication)] || + [self isRunningTest:@selector + (testPasswordPickerViewDismissedForAuthentication)] || + [self isRunningTest:@selector + (testFamilyPickerViewDismissedForAuthentication)]) { config.features_enabled.push_back( password_manager::features::kIOSPasswordAuthOnEntryV2); } @@ -287,8 +301,7 @@ selectElementWithMatcher:grey_accessibilityID(kPasswordShareButtonID)] performAction:grey_tap()]; - [[EarlGrey - selectElementWithMatcher:grey_accessibilityID(kPasswordPickerViewID)] + [[EarlGrey selectElementWithMatcher:PasswordPickerViewMatcher()] performAction:grey_swipeFastInDirection(kGREYDirectionDown)]; // Check that the current view is the password details view. @@ -528,8 +541,7 @@ performAction:grey_tap()]; // Scroll down to the last recipient (the ineligible ones are on the bottom). - [[EarlGrey - selectElementWithMatcher:grey_accessibilityID(kFamilyPickerTableViewID)] + [[EarlGrey selectElementWithMatcher:FamilyPickerTableViewMatcher()] performAction:grey_scrollToContentEdge(kGREYContentEdgeBottom)]; // Tap on the info button next to the ineligible recipient row. [[EarlGrey @@ -599,8 +611,7 @@ performAction:grey_tap()]; // Check that the current view is the family picker view. - [[EarlGrey - selectElementWithMatcher:grey_accessibilityID(kFamilyPickerTableViewID)] + [[EarlGrey selectElementWithMatcher:FamilyPickerTableViewMatcher()] assertWithMatcher:grey_notNil()]; // Tap the cancel button. @@ -613,8 +624,7 @@ [[EarlGrey selectElementWithMatcher:grey_accessibilityID(kPasswordShareButtonID)] performAction:grey_tap()]; - [[EarlGrey - selectElementWithMatcher:grey_accessibilityID(kFamilyPickerTableViewID)] + [[EarlGrey selectElementWithMatcher:FamilyPickerTableViewMatcher()] assertWithMatcher:grey_notNil()]; } @@ -664,9 +674,59 @@ // Background then foreground app so reauthentication UI is displayed. [[AppLaunchManager sharedManager] backgroundAndForegroundApp]; - // Check that first run experience is gone. + // Check that first run experience is gone and password details is visible. [[EarlGrey selectElementWithMatcher:PasswordSharingFirstRunMatcher()] assertWithMatcher:grey_nil()]; + + [[EarlGrey selectElementWithMatcher:grey_accessibilityID( + kPasswordDetailsViewControllerID)] + assertWithMatcher:grey_sufficientlyVisible()]; +} + +- (void)testFamilyPickerViewDismissedForAuthentication { + SignInAndEnableSync(); + [self saveExamplePasswordToProfileStoreAndOpenDetails]; + + [[EarlGrey + selectElementWithMatcher:grey_accessibilityID(kPasswordShareButtonID)] + performAction:grey_tap()]; + + [[EarlGrey selectElementWithMatcher:FamilyPickerTableViewMatcher()] + assertWithMatcher:grey_sufficientlyVisible()]; + + // Background then foreground app so reauthentication UI is displayed. + [[AppLaunchManager sharedManager] backgroundAndForegroundApp]; + + // Check that the family picker is gone and password details is visible. + [[EarlGrey selectElementWithMatcher:FamilyPickerTableViewMatcher()] + assertWithMatcher:grey_nil()]; + + [[EarlGrey selectElementWithMatcher:grey_accessibilityID( + kPasswordDetailsViewControllerID)] + assertWithMatcher:grey_sufficientlyVisible()]; +} + +- (void)testPasswordPickerViewDismissedForAuthentication { + SignInAndEnableSync(); + [self saveExamplePasswordsToProfileStoreAndOpenDetails]; + + [[EarlGrey + selectElementWithMatcher:grey_accessibilityID(kPasswordShareButtonID)] + performAction:grey_tap()]; + + [[EarlGrey selectElementWithMatcher:PasswordPickerViewMatcher()] + assertWithMatcher:grey_sufficientlyVisible()]; + + // Background then foreground app so reauthentication UI is displayed. + [[AppLaunchManager sharedManager] backgroundAndForegroundApp]; + + // Check that the password picker is gone and password details is visible. + [[EarlGrey selectElementWithMatcher:PasswordPickerViewMatcher()] + assertWithMatcher:grey_nil()]; + + [[EarlGrey selectElementWithMatcher:grey_accessibilityID( + kPasswordDetailsViewControllerID)] + assertWithMatcher:grey_sufficientlyVisible()]; } @end
diff --git a/ios/chrome/browser/ui/settings/password/password_sharing/sharing_status_coordinator.mm b/ios/chrome/browser/ui/settings/password/password_sharing/sharing_status_coordinator.mm index c884979..3eca2e2 100644 --- a/ios/chrome/browser/ui/settings/password/password_sharing/sharing_status_coordinator.mm +++ b/ios/chrome/browser/ui/settings/password/password_sharing/sharing_status_coordinator.mm
@@ -135,14 +135,6 @@ [self.delegate startPasswordSharing]; } -- (void)learnMoreLinkWasTapped { - LogPasswordSharingInteraction( - PasswordSharingInteraction::kSharingConfirmationLearnMoreClicked); - - [self openURLInNewTabAndCloseSettings:GURL(kPasswordSharingLearnMoreURL)]; - [self.delegate sharingStatusCoordinatorWasDismissed:self]; -} - - (void)changePasswordLinkWasTapped { CHECK(_changePasswordURL.has_value());
diff --git a/ios/chrome/browser/ui/settings/password/password_sharing/sharing_status_coordinator_unittest.mm b/ios/chrome/browser/ui/settings/password/password_sharing/sharing_status_coordinator_unittest.mm index 9a81ac6..60c49a7f 100644 --- a/ios/chrome/browser/ui/settings/password/password_sharing/sharing_status_coordinator_unittest.mm +++ b/ios/chrome/browser/ui/settings/password/password_sharing/sharing_status_coordinator_unittest.mm
@@ -56,24 +56,6 @@ id mock_application_settings_commands_handler_; }; -TEST_F(SharingStatusCoordinatorTest, OpensHelpCenterOnLearnMoreTap) { - base::HistogramTester histogram_tester; - - OCMExpect([mock_application_commands_handler_ - closeSettingsUIAndOpenURL:[OCMArg checkWithBlock:^BOOL( - OpenNewTabCommand* command) { - return command.URL == - GURL("https://support.google.com/chrome/?p=password_sharing"); - }]]); - [(id<SharingStatusViewControllerPresentationDelegate>) - coordinator_ learnMoreLinkWasTapped]; - EXPECT_OCMOCK_VERIFY(mock_application_commands_handler_); - - histogram_tester.ExpectUniqueSample( - "PasswordManager.PasswordSharingIOS.UserAction", - PasswordSharingInteraction::kSharingConfirmationLearnMoreClicked, 1); -} - TEST_F(SharingStatusCoordinatorTest, RedirectsToSiteOnChangePasswordURLTap) { base::HistogramTester histogram_tester;
diff --git a/ios/chrome/browser/ui/settings/password/password_sharing/sharing_status_view_controller.mm b/ios/chrome/browser/ui/settings/password/password_sharing/sharing_status_view_controller.mm index cf05651..6303fc8 100644 --- a/ios/chrome/browser/ui/settings/password/password_sharing/sharing_status_view_controller.mm +++ b/ios/chrome/browser/ui/settings/password/password_sharing/sharing_status_view_controller.mm
@@ -67,7 +67,6 @@ // Accessibility identifiers of text views with links. NSString* const kSharingStatusFooterId = @"SharingStatusViewFooter"; -NSString* const kSharingStatusSubtitleId = @"SharingStatusViewSubtitle"; } // namespace @@ -249,11 +248,7 @@ shouldInteractWithURL:(NSURL*)URL inRange:(NSRange)characterRange interaction:(UITextItemInteraction)interaction { - if (textView.accessibilityIdentifier == kSharingStatusSubtitleId) { - [self.delegate learnMoreLinkWasTapped]; - } else if (textView.accessibilityIdentifier == kSharingStatusFooterId) { - [self.delegate changePasswordLinkWasTapped]; - } + [self.delegate changePasswordLinkWasTapped]; return NO; } @@ -652,17 +647,14 @@ UITextView* subtitle = [self createTextView]; subtitle.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody]; subtitle.textColor = [UIColor colorNamed:kTextPrimaryColor]; - subtitle.accessibilityIdentifier = kSharingStatusSubtitleId; StringWithTags stringWithBolds = ParseStringWithTags(self.subtitleString, kBeginBoldTag, kEndBoldTag); - StringWithTags stringWithLinks = ParseStringWithLinks(stringWithBolds.string); - subtitle.text = stringWithLinks.string; + subtitle.text = stringWithBolds.string; for (const NSRange& range : stringWithBolds.ranges) { [self addBoldAttributeToTextView:subtitle range:range]; } - [self addLinkAttributeToTextView:subtitle range:stringWithLinks.ranges[0]]; return subtitle; }
diff --git a/ios/chrome/browser/ui/settings/password/password_sharing/sharing_status_view_controller_presentation_delegate.h b/ios/chrome/browser/ui/settings/password/password_sharing/sharing_status_view_controller_presentation_delegate.h index 7d243728..f4880d2 100644 --- a/ios/chrome/browser/ui/settings/password/password_sharing/sharing_status_view_controller_presentation_delegate.h +++ b/ios/chrome/browser/ui/settings/password/password_sharing/sharing_status_view_controller_presentation_delegate.h
@@ -18,9 +18,6 @@ // sharing coordinator. - (void)startPasswordSharing; -// Handles taps on the link to learn more about the password sharing feature. -- (void)learnMoreLinkWasTapped; - // Handles taps on the link to the site where the user can change the password // that was shared. - (void)changePasswordLinkWasTapped;
diff --git a/ios/chrome/browser/ui/settings/password/passwords_coordinator.mm b/ios/chrome/browser/ui/settings/password/passwords_coordinator.mm index 433c2cc..b7014af 100644 --- a/ios/chrome/browser/ui/settings/password/passwords_coordinator.mm +++ b/ios/chrome/browser/ui/settings/password/passwords_coordinator.mm
@@ -193,23 +193,16 @@ self.mediator.consumer = self.passwordsViewController; - BOOL startBlockedForReauth = - password_manager::features::IsAuthOnEntryEnabled() || - password_manager::features::IsAuthOnEntryV2Enabled(); // Disable animation when content will be blocked for reauth to prevent // flickering in navigation bar. [self.baseNavigationController pushViewController:self.passwordsViewController - animated:!startBlockedForReauth]; + animated:NO]; _visitsRecorder = [[IOSPasswordManagerVisitsRecorder alloc] initWithPasswordManagerSurface:password_manager::PasswordManagerSurface:: kPasswordList]; - if (startBlockedForReauth) { - [self startReauthCoordinatorWithAuthOnStart:YES]; - } else { - [_visitsRecorder maybeRecordVisitMetric]; - } + [self startReauthCoordinatorWithAuthOnStart:YES]; // Start a password check. [self checkSavedPasswords];
diff --git a/ios/chrome/browser/ui/settings/password/reauthentication/reauthentication_coordinator.mm b/ios/chrome/browser/ui/settings/password/reauthentication/reauthentication_coordinator.mm index 143ba7a..42d4d224 100644 --- a/ios/chrome/browser/ui/settings/password/reauthentication/reauthentication_coordinator.mm +++ b/ios/chrome/browser/ui/settings/password/reauthentication/reauthentication_coordinator.mm
@@ -268,8 +268,9 @@ UIViewController* presentedViewController = topViewController.presentedViewController; // Do not dismiss the Search Controller, otherwise pushViewController does not - // add a the new view controller to the top of the navigation stack. - if (![presentedViewController isKindOfClass:[UISearchController class]]) { + // add the new view controller to the top of the navigation stack. + if (![presentedViewController isKindOfClass:[UISearchController class]] && + !presentedViewController.isBeingDismissed) { [presentedViewController.presentingViewController dismissViewControllerAnimated:NO completion:nil];
diff --git a/ios_internal b/ios_internal index 61b3244..ad7dea6 160000 --- a/ios_internal +++ b/ios_internal
@@ -1 +1 @@ -Subproject commit 61b32446e8a800b02f9bbaf7a2dc49b9d752b034 +Subproject commit ad7dea67e79c6d152370879b33caf38c79c7e160
diff --git a/media/base/android/media_drm_bridge_unittest.cc b/media/base/android/media_drm_bridge_unittest.cc index 5a4f4e2..0cdc6f8 100644 --- a/media/base/android/media_drm_bridge_unittest.cc +++ b/media/base/android/media_drm_bridge_unittest.cc
@@ -331,6 +331,8 @@ scoped_feature_list_.InitWithFeatures({media::kExternalClearKeyForTesting}, {}); + // TODO(b/263310318): Remove test skip when clear key is fixed and we call + // into MediaDrm for Android ClearKey instead of using AesDecryptor. if (!MediaDrmBridge::IsKeySystemSupported(kExternalClearKeyKeySystem)) { GTEST_SKIP() << "ClearKey not supported on device."; }
diff --git a/media/filters/BUILD.gn b/media/filters/BUILD.gn index d482ac9..ad30f58 100644 --- a/media/filters/BUILD.gn +++ b/media/filters/BUILD.gn
@@ -4,7 +4,6 @@ import("//media/gpu/args.gni") import("//media/media_options.gni") -import("//third_party/libgav1/options.gni") source_set("filters") { # Do not expand the visibility here without double-checking with OWNERS, this @@ -53,8 +52,6 @@ "offloading_video_decoder.h", "pipeline_controller.cc", "pipeline_controller.h", - "resolution_monitor.cc", - "resolution_monitor.h", "source_buffer_parse_warnings.h", "source_buffer_range.cc", "source_buffer_range.h", @@ -84,8 +81,6 @@ configs += [ "//media:subcomponent_config" ] - assert(use_libgav1_parser) - deps = [ "//base", "//build:chromeos_buildflags", @@ -94,9 +89,7 @@ "//media/base", "//media/cdm", "//media/formats", - "//media/parsers", "//media/video", - "//third_party/libgav1:libgav1_parser", "//third_party/libyuv", "//ui/gfx/geometry:geometry", ] @@ -327,7 +320,6 @@ "memory_data_source_unittest.cc", "offloading_video_decoder_unittest.cc", "pipeline_controller_unittest.cc", - "resolution_monitor_unittest.cc", "source_buffer_state_unittest.cc", "source_buffer_stream_unittest.cc", "stream_parser_factory_unittest.cc",
diff --git a/media/filters/resolution_monitor.h b/media/filters/resolution_monitor.h deleted file mode 100644 index 2175fc6..0000000 --- a/media/filters/resolution_monitor.h +++ /dev/null
@@ -1,35 +0,0 @@ -// Copyright 2023 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef MEDIA_FILTERS_RESOLUTION_MONITOR_H_ -#define MEDIA_FILTERS_RESOLUTION_MONITOR_H_ - -#include <memory> - -#include "base/sequence_checker.h" -#include "media/base/media_export.h" -#include "media/base/video_codecs.h" -#include "third_party/abseil-cpp/absl/types/optional.h" -#include "ui/gfx/geometry/size.h" - -namespace media { - -class DecoderBuffer; - -// Resolution monitor acquires a resolution of DecoderBuffer by parsing it. We -// can know the stream resolution before the first keyframe is decoded. This -// avoids requesting a sender to produce a keyframe again when a software -// decoder fallback due to a stream resolution happens. -class MEDIA_EXPORT ResolutionMonitor { - public: - virtual ~ResolutionMonitor(); - - static std::unique_ptr<ResolutionMonitor> Create(VideoCodec codec); - - virtual absl::optional<gfx::Size> GetResolution( - const DecoderBuffer& buffer) = 0; - virtual VideoCodec codec() const = 0; -}; -} // namespace media -#endif // MEDIA_FILTERS_RESOLUTION_MONITOR_H_
diff --git a/net/cookies/cookie_inclusion_status.cc b/net/cookies/cookie_inclusion_status.cc index 5be49154..d2c184d 100644 --- a/net/cookies/cookie_inclusion_status.cc +++ b/net/cookies/cookie_inclusion_status.cc
@@ -76,6 +76,9 @@ // If the cookie would be excluded for reasons other than the new SameSite // rules, don't bother warning about it. MaybeClearSameSiteWarning(); + // If the cookie would be excluded for reasons unrelated to 3pcd, don't bother + // warning about 3pcd. + MaybeClearThirdPartyPhaseoutReason(); } void CookieInclusionStatus::RemoveExclusionReason(ExclusionReason reason) { @@ -118,6 +121,19 @@ } } +void CookieInclusionStatus::MaybeClearThirdPartyPhaseoutReason() { + if (!IsInclude()) { + RemoveWarningReason(WARN_THIRD_PARTY_PHASEOUT); + } + if (ExclusionReasonsWithout( + {EXCLUDE_THIRD_PARTY_PHASEOUT, + EXCLUDE_THIRD_PARTY_BLOCKED_WITHIN_FIRST_PARTY_SET}) != 0u) { + // TODO(crbug.com/1516673): Once the bug is fixed, also remove + // EXCLUDE_THIRD_PARTY_BLOCKED_WITHIN_FIRST_PARTY_SET. + RemoveExclusionReason(EXCLUDE_THIRD_PARTY_PHASEOUT); + } +} + bool CookieInclusionStatus::ShouldRecordDowngradeMetrics() const { return ExclusionReasonsWithout({ EXCLUDE_SAMESITE_STRICT,
diff --git a/net/cookies/cookie_inclusion_status.h b/net/cookies/cookie_inclusion_status.h index fa6562e..98d8012 100644 --- a/net/cookies/cookie_inclusion_status.h +++ b/net/cookies/cookie_inclusion_status.h
@@ -392,6 +392,11 @@ ExclusionReasonBitset ExclusionReasonsWithout( const std::vector<ExclusionReason>& reasons) const; + // If the cookie would have been excluded by reasons that are not + // Third-party cookie phaseout related, clear the Third-party cookie phaseout + // warning/exclusion reason in this case. + void MaybeClearThirdPartyPhaseoutReason(); + // A bit vector of the applicable exclusion reasons. ExclusionReasonBitset exclusion_reasons_;
diff --git a/net/cookies/cookie_inclusion_status_unittest.cc b/net/cookies/cookie_inclusion_status_unittest.cc index 1281720..9378b456 100644 --- a/net/cookies/cookie_inclusion_status_unittest.cc +++ b/net/cookies/cookie_inclusion_status_unittest.cc
@@ -50,14 +50,80 @@ CookieInclusionStatus status_two_reasons = status_one_reason; status_two_reasons.AddExclusionReason(reason2); EXPECT_FALSE(status_two_reasons.IsInclude()); - EXPECT_TRUE(status_two_reasons.HasExclusionReason(reason1)); - EXPECT_TRUE(status_two_reasons.HasExclusionReason(reason2)); - EXPECT_FALSE(status_two_reasons.HasOnlyExclusionReason(reason1)); - EXPECT_FALSE(status_two_reasons.HasOnlyExclusionReason(reason2)); + + if (reason1 != CookieInclusionStatus::EXCLUDE_THIRD_PARTY_PHASEOUT && + reason2 != CookieInclusionStatus::EXCLUDE_THIRD_PARTY_PHASEOUT) { + EXPECT_TRUE(status_two_reasons.HasExclusionReason(reason1)); + EXPECT_TRUE(status_two_reasons.HasExclusionReason(reason2)); + } } } } +TEST(CookieInclusionStatusTest, + ExcludeStatus_MaybeClearThirdPartyPhaseoutReason) { + int num_exclusion_reasons = + static_cast<int>(CookieInclusionStatus::NUM_EXCLUSION_REASONS); + CookieInclusionStatus::ExclusionReason reason1 = + CookieInclusionStatus::EXCLUDE_THIRD_PARTY_PHASEOUT; + const CookieInclusionStatus status_one_reason(reason1); + ASSERT_FALSE(status_one_reason.IsInclude()); + ASSERT_TRUE(status_one_reason.HasOnlyExclusionReason(reason1)); + + for (int j = 0; j < num_exclusion_reasons; ++j) { + auto reason2 = static_cast<CookieInclusionStatus::ExclusionReason>(j); + if (reason1 == reason2) { + continue; + } + EXPECT_FALSE(status_one_reason.HasExclusionReason(reason2)) << reason2; + + CookieInclusionStatus status_two_reasons = status_one_reason; + status_two_reasons.AddExclusionReason(reason2); + EXPECT_FALSE(status_two_reasons.IsInclude()); + + if (reason2 == CookieInclusionStatus:: + EXCLUDE_THIRD_PARTY_BLOCKED_WITHIN_FIRST_PARTY_SET) { + EXPECT_TRUE(status_two_reasons.HasExclusionReason(reason1)); + EXPECT_TRUE(status_two_reasons.HasExclusionReason(reason2)); + } else { + EXPECT_TRUE(status_two_reasons.HasOnlyExclusionReason(reason2)); + } + } +} + +TEST(CookieInclusionStatusTest, + AddExclusionReason_MaybeClearThirdPartyPhaseoutReason) { + CookieInclusionStatus status; + status.AddWarningReason(CookieInclusionStatus::WARN_THIRD_PARTY_PHASEOUT); + ASSERT_TRUE(status.ShouldWarn()); + ASSERT_TRUE(status.HasExactlyWarningReasonsForTesting( + {CookieInclusionStatus::WARN_THIRD_PARTY_PHASEOUT})); + // Adding an exclusion reason should clear 3PCD warning reason. + status.AddExclusionReason( + CookieInclusionStatus::EXCLUDE_THIRD_PARTY_PHASEOUT); + EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_THIRD_PARTY_PHASEOUT})); + EXPECT_FALSE(status.ShouldWarn()); + + status.AddExclusionReason( + CookieInclusionStatus:: + EXCLUDE_THIRD_PARTY_BLOCKED_WITHIN_FIRST_PARTY_SET); + EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_THIRD_PARTY_PHASEOUT, + CookieInclusionStatus:: + EXCLUDE_THIRD_PARTY_BLOCKED_WITHIN_FIRST_PARTY_SET})); + // Adding an exclusion reason unrelated with 3PCD should clear 3PCD related + // exclusion reasons. + status.AddExclusionReason( + CookieInclusionStatus::EXCLUDE_SAMESITE_NONE_INSECURE); + EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_SAMESITE_NONE_INSECURE, + // TODO(crbug.com/1516673): This should also be removed. + CookieInclusionStatus:: + EXCLUDE_THIRD_PARTY_BLOCKED_WITHIN_FIRST_PARTY_SET})); + EXPECT_FALSE(status.IsInclude()); +} + TEST(CookieInclusionStatusTest, AddExclusionReason) { CookieInclusionStatus status; status.AddWarningReason(
diff --git a/net/quic/quic_stream_factory_test.cc b/net/quic/quic_stream_factory_test.cc index 3b53f58..894328ab 100644 --- a/net/quic/quic_stream_factory_test.cc +++ b/net/quic/quic_stream_factory_test.cc
@@ -3607,15 +3607,14 @@ if (migrate_idle_sessions) { quic_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING); // Hanging read. // A RESET will be sent to the peer to cancel the non-migratable stream. - quic_data1.AddWrite(SYNCHRONOUS, // 3 - client_maker_.MakeDataPacket( - packet_num++, GetQpackDecoderStreamId(), false, - StreamCancellationQpackDecoderInstruction(0))); + quic_data1.AddWrite(SYNCHRONOUS, + client_maker_.MakeDataAndRstPacket( + packet_num++, GetQpackDecoderStreamId(), + StreamCancellationQpackDecoderInstruction(0), + GetNthClientInitiatedBidirectionalStreamId(0), + quic::QUIC_STREAM_CANCELLED)); quic_data1.AddWrite( - SYNCHRONOUS, - client_maker_.MakeRetransmissionAndRstPacket( - 1, packet_num++, GetNthClientInitiatedBidirectionalStreamId(0), - quic::QUIC_STREAM_CANCELLED)); + SYNCHRONOUS, client_maker_.MakeRetransmissionPacket(1, packet_num++)); // Ping packet to send after migration is completed. quic_data1.AddWrite(SYNCHRONOUS, client_maker_.MakePingPacket(packet_num++)); @@ -3624,9 +3623,11 @@ } else { client_maker_.set_connection_id(cid_on_old_path); socket_data.AddWrite( - SYNCHRONOUS, client_maker_.MakeDataAckAndConnectionClosePacket( + SYNCHRONOUS, client_maker_.MakeDataRstAckAndConnectionClosePacket( packet_num++, GetQpackDecoderStreamId(), - StreamCancellationQpackDecoderInstruction(0), 1, 1, + StreamCancellationQpackDecoderInstruction(0), + GetNthClientInitiatedBidirectionalStreamId(0), + quic::QUIC_STREAM_CANCELLED, 1, 1, quic::QUIC_CONNECTION_MIGRATION_NO_MIGRATABLE_STREAMS, "net error", /*path_response_frame*/ 0x1b)); } @@ -7530,14 +7531,13 @@ quic_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING); // Hanging read. // A RESET will be sent to the peer to cancel the non-migratable stream. quic_data1.AddWrite(SYNCHRONOUS, - client_maker_.MakeDataPacket( - packet_num++, GetQpackDecoderStreamId(), false, - StreamCancellationQpackDecoderInstruction(0))); + client_maker_.MakeDataAndRstPacket( + packet_num++, GetQpackDecoderStreamId(), + StreamCancellationQpackDecoderInstruction(0), + GetNthClientInitiatedBidirectionalStreamId(0), + quic::QUIC_STREAM_CANCELLED)); quic_data1.AddWrite( - SYNCHRONOUS, - client_maker_.MakeRetransmissionAndRstPacket( - 1, packet_num++, GetNthClientInitiatedBidirectionalStreamId(0), - quic::QUIC_STREAM_CANCELLED)); + SYNCHRONOUS, client_maker_.MakeRetransmissionPacket(1, packet_num++)); // Ping packet to send after migration is completed. quic_data1.AddWrite(SYNCHRONOUS, client_maker_.MakePingPacket(packet_num++)); @@ -7546,9 +7546,11 @@ } else { client_maker_.set_connection_id(cid_on_old_path); socket_data.AddWrite( - SYNCHRONOUS, client_maker_.MakeDataAckAndConnectionClosePacket( + SYNCHRONOUS, client_maker_.MakeDataRstAckAndConnectionClosePacket( packet_num++, GetQpackDecoderStreamId(), - StreamCancellationQpackDecoderInstruction(0), 1, 1, + StreamCancellationQpackDecoderInstruction(0), + GetNthClientInitiatedBidirectionalStreamId(0), + quic::QUIC_STREAM_CANCELLED, 1, 1, quic::QUIC_CONNECTION_MIGRATION_NO_MIGRATABLE_STREAMS, "net error", /*path_response_frame*/ 0x1b)); }
diff --git a/net/quic/quic_test_packet_maker.cc b/net/quic/quic_test_packet_maker.cc index cd26252..2babf82 100644 --- a/net/quic/quic_test_packet_maker.cc +++ b/net/quic/quic_test_packet_maker.cc
@@ -527,8 +527,8 @@ InitializeHeader(num); AddQuicAckFrame(largest_received, smallest_received); - AddQuicStreamFrame(data_id, fin, data); AddQuicRstStreamFrame(stream_id, error_code); + AddQuicStreamFrame(data_id, fin, data); return BuildPacket(); }
diff --git a/net/third_party/quiche/BUILD.gn b/net/third_party/quiche/BUILD.gn index da18b98f..446ed54 100644 --- a/net/third_party/quiche/BUILD.gn +++ b/net/third_party/quiche/BUILD.gn
@@ -36,7 +36,6 @@ if (is_clang) { cflags += [ "-Wno-unused-private-field", - "-Wno-shadow", "-Wno-sign-compare", ] }
diff --git a/net/third_party/quiche/src b/net/third_party/quiche/src index 2789c40..b05cd0f 160000 --- a/net/third_party/quiche/src +++ b/net/third_party/quiche/src
@@ -1 +1 @@ -Subproject commit 2789c408aa2677e170a7f4f8a044e42a2f5c8bfe +Subproject commit b05cd0f90dcbfb962056ec04263452aa14120677
diff --git a/sandbox/policy/features.cc b/sandbox/policy/features.cc index b4c3d81..0f26ffe 100644 --- a/sandbox/policy/features.cc +++ b/sandbox/policy/features.cc
@@ -165,12 +165,12 @@ // Enables the renderer on Android to use a separate seccomp policy. BASE_FEATURE(kUseRendererProcessPolicy, "UseRendererProcessPolicy", - base::FEATURE_DISABLED_BY_DEFAULT); + base::FEATURE_ENABLED_BY_DEFAULT); // When enabled, this features restricts a set of syscalls in // BaselinePolicyAndroid that are used by RendererProcessPolicy. BASE_FEATURE(kRestrictRendererPoliciesInBaseline, "RestrictRendererPoliciesInBaseline", - base::FEATURE_DISABLED_BY_DEFAULT); + base::FEATURE_ENABLED_BY_DEFAULT); // When enabled, restrict clone to just flags used by fork and pthread_create on // android. BASE_FEATURE(kRestrictCloneParameters,
diff --git a/services/network/BUILD.gn b/services/network/BUILD.gn index a996cce..fd8cce9 100644 --- a/services/network/BUILD.gn +++ b/services/network/BUILD.gn
@@ -62,6 +62,8 @@ "ip_protection/ip_protection_config_cache.h", "ip_protection/ip_protection_config_cache_impl.cc", "ip_protection/ip_protection_config_cache_impl.h", + "ip_protection/ip_protection_proxy_delegate.cc", + "ip_protection/ip_protection_proxy_delegate.h", "ip_protection/ip_protection_proxy_list_manager.h", "ip_protection/ip_protection_proxy_list_manager_impl.cc", "ip_protection/ip_protection_proxy_list_manager_impl.h", @@ -429,6 +431,7 @@ "http_cache_data_remover_unittest.cc", "ignore_errors_cert_verifier_unittest.cc", "ip_protection/ip_protection_config_cache_impl_unittest.cc", + "ip_protection/ip_protection_proxy_delegate_unittest.cc", "ip_protection/ip_protection_proxy_list_manager_impl_unittest.cc", "ip_protection/ip_protection_token_cache_manager_impl_unittest.cc", "keepalive_statistics_recorder_unittest.cc",
diff --git a/services/network/ip_protection/ip_protection_proxy_delegate.cc b/services/network/ip_protection/ip_protection_proxy_delegate.cc new file mode 100644 index 0000000..4ccfe3bb8 --- /dev/null +++ b/services/network/ip_protection/ip_protection_proxy_delegate.cc
@@ -0,0 +1,199 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "services/network/ip_protection/ip_protection_proxy_delegate.h" + +#include "base/containers/contains.h" +#include "base/feature_list.h" +#include "base/functional/bind.h" +#include "base/memory/scoped_refptr.h" +#include "base/strings/strcat.h" +#include "net/base/features.h" +#include "net/base/proxy_chain.h" +#include "net/base/proxy_server.h" +#include "net/base/url_util.h" +#include "net/http/http_request_headers.h" +#include "net/http/http_util.h" +#include "net/proxy_resolution/proxy_info.h" +#include "net/proxy_resolution/proxy_resolution_service.h" +#include "services/network/masked_domain_list/network_service_proxy_allow_list.h" +#include "services/network/url_loader.h" +#include "url/url_constants.h" + +namespace network { + +IpProtectionProxyDelegate::IpProtectionProxyDelegate( + NetworkServiceProxyAllowList* network_service_proxy_allow_list) + : network_service_proxy_allow_list_(network_service_proxy_allow_list) {} + +IpProtectionProxyDelegate::~IpProtectionProxyDelegate() = default; + +void IpProtectionProxyDelegate::OnResolveProxy( + const GURL& url, + const net::NetworkAnonymizationKey& network_anonymization_key, + const std::string& method, + const net::ProxyRetryInfoMap& proxy_retry_info, + net::ProxyInfo* result) { + auto dvlog = [&](std::string message) { + absl::optional<net::SchemefulSite> top_frame_site = + network_anonymization_key.GetTopFrameSite(); + DVLOG(3) << "NSPD::OnResolveProxy(" << url << ", " + << (top_frame_site.has_value() ? top_frame_site.value() + : net::SchemefulSite()) + << ") - " << message; + }; + // Note: We do not proxy requests if: + // - The allow list is not available or is not enabled. + // - The request doesn't match the allow list. + // - The token cache is not available. + // - The token cache does not have tokens. + // - No proxy list is available. + // - `kEnableIpProtection` is `false`. + // - `kIpPrivacyDirectOnly` is `true`. + if (!network_service_proxy_allow_list_) { + dvlog("no proxy allow list"); + return; + } + if (!network_service_proxy_allow_list_->IsEnabled()) { + dvlog("proxy allow list not enabled"); + return; + } + if (!network_service_proxy_allow_list_->Matches(url, + network_anonymization_key)) { + dvlog("proxy allow list did not match"); + return; + } + result->set_is_mdl_match(true); + if (!base::FeatureList::IsEnabled(net::features::kEnableIpProtectionProxy)) { + dvlog("ip protection proxy not enabled"); + return; + } + if (!ipp_config_cache_) { + dvlog("no cache"); + return; + } + if (!ipp_config_cache_->AreAuthTokensAvailable()) { + dvlog("no auth token available from cache"); + return; + } + if (!ipp_config_cache_->IsProxyListAvailable()) { + // NOTE: When this `vlog()` is removed, there's no need to distinguish + // the case where a proxy list has not been downloaded, and the case + // where a proxy list is empty. The `IsProxyListAvailable()` method can + // be removed at that time. + dvlog("no proxy list available from cache"); + return; + } + + net::ProxyList proxy_list; + if (!net::features::kIpPrivacyDirectOnly.Get()) { + const std::vector<net::ProxyChain>& proxy_chain_list = + ipp_config_cache_->GetProxyChainList(); + for (const auto& proxy_chain : proxy_chain_list) { + if (proxy_chain.is_single_proxy() && url.SchemeIs(url::kHttpScheme)) { + // Proxying HTTP traffic correctly for IP Protection requires + // multi-proxy chains to be used, so if a single-proxy chain is + // encountered here then just fail. + // TODO(https://crbug.com/1474932): Once chains are guaranteed to be + // multi-proxy here, turn this into a CHECK. + dvlog("can't proxy HTTP URL through a single-proxy chain"); + return; + } + proxy_list.AddProxyChain(std::move(proxy_chain)); + } + } + // Final fallback is to DIRECT. + auto direct_proxy_chain = net::ProxyChain::Direct(); + if (net::features::kIpPrivacyDirectOnly.Get()) { + // To enable measuring how much traffic would be proxied (for + // experimentation and planning purposes), mark the direct + // proxy chain as being for IP Protection when `kIpPrivacyDirectOnly` is + // true. When it is false, we only care about traffic that actually went + // through the IP Protection proxies, so don't set this flag. + direct_proxy_chain = std::move(direct_proxy_chain).ForIpProtection(); + } + proxy_list.AddProxyChain(std::move(direct_proxy_chain)); + + if (VLOG_IS_ON(3)) { + dvlog(base::StrCat({"setting proxy list (before deprioritization) to ", + proxy_list.ToDebugString()})); + } + result->OverrideProxyList(MergeProxyRules(result->proxy_list(), proxy_list)); + result->DeprioritizeBadProxyChains(proxy_retry_info); + return; +} + +void IpProtectionProxyDelegate::OnFallback(const net::ProxyChain& bad_chain, + int net_error) { + // If the bad proxy was an IP Protection proxy, refresh the list of IP + // protection proxies immediately. + if (bad_chain.is_for_ip_protection()) { + CHECK(ipp_config_cache_); + ipp_config_cache_->RequestRefreshProxyList(); + } +} + +void IpProtectionProxyDelegate::OnBeforeTunnelRequest( + const net::ProxyChain& proxy_chain, + size_t chain_index, + net::HttpRequestHeaders* extra_headers) { + auto vlog = [](std::string message) { + VLOG(2) << "NSPD::OnBeforeTunnelRequest() - " << message; + }; + if (proxy_chain.is_for_ip_protection()) { + // Temporarily support a pre-shared key for access to proxyB. + if (chain_index == 1) { + std::string proxy_b_psk = net::features::kIpPrivacyProxyBPsk.Get(); + if (!proxy_b_psk.empty()) { + vlog("adding proxyB PSK"); + extra_headers->SetHeader(net::HttpRequestHeaders::kProxyAuthorization, + base::StrCat({"Preshared ", proxy_b_psk})); + } + } + CHECK(ipp_config_cache_); + absl::optional<network::mojom::BlindSignedAuthTokenPtr> token = + ipp_config_cache_->GetAuthToken(chain_index); + if (token) { + vlog("adding auth token"); + // The token value we have here is the full Authorization header value, so + // we can add it verbatim. + extra_headers->SetHeader(net::HttpRequestHeaders::kAuthorization, + std::move((*token)->token)); + } else { + vlog("no token available"); + } + } else { + vlog("not for IP protection"); + } +} + +net::Error IpProtectionProxyDelegate::OnTunnelHeadersReceived( + const net::ProxyChain& proxy_chain, + size_t chain_index, + const net::HttpResponseHeaders& response_headers) { + return net::OK; +} + +void IpProtectionProxyDelegate::SetProxyResolutionService( + net::ProxyResolutionService* proxy_resolution_service) {} + +net::ProxyList IpProtectionProxyDelegate::MergeProxyRules( + const net::ProxyList& existing_proxy_list, + const net::ProxyList& custom_proxy_list) const { + net::ProxyList merged_proxy_list; + for (const auto& existing_chain : existing_proxy_list.AllChains()) { + if (existing_chain.is_direct()) { + // Replace direct option with all proxies in the custom proxy list + for (const auto& custom_chain : custom_proxy_list.AllChains()) { + merged_proxy_list.AddProxyChain(custom_chain); + } + } else { + merged_proxy_list.AddProxyChain(existing_chain); + } + } + + return merged_proxy_list; +} + +} // namespace network
diff --git a/services/network/ip_protection/ip_protection_proxy_delegate.h b/services/network/ip_protection/ip_protection_proxy_delegate.h new file mode 100644 index 0000000..e7ee8ad --- /dev/null +++ b/services/network/ip_protection/ip_protection_proxy_delegate.h
@@ -0,0 +1,83 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef SERVICES_NETWORK_IP_PROTECTION_IP_PROTECTION_PROXY_DELEGATE_H_ +#define SERVICES_NETWORK_IP_PROTECTION_IP_PROTECTION_PROXY_DELEGATE_H_ + +#include <deque> + +#include "base/component_export.h" +#include "base/memory/raw_ptr.h" +#include "mojo/public/cpp/bindings/receiver.h" +#include "mojo/public/cpp/bindings/remote.h" +#include "net/base/proxy_delegate.h" +#include "services/network/ip_protection/ip_protection_config_cache.h" +#include "services/network/masked_domain_list/network_service_proxy_allow_list.h" +#include "services/network/public/mojom/network_context.mojom.h" + +namespace net { +class HttpRequestHeaders; +class ProxyResolutionService; +} // namespace net + +namespace network { + +// IpProtectionProxyDelegate is used to support IP protection, by injecting +// proxies for requests where IP should be protected. +class COMPONENT_EXPORT(NETWORK_SERVICE) IpProtectionProxyDelegate + : public net::ProxyDelegate { + public: + IpProtectionProxyDelegate( + NetworkServiceProxyAllowList* network_service_proxy_allow_list); + + IpProtectionProxyDelegate(const IpProtectionProxyDelegate&) = delete; + IpProtectionProxyDelegate& operator=(const IpProtectionProxyDelegate&) = + delete; + + ~IpProtectionProxyDelegate() override; + + void SetIpProtectionConfigCache( + std::unique_ptr<IpProtectionConfigCache> ipp_config_cache) { + ipp_config_cache_ = std::move(ipp_config_cache); + } + + // net::ProxyDelegate implementation: + void OnResolveProxy( + const GURL& url, + const net::NetworkAnonymizationKey& network_anonymization_key, + const std::string& method, + const net::ProxyRetryInfoMap& proxy_retry_info, + net::ProxyInfo* result) override; + void OnFallback(const net::ProxyChain& bad_chain, int net_error) override; + void OnBeforeTunnelRequest(const net::ProxyChain& proxy_chain, + size_t chain_index, + net::HttpRequestHeaders* extra_headers) override; + net::Error OnTunnelHeadersReceived( + const net::ProxyChain& proxy_chain, + size_t chain_index, + const net::HttpResponseHeaders& response_headers) override; + void SetProxyResolutionService( + net::ProxyResolutionService* proxy_resolution_service) override; + + IpProtectionConfigCache* GetIpProtectionConfigCache() { + return ipp_config_cache_.get(); + } + + private: + friend class IpProtectionProxyDelegateTest; + FRIEND_TEST_ALL_PREFIXES(IpProtectionProxyDelegateTest, MergeProxyRules); + + // Returns the equivalent of replacing all DIRECT proxies in + // `existing_proxy_list` with the proxies in `custom_proxy_list`. + net::ProxyList MergeProxyRules(const net::ProxyList& existing_proxy_list, + const net::ProxyList& custom_proxy_list) const; + + const raw_ptr<NetworkServiceProxyAllowList> network_service_proxy_allow_list_; + + std::unique_ptr<IpProtectionConfigCache> ipp_config_cache_; +}; + +} // namespace network + +#endif // SERVICES_NETWORK_IP_PROTECTION_IP_PROTECTION_PROXY_DELEGATE_H_
diff --git a/services/network/ip_protection/ip_protection_proxy_delegate_unittest.cc b/services/network/ip_protection/ip_protection_proxy_delegate_unittest.cc new file mode 100644 index 0000000..d537c29e --- /dev/null +++ b/services/network/ip_protection/ip_protection_proxy_delegate_unittest.cc
@@ -0,0 +1,725 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "services/network/ip_protection/ip_protection_proxy_delegate.h" + +#include <string> + +#include "base/memory/raw_ptr.h" +#include "base/memory/scoped_refptr.h" +#include "base/test/bind.h" +#include "base/test/scoped_feature_list.h" +#include "base/test/task_environment.h" +#include "mojo/public/cpp/bindings/remote.h" +#include "mojo/public/cpp/bindings/self_owned_receiver.h" +#include "net/base/network_anonymization_key.h" +#include "net/base/proxy_chain.h" +#include "net/base/proxy_string_util.h" +#include "net/proxy_resolution/proxy_info.h" +#include "net/traffic_annotation/network_traffic_annotation_test_helper.h" +#include "net/url_request/url_request_context.h" +#include "net/url_request/url_request_context_builder.h" +#include "net/url_request/url_request_test_util.h" +#include "services/network/ip_protection/ip_protection_config_cache_impl.h" +#include "services/network/ip_protection/ip_protection_proxy_list_manager.h" +#include "services/network/ip_protection/ip_protection_token_cache_manager.h" +#include "services/network/masked_domain_list/network_service_proxy_allow_list.h" +#include "services/network/public/cpp/features.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/abseil-cpp/absl/types/optional.h" + +namespace network { +namespace { + +constexpr char kHttpsUrl[] = "https://example.com"; +constexpr char kHttpUrl[] = "http://example.com"; +constexpr char kLocalhost[] = "http://localhost"; + +class MockIpProtectionConfigCache : public IpProtectionConfigCache { + public: + bool AreAuthTokensAvailable() override { return auth_token_.has_value(); } + void InvalidateTryAgainAfterTime() override {} + absl::optional<network::mojom::BlindSignedAuthTokenPtr> GetAuthToken( + size_t chain_index) override { + return std::move(auth_token_); + } + + // Set the auth token that will be returned from the next call to + // `GetAuthToken()`. + void SetNextAuthToken( + absl::optional<network::mojom::BlindSignedAuthTokenPtr> auth_token) { + auth_token_ = std::move(auth_token); + } + + void SetUp() override { NOTREACHED_NORETURN(); } + + void SetIpProtectionProxyListManagerForTesting( + std::unique_ptr<IpProtectionProxyListManager> ipp_proxy_list_manager) + override { + NOTREACHED_NORETURN(); + } + + IpProtectionTokenCacheManager* GetIpProtectionTokenCacheManagerForTesting( + network::mojom::IpProtectionProxyLayer proxy_layer) override { + NOTREACHED_NORETURN(); + } + + void SetIpProtectionTokenCacheManagerForTesting( + network::mojom::IpProtectionProxyLayer proxy_layer, + std::unique_ptr<IpProtectionTokenCacheManager> ipp_token_cache_manager) + override { + NOTREACHED_NORETURN(); + } + + std::vector<net::ProxyChain> GetProxyChainList() override { + return proxy_chain_list_; + } + + bool IsProxyListAvailable() override { return proxy_list_.has_value(); } + + void RequestRefreshProxyList() override { + if (on_force_refresh_proxy_list_) { + std::move(on_force_refresh_proxy_list_).Run(); + } + } + + // Set the proxy list returned from `ProxyList()`. + void SetProxyList(std::vector<std::vector<std::string>> proxy_list) { + proxy_list_ = std::move(proxy_list); + proxy_chain_list_ = IpProtectionConfigCacheImpl:: + ConvertProxyServerStringsToProxyChainListForTesting(*proxy_list_); + } + + void SetOnRequestRefreshProxyList( + base::OnceClosure on_force_refresh_proxy_list) { + on_force_refresh_proxy_list_ = std::move(on_force_refresh_proxy_list); + } + + private: + absl::optional<network::mojom::BlindSignedAuthTokenPtr> auth_token_; + absl::optional<std::vector<std::vector<std::string>>> proxy_list_; + std::vector<net::ProxyChain> proxy_chain_list_; + base::OnceClosure on_force_refresh_proxy_list_; +}; + +} // namespace + +MATCHER_P2(Contain, + expected_name, + expected_value, + std::string("headers ") + (negation ? "don't " : "") + "contain '" + + expected_name + ": " + expected_value + "'") { + std::string value; + return arg.GetHeader(expected_name, &value) && value == expected_value; +} + +struct HeadersReceived { + net::ProxyChain proxy_chain; + uint64_t chain_index; + scoped_refptr<net::HttpResponseHeaders> response_headers; +}; + +class TestCustomProxyConnectionObserver + : public mojom::CustomProxyConnectionObserver { + public: + TestCustomProxyConnectionObserver() = default; + ~TestCustomProxyConnectionObserver() override = default; + + const absl::optional<std::pair<net::ProxyChain, int>>& FallbackArgs() const { + return fallback_; + } + + const absl::optional<HeadersReceived>& HeadersReceivedArgs() const { + return headers_received_; + } + + // mojom::CustomProxyConnectionObserver: + void OnFallback(const net::ProxyChain& bad_chain, int net_error) override { + fallback_ = std::make_pair(bad_chain, net_error); + } + void OnTunnelHeadersReceived(const net::ProxyChain& proxy_chain, + uint64_t chain_index, + const scoped_refptr<net::HttpResponseHeaders>& + response_headers) override { + headers_received_ = + HeadersReceived{proxy_chain, chain_index, response_headers}; + } + + private: + absl::optional<std::pair<net::ProxyChain, int>> fallback_; + absl::optional<HeadersReceived> headers_received_; +}; + +class IpProtectionProxyDelegateTest : public testing::Test { + public: + IpProtectionProxyDelegateTest() = default; + + void SetUp() override { + context_ = net::CreateTestURLRequestContextBuilder()->Build(); + scoped_feature_list_.InitWithFeatures( + {net::features::kEnableIpProtectionProxy, + network::features::kMaskedDomainList}, + {}); + } + + protected: + std::unique_ptr<IpProtectionProxyDelegate> CreateDelegate( + NetworkServiceProxyAllowList* network_service_proxy_allow_list) { + return std::make_unique<IpProtectionProxyDelegate>( + network_service_proxy_allow_list); + } + + std::unique_ptr<net::URLRequest> CreateRequest(const GURL& url) { + return context_->CreateRequest(url, net::DEFAULT_PRIORITY, nullptr, + TRAFFIC_ANNOTATION_FOR_TESTS); + } + + mojom::BlindSignedAuthTokenPtr MakeAuthToken(std::string content) { + auto token = mojom::BlindSignedAuthToken::New(); + token->token = std::move(content); + return token; + } + + void RunUntilIdle() { task_environment_.RunUntilIdle(); } + + private: + std::unique_ptr<net::URLRequestContext> context_; + base::test::ScopedFeatureList scoped_feature_list_; + base::test::TaskEnvironment task_environment_; +}; + +TEST_F(IpProtectionProxyDelegateTest, AddsTokenToTunnelRequest) { + auto delegate = CreateDelegate(nullptr); + + auto ipp_config_cache = std::make_unique<MockIpProtectionConfigCache>(); + ipp_config_cache->SetNextAuthToken(MakeAuthToken("Bearer: a-token")); + ipp_config_cache->SetProxyList({{"proxya", "proxyb"}}); + delegate->SetIpProtectionConfigCache(std::move(ipp_config_cache)); + + net::HttpRequestHeaders headers; + auto ip_protection_proxy_chain = + net::ProxyChain( + {net::ProxyServer::FromSchemeHostAndPort( + net::ProxyServer::SCHEME_HTTPS, "proxya", absl::nullopt), + net::ProxyServer::FromSchemeHostAndPort( + net::ProxyServer::SCHEME_HTTPS, "proxyb", absl::nullopt)}) + .ForIpProtection(); + delegate->OnBeforeTunnelRequest(ip_protection_proxy_chain, /*chain_index=*/0, + &headers); + + EXPECT_THAT(headers, Contain("Authorization", "Bearer: a-token")); +} + +TEST_F(IpProtectionProxyDelegateTest, AddsPskToTunnelRequest) { + std::map<std::string, std::string> parameters; + parameters[net::features::kIpPrivacyProxyBPsk.name] = "seekrit"; + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndEnableFeatureWithParameters( + net::features::kEnableIpProtectionProxy, std::move(parameters)); + + auto delegate = CreateDelegate(nullptr); + + auto ipp_config_cache = std::make_unique<MockIpProtectionConfigCache>(); + ipp_config_cache->SetProxyList({{"proxya", "proxyb"}}); + delegate->SetIpProtectionConfigCache(std::move(ipp_config_cache)); + + net::HttpRequestHeaders headers; + auto ip_protection_proxy_chain = + net::ProxyChain( + {net::ProxyServer::FromSchemeHostAndPort( + net::ProxyServer::SCHEME_HTTPS, "proxya", absl::nullopt), + net::ProxyServer::FromSchemeHostAndPort( + net::ProxyServer::SCHEME_HTTPS, "proxyb", absl::nullopt)}) + .ForIpProtection(); + delegate->OnBeforeTunnelRequest(ip_protection_proxy_chain, /*chain_index=*/0, + &headers); + EXPECT_THAT(headers, testing::Not(Contain("Proxy-Authorization", + "Preshared seekrit"))); + + delegate->OnBeforeTunnelRequest(ip_protection_proxy_chain, /*chain_index=*/1, + &headers); + EXPECT_THAT(headers, Contain("Proxy-Authorization", "Preshared seekrit")); +} + +TEST_F(IpProtectionProxyDelegateTest, + OnResolveProxyDiscardsInvalidProxyServers) { + std::map<std::string, std::set<std::string>> first_party_map; + first_party_map["example.com"] = {}; + auto network_service_proxy_allow_list = + NetworkServiceProxyAllowList::CreateForTesting(first_party_map); + auto delegate = CreateDelegate(&network_service_proxy_allow_list); + + auto ipp_config_cache = std::make_unique<MockIpProtectionConfigCache>(); + ipp_config_cache->SetNextAuthToken(MakeAuthToken("Bearer: a-token")); + ipp_config_cache->SetProxyList({{"[foo]"}}); + delegate->SetIpProtectionConfigCache(std::move(ipp_config_cache)); + + net::ProxyInfo result; + result.UseDirect(); + delegate->OnResolveProxy(GURL(kHttpsUrl), + net::NetworkAnonymizationKey::CreateCrossSite( + net::SchemefulSite(GURL("https://top.com"))), + "GET", net::ProxyRetryInfoMap(), &result); + EXPECT_TRUE(result.is_direct()); + EXPECT_FALSE(result.is_for_ip_protection()); +} + +TEST_F(IpProtectionProxyDelegateTest, OnResolveProxyDeprioritizesBadProxies) { + std::map<std::string, std::set<std::string>> first_party_map; + first_party_map["example.com"] = {}; + auto network_service_proxy_allow_list = + NetworkServiceProxyAllowList::CreateForTesting(first_party_map); + auto delegate = CreateDelegate(&network_service_proxy_allow_list); + + auto ipp_config_cache = std::make_unique<MockIpProtectionConfigCache>(); + ipp_config_cache->SetNextAuthToken(MakeAuthToken("Bearer: a-token")); + ipp_config_cache->SetProxyList({{"proxya"}, {"backup"}}); + delegate->SetIpProtectionConfigCache(std::move(ipp_config_cache)); + + net::ProxyRetryInfoMap retry_map; + net::ProxyRetryInfo& info = + retry_map[ProxyUriToProxyChain("https://proxya", + net::ProxyServer::SCHEME_HTTPS) + .ForIpProtection()]; + info.try_while_bad = false; + info.bad_until = base::TimeTicks::Now() + base::Days(2); + + net::ProxyInfo result; + result.UseDirect(); + delegate->OnResolveProxy(GURL(kHttpsUrl), + net::NetworkAnonymizationKey::CreateCrossSite( + net::SchemefulSite(GURL("https://top.com"))), + "GET", std::move(retry_map), &result); + + net::ProxyList expected_proxy_list; + expected_proxy_list.AddProxyChain( + net::PacResultElementToProxyChain("HTTPS backup").ForIpProtection()); + expected_proxy_list.AddProxyServer(net::ProxyServer::Direct()); + + EXPECT_TRUE(result.proxy_list().Equals(expected_proxy_list)) + << "Got: " << result.proxy_list().ToDebugString(); + EXPECT_TRUE(result.is_for_ip_protection()); +} + +TEST_F(IpProtectionProxyDelegateTest, OnResolveProxyAllProxiesBad) { + std::map<std::string, std::set<std::string>> first_party_map; + first_party_map["example.com"] = {}; + auto network_service_proxy_allow_list = + NetworkServiceProxyAllowList::CreateForTesting(first_party_map); + auto delegate = CreateDelegate(&network_service_proxy_allow_list); + + auto ipp_config_cache = std::make_unique<MockIpProtectionConfigCache>(); + ipp_config_cache->SetNextAuthToken(MakeAuthToken("Bearer: a-token")); + ipp_config_cache->SetProxyList({{"proxya"}}); + delegate->SetIpProtectionConfigCache(std::move(ipp_config_cache)); + + net::ProxyRetryInfoMap retry_map; + net::ProxyRetryInfo& info = + retry_map[ProxyUriToProxyChain("https://proxya", + net::ProxyServer::SCHEME_HTTPS) + .ForIpProtection()]; + info.try_while_bad = false; + info.bad_until = base::TimeTicks::Now() + base::Days(2); + + net::ProxyInfo result; + result.UseDirect(); + delegate->OnResolveProxy(GURL(kHttpsUrl), + net::NetworkAnonymizationKey::CreateCrossSite( + net::SchemefulSite(GURL("https://top.com"))), + "GET", std::move(retry_map), &result); + + EXPECT_TRUE(result.is_direct()); + EXPECT_FALSE(result.is_for_ip_protection()); +} + +TEST_F(IpProtectionProxyDelegateTest, + OnResolveProxyNetworkServiceProxyAllowListMatch) { + std::map<std::string, std::set<std::string>> first_party_map; + first_party_map["example.com"] = {}; + auto network_service_proxy_allow_list = + NetworkServiceProxyAllowList::CreateForTesting(first_party_map); + auto delegate = CreateDelegate(&network_service_proxy_allow_list); + + auto ipp_config_cache = std::make_unique<MockIpProtectionConfigCache>(); + ipp_config_cache->SetNextAuthToken(MakeAuthToken("Bearer: a-token")); + ipp_config_cache->SetProxyList( + {{"ippro-1", "ippro-2"}, {"ippro-2", "ippro-2"}}); + delegate->SetIpProtectionConfigCache(std::move(ipp_config_cache)); + + net::ProxyInfo result; + // Verify that the IP Protection proxy list is correctly merged with the + // existing proxy list. + result.UsePacString("PROXY bar; DIRECT; PROXY weird"); + delegate->OnResolveProxy(GURL(kHttpsUrl), + net::NetworkAnonymizationKey::CreateCrossSite( + net::SchemefulSite(GURL("https://top.com"))), + "GET", net::ProxyRetryInfoMap(), &result); + + net::ProxyList expected_proxy_list; + expected_proxy_list.AddProxyServer( + net::PacResultElementToProxyServer("PROXY bar")); + + const net::ProxyServer kProxyServer1{net::ProxyServer::SCHEME_HTTPS, + net::HostPortPair("ippro-1", 443)}; + const net::ProxyServer kProxyServer2{net::ProxyServer::SCHEME_HTTPS, + net::HostPortPair("ippro-2", 443)}; + const net::ProxyChain kIpProtectionChain1 = + net::ProxyChain({kProxyServer1, kProxyServer2}).ForIpProtection(); + const net::ProxyChain kIpProtectionChain2 = + net::ProxyChain({kProxyServer2, kProxyServer2}).ForIpProtection(); + + expected_proxy_list.AddProxyChain(std::move(kIpProtectionChain1)); + expected_proxy_list.AddProxyChain(std::move(kIpProtectionChain2)); + expected_proxy_list.AddProxyServer(net::ProxyServer::Direct()); + expected_proxy_list.AddProxyServer( + net::PacResultElementToProxyServer("PROXY weird")); + + EXPECT_TRUE(result.proxy_list().Equals(expected_proxy_list)) + << "Got: " << result.proxy_list().ToDebugString(); + EXPECT_FALSE(result.is_for_ip_protection()); + + // After a fallback, the first IP Protection proxy chain should be used. + EXPECT_TRUE(result.Fallback(net::ERR_PROXY_CONNECTION_FAILED, + net::NetLogWithSource())); + EXPECT_TRUE(result.is_for_ip_protection()); +} + +TEST_F(IpProtectionProxyDelegateTest, + OnResolveProxyNetworkServiceProxyAllowListMatch_DirectOnly) { + std::map<std::string, std::string> parameters; + parameters[net::features::kIpPrivacyDirectOnly.name] = "true"; + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndEnableFeatureWithParameters( + net::features::kEnableIpProtectionProxy, std::move(parameters)); + std::map<std::string, std::set<std::string>> first_party_map; + first_party_map["example.com"] = {}; + auto network_service_proxy_allow_list = + NetworkServiceProxyAllowList::CreateForTesting(first_party_map); + auto delegate = CreateDelegate(&network_service_proxy_allow_list); + + auto ipp_config_cache = std::make_unique<MockIpProtectionConfigCache>(); + ipp_config_cache->SetNextAuthToken(MakeAuthToken("Bearer: a-token")); + ipp_config_cache->SetProxyList({{"foo"}}); + delegate->SetIpProtectionConfigCache(std::move(ipp_config_cache)); + + net::ProxyInfo result; + result.UseDirect(); + delegate->OnResolveProxy(GURL(kHttpsUrl), + net::NetworkAnonymizationKey::CreateCrossSite( + net::SchemefulSite(GURL("https://top.com"))), + "GET", net::ProxyRetryInfoMap(), &result); + + net::ProxyList expected_proxy_list; + auto ip_protection_proxy_chain = net::ProxyChain::Direct().ForIpProtection(); + expected_proxy_list.AddProxyChain(std::move(ip_protection_proxy_chain)); + EXPECT_TRUE(result.proxy_list().Equals(expected_proxy_list)) + << "Got: " << result.proxy_list().ToDebugString(); + EXPECT_TRUE(result.is_for_ip_protection()); +} + +TEST_F( + IpProtectionProxyDelegateTest, + OnResolveProxyNetworkServiceProxyAllowListDoesNotMatch_FirstPartyException) { + std::map<std::string, std::set<std::string>> first_party_map; + first_party_map["example.com"] = {"top.com"}; + auto network_service_proxy_allow_list = + NetworkServiceProxyAllowList::CreateForTesting(first_party_map); + auto delegate = CreateDelegate(&network_service_proxy_allow_list); + + auto ipp_config_cache = std::make_unique<MockIpProtectionConfigCache>(); + ipp_config_cache->SetNextAuthToken(MakeAuthToken("Bearer: a-token")); + ipp_config_cache->SetProxyList({{"ippro-1"}, {"ippro-2"}}); + delegate->SetIpProtectionConfigCache(std::move(ipp_config_cache)); + + net::ProxyInfo result; + result.UseDirect(); + delegate->OnResolveProxy(GURL(kHttpsUrl), + net::NetworkAnonymizationKey::CreateCrossSite( + net::SchemefulSite(GURL("https://top.com"))), + "GET", net::ProxyRetryInfoMap(), &result); + + EXPECT_TRUE(result.is_direct()); + EXPECT_FALSE(result.is_for_ip_protection()); +} + +TEST_F(IpProtectionProxyDelegateTest, OnResolveProxy_NoConfigCache) { + std::map<std::string, std::set<std::string>> first_party_map; + first_party_map["example.com"] = {}; + auto network_service_proxy_allow_list = + NetworkServiceProxyAllowList::CreateForTesting(first_party_map); + auto delegate = CreateDelegate(&network_service_proxy_allow_list); + + net::ProxyInfo result; + result.UseDirect(); + delegate->OnResolveProxy(GURL(kHttpsUrl), + net::NetworkAnonymizationKey::CreateCrossSite( + net::SchemefulSite(GURL("https://top.com"))), + "GET", net::ProxyRetryInfoMap(), &result); + + EXPECT_TRUE(result.is_direct()); + EXPECT_FALSE(result.is_for_ip_protection()); +} + +TEST_F(IpProtectionProxyDelegateTest, OnResolveProxy_NoAuthToken) { + std::map<std::string, std::set<std::string>> first_party_map; + first_party_map["example.com"] = {}; + auto network_service_proxy_allow_list = + NetworkServiceProxyAllowList::CreateForTesting(first_party_map); + auto delegate = CreateDelegate(&network_service_proxy_allow_list); + + auto ipp_config_cache = std::make_unique<MockIpProtectionConfigCache>(); + ipp_config_cache->SetProxyList({{"proxy"}}); + // No token is added to the cache, so the result will be direct. + delegate->SetIpProtectionConfigCache(std::move(ipp_config_cache)); + + net::ProxyInfo result; + result.UseDirect(); + delegate->OnResolveProxy(GURL(kHttpsUrl), + net::NetworkAnonymizationKey::CreateCrossSite( + net::SchemefulSite(GURL("https://top.com"))), + "GET", net::ProxyRetryInfoMap(), &result); + + EXPECT_TRUE(result.is_direct()); + EXPECT_FALSE(result.is_for_ip_protection()); +} + +TEST_F(IpProtectionProxyDelegateTest, OnResolveProxy_NoProxyList) { + std::map<std::string, std::set<std::string>> first_party_map; + first_party_map["example.com"] = {}; + auto network_service_proxy_allow_list = + NetworkServiceProxyAllowList::CreateForTesting(first_party_map); + auto delegate = CreateDelegate(&network_service_proxy_allow_list); + auto ipp_config_cache = std::make_unique<MockIpProtectionConfigCache>(); + // No proxy list is added to the cache, so the result will be direct. + ipp_config_cache->SetNextAuthToken(MakeAuthToken("Bearer: a-token")); + delegate->SetIpProtectionConfigCache(std::move(ipp_config_cache)); + + net::ProxyInfo result; + result.UseDirect(); + delegate->OnResolveProxy(GURL(kHttpsUrl), + net::NetworkAnonymizationKey::CreateCrossSite( + net::SchemefulSite(GURL("https://top.com"))), + "GET", net::ProxyRetryInfoMap(), &result); + + EXPECT_TRUE(result.is_direct()); + EXPECT_FALSE(result.is_for_ip_protection()); +} + +TEST_F(IpProtectionProxyDelegateTest, OnResolveProxy_AllowListDisabled) { + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitWithFeatures({}, + {net::features::kEnableIpProtectionProxy, + network::features::kMaskedDomainList}); + std::map<std::string, std::set<std::string>> first_party_map; + first_party_map["example.com"] = {}; + auto network_service_proxy_allow_list = + NetworkServiceProxyAllowList::CreateForTesting(first_party_map); + auto delegate = CreateDelegate(&network_service_proxy_allow_list); + + auto ipp_config_cache = std::make_unique<MockIpProtectionConfigCache>(); + ipp_config_cache->SetNextAuthToken(MakeAuthToken("Bearer: a-token")); + ipp_config_cache->SetProxyList({{"proxy"}}); + delegate->SetIpProtectionConfigCache(std::move(ipp_config_cache)); + + net::ProxyInfo result; + result.UseDirect(); + delegate->OnResolveProxy(GURL(kHttpsUrl), + net::NetworkAnonymizationKey::CreateCrossSite( + net::SchemefulSite(GURL("https://top.com"))), + "GET", net::ProxyRetryInfoMap(), &result); + + EXPECT_TRUE(result.is_direct()); + EXPECT_FALSE(result.is_for_ip_protection()); +} + +TEST_F( + IpProtectionProxyDelegateTest, + OnResolveProxyNetworkServiceProxyAllowListDoesNotMatch_ResourceNotAllowed) { + std::map<std::string, std::set<std::string>> first_party_map; + auto network_service_proxy_allow_list = + NetworkServiceProxyAllowList::CreateForTesting(first_party_map); + + auto delegate = CreateDelegate(&network_service_proxy_allow_list); + + auto ipp_config_cache = std::make_unique<MockIpProtectionConfigCache>(); + ipp_config_cache->SetNextAuthToken(MakeAuthToken("Bearer: a-token")); + ipp_config_cache->SetProxyList({{"ippro-1"}, {"ippro-2"}}); + delegate->SetIpProtectionConfigCache(std::move(ipp_config_cache)); + + net::ProxyInfo result; + result.UseDirect(); + delegate->OnResolveProxy(GURL(kHttpsUrl), + net::NetworkAnonymizationKey::CreateCrossSite( + net::SchemefulSite(GURL("https://top.com"))), + "GET", net::ProxyRetryInfoMap(), &result); + + EXPECT_TRUE(result.is_direct()); + EXPECT_FALSE(result.is_for_ip_protection()); +} + +// When URLs do not match the allow list, the result is direct and not flagged +// as for IP protection. +TEST_F(IpProtectionProxyDelegateTest, OnResolveProxyIpProtectionNoMatch) { + std::map<std::string, std::set<std::string>> first_party_map; + auto network_service_proxy_allow_list = + NetworkServiceProxyAllowList::CreateForTesting(first_party_map); + auto delegate = CreateDelegate(&network_service_proxy_allow_list); + + auto ipp_config_cache = std::make_unique<MockIpProtectionConfigCache>(); + ipp_config_cache->SetNextAuthToken(MakeAuthToken("Bearer: a-token")); + ipp_config_cache->SetProxyList({{"ippro-1"}, {"ippro-2"}}); + delegate->SetIpProtectionConfigCache(std::move(ipp_config_cache)); + + net::ProxyInfo result; + result.UseDirect(); + delegate->OnResolveProxy(GURL(kLocalhost), + net::NetworkAnonymizationKey::CreateCrossSite( + net::SchemefulSite(GURL("http://top.com"))), + "GET", net::ProxyRetryInfoMap(), &result); + EXPECT_TRUE(result.is_direct()); + EXPECT_FALSE(result.is_for_ip_protection()); +} + +// When the URL is HTTP and single-proxy chains are used, the result is direct +// and not flagged as for IP Protection. +// TODO(https://crbug.com/1474932): Once IP Protection chains are guaranteed to +// be multi-proxy, we can remove this test. +TEST_F(IpProtectionProxyDelegateTest, + OnResolveProxyIpProtectionSingleProxyHttpFailure) { + std::map<std::string, std::set<std::string>> first_party_map; + first_party_map["example.com"] = {}; + auto network_service_proxy_allow_list = + NetworkServiceProxyAllowList::CreateForTesting(first_party_map); + auto delegate = CreateDelegate(&network_service_proxy_allow_list); + + auto ipp_config_cache = std::make_unique<MockIpProtectionConfigCache>(); + ipp_config_cache->SetNextAuthToken(MakeAuthToken("Bearer: a-token")); + ipp_config_cache->SetProxyList({{"proxy"}}); + delegate->SetIpProtectionConfigCache(std::move(ipp_config_cache)); + + net::ProxyInfo result; + result.UseDirect(); + delegate->OnResolveProxy(GURL(kHttpUrl), + net::NetworkAnonymizationKey::CreateCrossSite( + net::SchemefulSite(GURL("http://top.com"))), + "GET", net::ProxyRetryInfoMap(), &result); + EXPECT_TRUE(result.is_direct()); + EXPECT_FALSE(result.is_for_ip_protection()); +} + +// When the URL is HTTP and multi-proxy chains are used, the result is flagged +// as for IP protection and is not direct. +TEST_F(IpProtectionProxyDelegateTest, + OnResolveProxyIpProtectionMultiProxyHttpSuccess) { + std::map<std::string, std::set<std::string>> first_party_map; + first_party_map["example.com"] = {}; + auto network_service_proxy_allow_list = + NetworkServiceProxyAllowList::CreateForTesting(first_party_map); + auto delegate = CreateDelegate(&network_service_proxy_allow_list); + + auto ipp_config_cache = std::make_unique<MockIpProtectionConfigCache>(); + ipp_config_cache->SetNextAuthToken(MakeAuthToken("Bearer: a-token")); + ipp_config_cache->SetProxyList({{"proxy1", "proxy2"}}); + delegate->SetIpProtectionConfigCache(std::move(ipp_config_cache)); + + net::ProxyInfo result; + result.UseDirect(); + delegate->OnResolveProxy(GURL(kHttpUrl), + net::NetworkAnonymizationKey::CreateCrossSite( + net::SchemefulSite(GURL("http://top.com"))), + "GET", net::ProxyRetryInfoMap(), &result); + EXPECT_FALSE(result.is_direct()); + EXPECT_TRUE(result.is_for_ip_protection()); +} + +// When URLs match the allow list, and a token is available, the result is +// flagged as for IP protection and is not direct. +TEST_F(IpProtectionProxyDelegateTest, OnResolveProxyIpProtectionHttpsSuccess) { + std::map<std::string, std::set<std::string>> first_party_map; + first_party_map["example.com"] = {}; + auto network_service_proxy_allow_list = + NetworkServiceProxyAllowList::CreateForTesting(first_party_map); + auto delegate = CreateDelegate(&network_service_proxy_allow_list); + + auto ipp_config_cache = std::make_unique<MockIpProtectionConfigCache>(); + ipp_config_cache->SetNextAuthToken(MakeAuthToken("Bearer: a-token")); + ipp_config_cache->SetProxyList({{"proxy"}}); + delegate->SetIpProtectionConfigCache(std::move(ipp_config_cache)); + + net::ProxyInfo result; + result.UseDirect(); + delegate->OnResolveProxy(GURL(kHttpsUrl), + net::NetworkAnonymizationKey::CreateCrossSite( + net::SchemefulSite(GURL("https://top.com"))), + "GET", net::ProxyRetryInfoMap(), &result); + EXPECT_FALSE(result.is_direct()); + EXPECT_TRUE(result.is_for_ip_protection()); +} + +TEST_F(IpProtectionProxyDelegateTest, OnFallback_IpProtection) { + auto ip_protection_proxy_chain = + net::ProxyChain::FromSchemeHostAndPort(net::ProxyServer::SCHEME_HTTPS, + "proxy.com", absl::nullopt) + .ForIpProtection(); + bool force_refresh_called = false; + + auto delegate = CreateDelegate(nullptr); + + auto ipp_config_cache = std::make_unique<MockIpProtectionConfigCache>(); + ipp_config_cache->SetOnRequestRefreshProxyList( + base::BindLambdaForTesting([&]() { force_refresh_called = true; })); + ipp_config_cache->SetProxyList({{"proxy.com"}}); + delegate->SetIpProtectionConfigCache(std::move(ipp_config_cache)); + + delegate->OnFallback(ip_protection_proxy_chain, net::ERR_FAILED); + EXPECT_TRUE(force_refresh_called); +} + +TEST_F(IpProtectionProxyDelegateTest, MergeProxyRules) { + net::ProxyChain chain1({ + net::ProxyServer::FromSchemeHostAndPort(net::ProxyServer::SCHEME_HTTPS, + "proxy2a.com", 80), + net::ProxyServer::FromSchemeHostAndPort(net::ProxyServer::SCHEME_HTTPS, + "proxy2b.com", 80), + }); + net::ProxyChain chain2(net::ProxyServer::Direct()); + net::ProxyChain chain3({ + net::ProxyServer::FromSchemeHostAndPort(net::ProxyServer::SCHEME_HTTPS, + "proxy1.com", 80), + }); + net::ProxyList existing_proxy_list; + existing_proxy_list.AddProxyChain(chain1); + existing_proxy_list.AddProxyChain(chain2); + existing_proxy_list.AddProxyChain(chain3); + + net::ProxyChain custom1({ + net::ProxyServer::FromSchemeHostAndPort(net::ProxyServer::SCHEME_HTTPS, + "custom-a.com", 80), + net::ProxyServer::FromSchemeHostAndPort(net::ProxyServer::SCHEME_HTTPS, + "custom-b.com", 80), + net::ProxyServer::FromSchemeHostAndPort(net::ProxyServer::SCHEME_HTTPS, + "custom-c.com", 80), + }); + net::ProxyChain custom2(net::ProxyServer::Direct()); + net::ProxyList custom_proxy_list; + custom_proxy_list.AddProxyChain(custom1); + custom_proxy_list.AddProxyChain(custom2); + + auto delegate = CreateDelegate(nullptr); + + auto result = + delegate->MergeProxyRules(existing_proxy_list, custom_proxy_list); + + // Custom chains replace `chain2`. + std::vector<net::ProxyChain> expected = { + chain1, + custom1, + custom2, + chain3, + }; + EXPECT_EQ(result.AllChains(), expected); +} + +} // namespace network
diff --git a/services/network/network_context.cc b/services/network/network_context.cc index dc72b94..06e53dcec8 100644 --- a/services/network/network_context.cc +++ b/services/network/network_context.cc
@@ -98,6 +98,7 @@ #include "services/network/http_server_properties_pref_delegate.h" #include "services/network/ignore_errors_cert_verifier.h" #include "services/network/ip_protection/ip_protection_config_cache_impl.h" +#include "services/network/ip_protection/ip_protection_proxy_delegate.h" #include "services/network/ip_protection/ip_protection_token_cache_manager_impl.h" #include "services/network/is_browser_initiated.h" #include "services/network/net_log_exporter.h" @@ -1932,7 +1933,11 @@ // initialized. CHECK(proxy_delegate_); - auto* ipp_config_cache = proxy_delegate_->GetIpProtectionConfigCache(); + // TODO(crbug.com/1476881): this mojom method should move to the + // IpProtectionProxyDelegate class. + IpProtectionProxyDelegate* proxy_delegate = + static_cast<IpProtectionProxyDelegate*>(proxy_delegate_.get()); + auto* ipp_config_cache = proxy_delegate->GetIpProtectionConfigCache(); CHECK(ipp_config_cache); auto* ipp_token_cache_manager_impl = static_cast<IpProtectionTokenCacheManagerImpl*>( @@ -1951,13 +1956,14 @@ ipp_token_cache_manager_impl->DisableCacheManagementForTesting( // IN-TEST base::BindOnce( [](base::WeakPtr<NetworkContext> weak_ptr, - VerifyIpProtectionConfigGetterForTestingCallback callback) { + VerifyIpProtectionConfigGetterForTestingCallback callback, + IpProtectionProxyDelegate* proxy_delegate) { // If this callback is called then `ipp_config_cache` is // still alive, which means that this `NetworkContext` is alive as // well. CHECK(weak_ptr); auto* ipp_config_cache = - weak_ptr->proxy_delegate_->GetIpProtectionConfigCache(); + proxy_delegate->GetIpProtectionConfigCache(); ipp_config_cache->InvalidateTryAgainAfterTime(); while (ipp_config_cache->AreAuthTokensAvailable()) { ipp_config_cache->GetAuthToken(0); // kProxyA. @@ -1973,7 +1979,7 @@ &NetworkContext::VerifyIpProtectionConfigGetterForTesting, weak_ptr, std::move(callback))); }, - weak_factory_.GetWeakPtr(), std::move(callback))); + weak_factory_.GetWeakPtr(), std::move(callback), proxy_delegate)); return; } @@ -1995,9 +2001,12 @@ ipp_token_cache_manager_impl->CallTryGetAuthTokensForTesting(); // IN-TEST } +// TODO(crbug.com/1476881): this should move to IpProtectionProxyDelegate void NetworkContext::OnIpProtectionConfigAvailableForTesting( VerifyIpProtectionConfigGetterForTestingCallback callback) { - auto* ipp_config_cache = proxy_delegate_->GetIpProtectionConfigCache(); + IpProtectionProxyDelegate* proxy_delegate = + static_cast<IpProtectionProxyDelegate*>(proxy_delegate_.get()); + auto* ipp_config_cache = proxy_delegate->GetIpProtectionConfigCache(); auto* ipp_token_cache_manager_impl = static_cast<IpProtectionTokenCacheManagerImpl*>( ipp_config_cache @@ -2020,7 +2029,9 @@ if (!proxy_delegate_) { return; } - auto* ipp_config_cache = proxy_delegate_->GetIpProtectionConfigCache(); + IpProtectionProxyDelegate* proxy_delegate = + static_cast<IpProtectionProxyDelegate*>(proxy_delegate_.get()); + auto* ipp_config_cache = proxy_delegate->GetIpProtectionConfigCache(); if (!ipp_config_cache) { return; } @@ -2359,13 +2370,13 @@ network_delegate_ = network_delegate.get(); builder.set_network_delegate(std::move(network_delegate)); - if (params_->initial_custom_proxy_config || - params_->custom_proxy_config_client_receiver) { - std::unique_ptr<NetworkServiceProxyDelegate> proxy_delegate = - std::make_unique<NetworkServiceProxyDelegate>( - std::move(params_->initial_custom_proxy_config), - std::move(params_->custom_proxy_config_client_receiver), - std::move(params_->custom_proxy_connection_observer_remote), + // Decide which ProxyDelegate to create. + // TODO(crbug.com/1476881): clean up this logic. + if (params_->initial_custom_proxy_config && + params_->initial_custom_proxy_config->rules + .restrict_to_network_service_proxy_allow_list) { + std::unique_ptr<IpProtectionProxyDelegate> proxy_delegate = + std::make_unique<IpProtectionProxyDelegate>( network_service_->network_service_proxy_allow_list()); if (params_->ip_protection_config_getter) { proxy_delegate->SetIpProtectionConfigCache( @@ -2375,6 +2386,15 @@ } proxy_delegate_ = proxy_delegate.get(); builder.set_proxy_delegate(std::move(proxy_delegate)); + } else if (params_->initial_custom_proxy_config || + params_->custom_proxy_config_client_receiver) { + std::unique_ptr<NetworkServiceProxyDelegate> proxy_delegate = + std::make_unique<NetworkServiceProxyDelegate>( + std::move(params_->initial_custom_proxy_config), + std::move(params_->custom_proxy_config_client_receiver), + std::move(params_->custom_proxy_connection_observer_remote)); + proxy_delegate_ = proxy_delegate.get(); + builder.set_proxy_delegate(std::move(proxy_delegate)); } net::NetLog* net_log = nullptr;
diff --git a/services/network/network_context.h b/services/network/network_context.h index 5a8232b..988ef64 100644 --- a/services/network/network_context.h +++ b/services/network/network_context.h
@@ -94,6 +94,7 @@ class HostPortPair; class IsolationInfo; class NetworkAnonymizationKey; +class ProxyDelegate; class StaticHttpUserAgentSettings; class URLRequestContext; class URLRequestContextBuilder; @@ -120,7 +121,6 @@ class NetworkService; class NetworkServiceMemoryCache; class NetworkServiceNetworkDelegate; -class NetworkServiceProxyDelegate; class P2PSocketManager; class PendingTrustTokenStore; class ProxyLookupRequest; @@ -898,7 +898,7 @@ std::unique_ptr<net::HostResolver::ProbeRequest> doh_probes_request_; // Owned by URLRequestContext. - raw_ptr<NetworkServiceProxyDelegate> proxy_delegate_ = nullptr; + raw_ptr<net::ProxyDelegate> proxy_delegate_ = nullptr; // Used for Signed Exchange certificate verification. uint64_t next_cert_verify_id_ = 0;
diff --git a/services/network/network_service_proxy_delegate.cc b/services/network/network_service_proxy_delegate.cc index d144bbf..b9652e9 100644 --- a/services/network/network_service_proxy_delegate.cc +++ b/services/network/network_service_proxy_delegate.cc
@@ -16,7 +16,6 @@ #include "net/http/http_util.h" #include "net/proxy_resolution/proxy_info.h" #include "net/proxy_resolution/proxy_resolution_service.h" -#include "services/network/masked_domain_list/network_service_proxy_allow_list.h" #include "services/network/url_loader.h" #include "url/url_constants.h" @@ -108,11 +107,9 @@ mojom::CustomProxyConfigPtr initial_config, mojo::PendingReceiver<mojom::CustomProxyConfigClient> config_client_receiver, - mojo::PendingRemote<mojom::CustomProxyConnectionObserver> observer_remote, - NetworkServiceProxyAllowList* network_service_proxy_allow_list) + mojo::PendingRemote<mojom::CustomProxyConnectionObserver> observer_remote) : proxy_config_(std::move(initial_config)), - receiver_(this, std::move(config_client_receiver)), - network_service_proxy_allow_list_(network_service_proxy_allow_list) { + receiver_(this, std::move(config_client_receiver)) { // Make sure there is always a valid proxy config so we don't need to null // check it. if (!proxy_config_) { @@ -137,98 +134,6 @@ const std::string& method, const net::ProxyRetryInfoMap& proxy_retry_info, net::ProxyInfo* result) { - auto dvlog = [&](std::string message) { - absl::optional<net::SchemefulSite> top_frame_site = - network_anonymization_key.GetTopFrameSite(); - DVLOG(3) << "NSPD::OnResolveProxy(" << url << ", " - << (top_frame_site.has_value() ? top_frame_site.value() - : net::SchemefulSite()) - << ") - " << message; - }; - if (IsForIpProtection()) { - // Note: We do not proxy requests if: - // - The allow list is not available or is not enabled. - // - The request doesn't match the allow list. - // - The token cache is not available. - // - The token cache does not have tokens. - // - No proxy list is available. - // - `kEnableIpProtection` is `false`. - // - `kIpPrivacyDirectOnly` is `true`. - if (!network_service_proxy_allow_list_) { - dvlog("no proxy allow list"); - return; - } - if (!network_service_proxy_allow_list_->IsEnabled()) { - dvlog("proxy allow list not enabled"); - return; - } - if (!network_service_proxy_allow_list_->Matches( - url, network_anonymization_key)) { - dvlog("proxy allow list did not match"); - return; - } - result->set_is_mdl_match(true); - if (!base::FeatureList::IsEnabled( - net::features::kEnableIpProtectionProxy)) { - dvlog("ip protection proxy not enabled"); - return; - } - if (!ipp_config_cache_) { - dvlog("no cache"); - return; - } - if (!ipp_config_cache_->AreAuthTokensAvailable()) { - dvlog("no auth token available from cache"); - return; - } - if (!ipp_config_cache_->IsProxyListAvailable()) { - // NOTE: When this `vlog()` is removed, there's no need to distinguish - // the case where a proxy list has not been downloaded, and the case - // where a proxy list is empty. The `IsProxyListAvailable()` method can - // be removed at that time. - dvlog("no proxy list available from cache"); - return; - } - - net::ProxyList proxy_list; - if (!net::features::kIpPrivacyDirectOnly.Get()) { - const std::vector<net::ProxyChain>& proxy_chain_list = - ipp_config_cache_->GetProxyChainList(); - for (const auto& proxy_chain : proxy_chain_list) { - if (proxy_chain.is_single_proxy() && url.SchemeIs(url::kHttpScheme)) { - // Proxying HTTP traffic correctly for IP Protection requires - // multi-proxy chains to be used, so if a single-proxy chain is - // encountered here then just fail. - // TODO(https://crbug.com/1474932): Once chains are guaranteed to be - // multi-proxy here, turn this into a CHECK. - dvlog("can't proxy HTTP URL through a single-proxy chain"); - return; - } - proxy_list.AddProxyChain(std::move(proxy_chain)); - } - } - // Final fallback is to DIRECT. - auto direct_proxy_chain = net::ProxyChain::Direct(); - if (net::features::kIpPrivacyDirectOnly.Get()) { - // To enable measuring how much traffic would be proxied (for - // experimentation and planning purposes), mark the direct - // proxy chain as being for IP Protection when `kIpPrivacyDirectOnly` is - // true. When it is false, we only care about traffic that actually went - // through the IP Protection proxies, so don't set this flag. - direct_proxy_chain = std::move(direct_proxy_chain).ForIpProtection(); - } - proxy_list.AddProxyChain(std::move(direct_proxy_chain)); - - if (VLOG_IS_ON(3)) { - dvlog(base::StrCat({"setting proxy list (before deprioritization) to ", - proxy_list.ToDebugString()})); - } - result->OverrideProxyList( - MergeProxyRules(result->proxy_list(), proxy_list)); - result->DeprioritizeBadProxyChains(proxy_retry_info); - return; - } - // At this point, this delegate is not supporting IP protection, so apply the // `proxy_config_` as usual. if (!EligibleForProxy(*result, method)) { @@ -251,13 +156,6 @@ void NetworkServiceProxyDelegate::OnFallback(const net::ProxyChain& bad_chain, int net_error) { - // If the bad proxy was an IP Protection proxy, refresh the list of IP - // protection proxies immediately. - if (bad_chain.is_for_ip_protection()) { - CHECK(ipp_config_cache_); - ipp_config_cache_->RequestRefreshProxyList(); - } - if (observer_) { observer_->OnFallback(bad_chain, net_error); } @@ -267,38 +165,9 @@ const net::ProxyChain& proxy_chain, size_t chain_index, net::HttpRequestHeaders* extra_headers) { - - auto vlog = [](std::string message) { - VLOG(2) << "NSPD::OnBeforeTunnelRequest() - " << message; - }; if (IsInProxyConfig(proxy_chain)) { MergeRequestHeaders(extra_headers, proxy_config_->connect_tunnel_headers); } - if (IsForIpProtection() && proxy_chain.is_for_ip_protection()) { - // Temporarily support a pre-shared key for access to proxyB. - if (chain_index == 1) { - std::string proxy_b_psk = net::features::kIpPrivacyProxyBPsk.Get(); - if (!proxy_b_psk.empty()) { - vlog("adding proxyB PSK"); - extra_headers->SetHeader(net::HttpRequestHeaders::kProxyAuthorization, - base::StrCat({"Preshared ", proxy_b_psk})); - } - } - CHECK(ipp_config_cache_); - absl::optional<network::mojom::BlindSignedAuthTokenPtr> token = - ipp_config_cache_->GetAuthToken(chain_index); - if (token) { - vlog("adding auth token"); - // The token value we have here is the full Authorization header value, so - // we can add it verbatim. - extra_headers->SetHeader(net::HttpRequestHeaders::kAuthorization, - std::move((*token)->token)); - } else { - vlog("no token available"); - } - } else { - vlog("not for IP protection"); - } } net::Error NetworkServiceProxyDelegate::OnTunnelHeadersReceived( @@ -373,16 +242,6 @@ return false; } -bool NetworkServiceProxyDelegate::MayProxyURL(const GURL& url) const { - return !proxy_config_->rules.empty(); -} - -bool NetworkServiceProxyDelegate::IsForIpProtection() { - // Only IP protection uses the network service proxy allow list, so this - // config represents IP protection if and only if the allow list is in use. - return proxy_config_->rules.restrict_to_network_service_proxy_allow_list; -} - bool NetworkServiceProxyDelegate::EligibleForProxy( const net::ProxyInfo& proxy_info, const std::string& method) const {
diff --git a/services/network/network_service_proxy_delegate.h b/services/network/network_service_proxy_delegate.h index 08c8139..84350387 100644 --- a/services/network/network_service_proxy_delegate.h +++ b/services/network/network_service_proxy_delegate.h
@@ -12,8 +12,6 @@ #include "mojo/public/cpp/bindings/receiver.h" #include "mojo/public/cpp/bindings/remote.h" #include "net/base/proxy_delegate.h" -#include "services/network/ip_protection/ip_protection_config_cache.h" -#include "services/network/masked_domain_list/network_service_proxy_allow_list.h" #include "services/network/public/mojom/network_context.mojom.h" namespace net { @@ -34,8 +32,8 @@ mojom::CustomProxyConfigPtr initial_config, mojo::PendingReceiver<mojom::CustomProxyConfigClient> config_client_receiver, - mojo::PendingRemote<mojom::CustomProxyConnectionObserver> observer_remote, - NetworkServiceProxyAllowList* network_service_proxy_allow_list); + mojo::PendingRemote<mojom::CustomProxyConnectionObserver> + observer_remote); NetworkServiceProxyDelegate(const NetworkServiceProxyDelegate&) = delete; NetworkServiceProxyDelegate& operator=(const NetworkServiceProxyDelegate&) = @@ -43,11 +41,6 @@ ~NetworkServiceProxyDelegate() override; - void SetIpProtectionConfigCache( - std::unique_ptr<IpProtectionConfigCache> ipp_config_cache) { - ipp_config_cache_ = std::move(ipp_config_cache); - } - // net::ProxyDelegate implementation: void OnResolveProxy( const GURL& url, @@ -66,23 +59,13 @@ void SetProxyResolutionService( net::ProxyResolutionService* proxy_resolution_service) override; - IpProtectionConfigCache* GetIpProtectionConfigCache() { - return ipp_config_cache_.get(); - } - private: friend class NetworkServiceProxyDelegateTest; FRIEND_TEST_ALL_PREFIXES(NetworkServiceProxyDelegateTest, MergeProxyRules); - // Checks if this CustomProxyConfig is supporting IP Protection. - bool IsForIpProtection(); - // Checks whether `proxy_chain` is present in the current proxy config. bool IsInProxyConfig(const net::ProxyChain& proxy_chain) const; - // Whether the current config may proxy |url|. - bool MayProxyURL(const GURL& url) const; - // Whether the HTTP |method| with current |proxy_info| is eligible to be // proxied. bool EligibleForProxy(const net::ProxyInfo& proxy_info, @@ -107,11 +90,8 @@ mojom::CustomProxyConfigPtr proxy_config_; mojo::Receiver<mojom::CustomProxyConfigClient> receiver_; mojo::Remote<mojom::CustomProxyConnectionObserver> observer_; - raw_ptr<NetworkServiceProxyAllowList> network_service_proxy_allow_list_; raw_ptr<net::ProxyResolutionService> proxy_resolution_service_ = nullptr; - - std::unique_ptr<IpProtectionConfigCache> ipp_config_cache_; }; } // namespace network
diff --git a/services/network/network_service_proxy_delegate_unittest.cc b/services/network/network_service_proxy_delegate_unittest.cc index f30b9a7..bab9c9b 100644 --- a/services/network/network_service_proxy_delegate_unittest.cc +++ b/services/network/network_service_proxy_delegate_unittest.cc
@@ -21,10 +21,6 @@ #include "net/url_request/url_request_context.h" #include "net/url_request/url_request_context_builder.h" #include "net/url_request/url_request_test_util.h" -#include "services/network/ip_protection/ip_protection_config_cache_impl.h" -#include "services/network/ip_protection/ip_protection_proxy_list_manager.h" -#include "services/network/ip_protection/ip_protection_token_cache_manager.h" -#include "services/network/masked_domain_list/network_service_proxy_allow_list.h" #include "services/network/public/cpp/features.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -38,73 +34,6 @@ constexpr char kHttpsUrl[] = "https://example.com"; constexpr char kWebsocketUrl[] = "ws://example.com"; -class MockIpProtectionConfigCache : public IpProtectionConfigCache { - public: - bool AreAuthTokensAvailable() override { return auth_token_.has_value(); } - void InvalidateTryAgainAfterTime() override {} - absl::optional<network::mojom::BlindSignedAuthTokenPtr> GetAuthToken( - size_t chain_index) override { - return std::move(auth_token_); - } - - // Set the auth token that will be returned from the next call to - // `GetAuthToken()`. - void SetNextAuthToken( - absl::optional<network::mojom::BlindSignedAuthTokenPtr> auth_token) { - auth_token_ = std::move(auth_token); - } - - void SetUp() override { NOTREACHED_NORETURN(); } - - void SetIpProtectionProxyListManagerForTesting( - std::unique_ptr<IpProtectionProxyListManager> ipp_proxy_list_manager) - override { - NOTREACHED_NORETURN(); - } - - IpProtectionTokenCacheManager* GetIpProtectionTokenCacheManagerForTesting( - network::mojom::IpProtectionProxyLayer proxy_layer) override { - NOTREACHED_NORETURN(); - } - - void SetIpProtectionTokenCacheManagerForTesting( - network::mojom::IpProtectionProxyLayer proxy_layer, - std::unique_ptr<IpProtectionTokenCacheManager> ipp_token_cache_manager) - override { - NOTREACHED_NORETURN(); - } - - std::vector<net::ProxyChain> GetProxyChainList() override { - return proxy_chain_list_; - } - - bool IsProxyListAvailable() override { return proxy_list_.has_value(); } - - void RequestRefreshProxyList() override { - if (on_force_refresh_proxy_list_) { - std::move(on_force_refresh_proxy_list_).Run(); - } - } - - // Set the proxy list returned from `ProxyList()`. - void SetProxyList(std::vector<std::vector<std::string>> proxy_list) { - proxy_list_ = std::move(proxy_list); - proxy_chain_list_ = IpProtectionConfigCacheImpl:: - ConvertProxyServerStringsToProxyChainListForTesting(*proxy_list_); - } - - void SetOnRequestRefreshProxyList( - base::OnceClosure on_force_refresh_proxy_list) { - on_force_refresh_proxy_list_ = std::move(on_force_refresh_proxy_list); - } - - private: - absl::optional<network::mojom::BlindSignedAuthTokenPtr> auth_token_; - absl::optional<std::vector<std::vector<std::string>>> proxy_list_; - std::vector<net::ProxyChain> proxy_chain_list_; - base::OnceClosure on_force_refresh_proxy_list_; -}; - } // namespace MATCHER_P2(Contain, @@ -168,12 +97,6 @@ protected: std::unique_ptr<NetworkServiceProxyDelegate> CreateDelegate( mojom::CustomProxyConfigPtr config) { - return CreateDelegate(std::move(config), nullptr); - } - - std::unique_ptr<NetworkServiceProxyDelegate> CreateDelegate( - mojom::CustomProxyConfigPtr config, - NetworkServiceProxyAllowList* network_service_proxy_allow_list) { std::unique_ptr<TestCustomProxyConnectionObserver> observer = std::make_unique<TestCustomProxyConnectionObserver>(); observer_ = observer.get(); @@ -184,8 +107,7 @@ auto delegate = std::make_unique<NetworkServiceProxyDelegate>( network::mojom::CustomProxyConfig::New(), - client_.BindNewPipeAndPassReceiver(), std::move(observer_remote), - network_service_proxy_allow_list); + client_.BindNewPipeAndPassReceiver(), std::move(observer_remote)); SetConfig(std::move(config)); return delegate; } @@ -223,8 +145,7 @@ TEST_F(NetworkServiceProxyDelegateTest, NullConfigDoesNotCrash) { mojo::Remote<mojom::CustomProxyConfigClient> client; auto delegate = std::make_unique<NetworkServiceProxyDelegate>( - nullptr, client.BindNewPipeAndPassReceiver(), mojo::NullRemote(), - nullptr); + nullptr, client.BindNewPipeAndPassReceiver(), mojo::NullRemote()); net::HttpRequestHeaders headers; auto request = CreateRequest(GURL(kHttpUrl)); @@ -244,109 +165,6 @@ EXPECT_THAT(headers, Contain("connect", "baz")); } -TEST_F(NetworkServiceProxyDelegateTest, AddsTokenToTunnelRequest) { - auto config = - NetworkServiceProxyAllowList::MakeIpProtectionCustomProxyConfig(); - auto delegate = CreateDelegate(std::move(config)); - - auto ipp_config_cache = std::make_unique<MockIpProtectionConfigCache>(); - ipp_config_cache->SetNextAuthToken(MakeAuthToken("Bearer: a-token")); - ipp_config_cache->SetProxyList({{"proxya", "proxyb"}}); - delegate->SetIpProtectionConfigCache(std::move(ipp_config_cache)); - - net::HttpRequestHeaders headers; - auto ip_protection_proxy_chain = - net::ProxyChain( - {net::ProxyServer::FromSchemeHostAndPort( - net::ProxyServer::SCHEME_HTTPS, "proxya", absl::nullopt), - net::ProxyServer::FromSchemeHostAndPort( - net::ProxyServer::SCHEME_HTTPS, "proxyb", absl::nullopt)}) - .ForIpProtection(); - delegate->OnBeforeTunnelRequest(ip_protection_proxy_chain, /*chain_index=*/0, - &headers); - - EXPECT_THAT(headers, Contain("Authorization", "Bearer: a-token")); -} - -TEST_F(NetworkServiceProxyDelegateTest, AddsPskToTunnelRequest) { - std::map<std::string, std::string> parameters; - parameters[net::features::kIpPrivacyProxyBPsk.name] = "seekrit"; - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndEnableFeatureWithParameters( - net::features::kEnableIpProtectionProxy, std::move(parameters)); - - auto config = - NetworkServiceProxyAllowList::MakeIpProtectionCustomProxyConfig(); - auto delegate = CreateDelegate(std::move(config)); - - auto ipp_config_cache = std::make_unique<MockIpProtectionConfigCache>(); - ipp_config_cache->SetProxyList({{"proxya", "proxyb"}}); - delegate->SetIpProtectionConfigCache(std::move(ipp_config_cache)); - - net::HttpRequestHeaders headers; - auto ip_protection_proxy_chain = - net::ProxyChain( - {net::ProxyServer::FromSchemeHostAndPort( - net::ProxyServer::SCHEME_HTTPS, "proxya", absl::nullopt), - net::ProxyServer::FromSchemeHostAndPort( - net::ProxyServer::SCHEME_HTTPS, "proxyb", absl::nullopt)}) - .ForIpProtection(); - delegate->OnBeforeTunnelRequest(ip_protection_proxy_chain, /*chain_index=*/0, - &headers); - EXPECT_THAT(headers, testing::Not(Contain("Proxy-Authorization", - "Preshared seekrit"))); - - delegate->OnBeforeTunnelRequest(ip_protection_proxy_chain, /*chain_index=*/1, - &headers); - EXPECT_THAT(headers, Contain("Proxy-Authorization", "Preshared seekrit")); -} - -TEST_F(NetworkServiceProxyDelegateTest, NoTokenIfNotIpProtection) { - auto config = mojom::CustomProxyConfig::New(); - config->rules.ParseFromString("https://proxy"); - auto delegate = CreateDelegate(std::move(config)); - - auto ipp_config_cache = std::make_unique<MockIpProtectionConfigCache>(); - ipp_config_cache->SetNextAuthToken(MakeAuthToken("Bearer: a-token")); - delegate->SetIpProtectionConfigCache(std::move(ipp_config_cache)); - - net::HttpRequestHeaders headers; - auto ip_protection_proxy_chain = - net::ProxyChain(net::PacResultElementToProxyServer("HTTPS proxy")) - .ForIpProtection(); - delegate->OnBeforeTunnelRequest(ip_protection_proxy_chain, /*chain_index=*/0, - &headers); - - std::string value; - EXPECT_FALSE(headers.GetHeader("Authorization", &value)); -} - -TEST_F(NetworkServiceProxyDelegateTest, - OnResolveProxyDiscardsInvalidProxyServers) { - auto config = - NetworkServiceProxyAllowList::MakeIpProtectionCustomProxyConfig(); - std::map<std::string, std::set<std::string>> first_party_map; - first_party_map["example.com"] = {}; - auto network_service_proxy_allow_list = - NetworkServiceProxyAllowList::CreateForTesting(first_party_map); - auto delegate = - CreateDelegate(std::move(config), &network_service_proxy_allow_list); - - auto ipp_config_cache = std::make_unique<MockIpProtectionConfigCache>(); - ipp_config_cache->SetNextAuthToken(MakeAuthToken("Bearer: a-token")); - ipp_config_cache->SetProxyList({{"[foo]"}}); - delegate->SetIpProtectionConfigCache(std::move(ipp_config_cache)); - - net::ProxyInfo result; - result.UseDirect(); - delegate->OnResolveProxy(GURL(kHttpsUrl), - net::NetworkAnonymizationKey::CreateCrossSite( - net::SchemefulSite(GURL("https://top.com"))), - "GET", net::ProxyRetryInfoMap(), &result); - EXPECT_TRUE(result.is_direct()); - EXPECT_FALSE(result.is_for_ip_protection()); -} - TEST_F(NetworkServiceProxyDelegateTest, OnResolveProxySuccessHttpProxy) { auto config = mojom::CustomProxyConfig::New(); config->rules.ParseFromString("http=foo"); @@ -687,275 +505,10 @@ EXPECT_FALSE(result.is_for_ip_protection()); } -TEST_F(NetworkServiceProxyDelegateTest, - OnResolveProxyNetworkServiceProxyAllowListMatch) { - auto config = - NetworkServiceProxyAllowList::MakeIpProtectionCustomProxyConfig(); - - std::map<std::string, std::set<std::string>> first_party_map; - first_party_map["example.com"] = {}; - auto network_service_proxy_allow_list = - NetworkServiceProxyAllowList::CreateForTesting(first_party_map); - auto delegate = - CreateDelegate(std::move(config), &network_service_proxy_allow_list); - - auto ipp_config_cache = std::make_unique<MockIpProtectionConfigCache>(); - ipp_config_cache->SetNextAuthToken(MakeAuthToken("Bearer: a-token")); - ipp_config_cache->SetProxyList( - {{"ippro-1", "ippro-2"}, {"ippro-2", "ippro-2"}}); - delegate->SetIpProtectionConfigCache(std::move(ipp_config_cache)); - - net::ProxyInfo result; - // Verify that the IP Protection proxy list is correctly merged with the - // existing proxy list. - result.UsePacString("PROXY bar; DIRECT; PROXY weird"); - delegate->OnResolveProxy(GURL(kHttpsUrl), - net::NetworkAnonymizationKey::CreateCrossSite( - net::SchemefulSite(GURL("https://top.com"))), - "GET", net::ProxyRetryInfoMap(), &result); - - net::ProxyList expected_proxy_list; - expected_proxy_list.AddProxyServer( - net::PacResultElementToProxyServer("PROXY bar")); - - const net::ProxyServer kProxyServer1{net::ProxyServer::SCHEME_HTTPS, - net::HostPortPair("ippro-1", 443)}; - const net::ProxyServer kProxyServer2{net::ProxyServer::SCHEME_HTTPS, - net::HostPortPair("ippro-2", 443)}; - const net::ProxyChain kIpProtectionChain1 = - net::ProxyChain({kProxyServer1, kProxyServer2}).ForIpProtection(); - const net::ProxyChain kIpProtectionChain2 = - net::ProxyChain({kProxyServer2, kProxyServer2}).ForIpProtection(); - - expected_proxy_list.AddProxyChain(std::move(kIpProtectionChain1)); - expected_proxy_list.AddProxyChain(std::move(kIpProtectionChain2)); - expected_proxy_list.AddProxyServer(net::ProxyServer::Direct()); - expected_proxy_list.AddProxyServer( - net::PacResultElementToProxyServer("PROXY weird")); - - EXPECT_TRUE(result.proxy_list().Equals(expected_proxy_list)) - << "Got: " << result.proxy_list().ToDebugString(); - EXPECT_FALSE(result.is_for_ip_protection()); - - // After a fallback, the first IP Protection proxy chain should be used. - EXPECT_TRUE(result.Fallback(net::ERR_PROXY_CONNECTION_FAILED, - net::NetLogWithSource())); - EXPECT_TRUE(result.is_for_ip_protection()); -} - -TEST_F(NetworkServiceProxyDelegateTest, - OnResolveProxyNetworkServiceProxyAllowListMatch_DirectOnly) { - std::map<std::string, std::string> parameters; - parameters[net::features::kIpPrivacyDirectOnly.name] = "true"; - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndEnableFeatureWithParameters( - net::features::kEnableIpProtectionProxy, std::move(parameters)); - auto config = - NetworkServiceProxyAllowList::MakeIpProtectionCustomProxyConfig(); - - std::map<std::string, std::set<std::string>> first_party_map; - first_party_map["example.com"] = {}; - auto network_service_proxy_allow_list = - NetworkServiceProxyAllowList::CreateForTesting(first_party_map); - auto delegate = - CreateDelegate(std::move(config), &network_service_proxy_allow_list); - - auto ipp_config_cache = std::make_unique<MockIpProtectionConfigCache>(); - ipp_config_cache->SetNextAuthToken(MakeAuthToken("Bearer: a-token")); - ipp_config_cache->SetProxyList({{"foo"}}); - delegate->SetIpProtectionConfigCache(std::move(ipp_config_cache)); - - net::ProxyInfo result; - result.UseDirect(); - delegate->OnResolveProxy(GURL(kHttpsUrl), - net::NetworkAnonymizationKey::CreateCrossSite( - net::SchemefulSite(GURL("https://top.com"))), - "GET", net::ProxyRetryInfoMap(), &result); - - net::ProxyList expected_proxy_list; - auto ip_protection_proxy_chain = net::ProxyChain::Direct().ForIpProtection(); - expected_proxy_list.AddProxyChain(std::move(ip_protection_proxy_chain)); - EXPECT_TRUE(result.proxy_list().Equals(expected_proxy_list)) - << "Got: " << result.proxy_list().ToDebugString(); - EXPECT_TRUE(result.is_for_ip_protection()); -} - -TEST_F( - NetworkServiceProxyDelegateTest, - OnResolveProxyNetworkServiceProxyAllowListDoesNotMatch_FirstPartyException) { - auto config = - NetworkServiceProxyAllowList::MakeIpProtectionCustomProxyConfig(); - - std::map<std::string, std::set<std::string>> first_party_map; - first_party_map["example.com"] = {"top.com"}; - auto network_service_proxy_allow_list = - NetworkServiceProxyAllowList::CreateForTesting(first_party_map); - auto delegate = - CreateDelegate(std::move(config), &network_service_proxy_allow_list); - - auto ipp_config_cache = std::make_unique<MockIpProtectionConfigCache>(); - ipp_config_cache->SetNextAuthToken(MakeAuthToken("Bearer: a-token")); - ipp_config_cache->SetProxyList({{"ippro-1"}, {"ippro-2"}}); - delegate->SetIpProtectionConfigCache(std::move(ipp_config_cache)); - - net::ProxyInfo result; - result.UseDirect(); - delegate->OnResolveProxy(GURL(kHttpsUrl), - net::NetworkAnonymizationKey::CreateCrossSite( - net::SchemefulSite(GURL("https://top.com"))), - "GET", net::ProxyRetryInfoMap(), &result); - - EXPECT_TRUE(result.is_direct()); - EXPECT_FALSE(result.is_for_ip_protection()); -} - -TEST_F(NetworkServiceProxyDelegateTest, OnResolveProxy_NoConfigCache) { - auto config = - NetworkServiceProxyAllowList::MakeIpProtectionCustomProxyConfig(); - - std::map<std::string, std::set<std::string>> first_party_map; - first_party_map["example.com"] = {}; - auto network_service_proxy_allow_list = - NetworkServiceProxyAllowList::CreateForTesting(first_party_map); - auto delegate = - CreateDelegate(std::move(config), &network_service_proxy_allow_list); - - net::ProxyInfo result; - result.UseDirect(); - delegate->OnResolveProxy(GURL(kHttpsUrl), - net::NetworkAnonymizationKey::CreateCrossSite( - net::SchemefulSite(GURL("https://top.com"))), - "GET", net::ProxyRetryInfoMap(), &result); - - EXPECT_TRUE(result.is_direct()); - EXPECT_FALSE(result.is_for_ip_protection()); -} - -TEST_F(NetworkServiceProxyDelegateTest, OnResolveProxy_NoAuthToken) { - auto config = - NetworkServiceProxyAllowList::MakeIpProtectionCustomProxyConfig(); - - std::map<std::string, std::set<std::string>> first_party_map; - first_party_map["example.com"] = {}; - auto network_service_proxy_allow_list = - NetworkServiceProxyAllowList::CreateForTesting(first_party_map); - auto delegate = - CreateDelegate(std::move(config), &network_service_proxy_allow_list); - - auto ipp_config_cache = std::make_unique<MockIpProtectionConfigCache>(); - ipp_config_cache->SetProxyList({{"proxy"}}); - // No token is added to the cache, so the result will be direct. - delegate->SetIpProtectionConfigCache(std::move(ipp_config_cache)); - - net::ProxyInfo result; - result.UseDirect(); - delegate->OnResolveProxy(GURL(kHttpsUrl), - net::NetworkAnonymizationKey::CreateCrossSite( - net::SchemefulSite(GURL("https://top.com"))), - "GET", net::ProxyRetryInfoMap(), &result); - - EXPECT_TRUE(result.is_direct()); - EXPECT_FALSE(result.is_for_ip_protection()); -} - -TEST_F(NetworkServiceProxyDelegateTest, OnResolveProxy_NoProxyList) { - auto config = - NetworkServiceProxyAllowList::MakeIpProtectionCustomProxyConfig(); - - std::map<std::string, std::set<std::string>> first_party_map; - first_party_map["example.com"] = {}; - auto network_service_proxy_allow_list = - NetworkServiceProxyAllowList::CreateForTesting(first_party_map); - auto delegate = - CreateDelegate(std::move(config), &network_service_proxy_allow_list); - auto ipp_config_cache = std::make_unique<MockIpProtectionConfigCache>(); - // No proxy list is added to the cache, so the result will be direct. - ipp_config_cache->SetNextAuthToken(MakeAuthToken("Bearer: a-token")); - delegate->SetIpProtectionConfigCache(std::move(ipp_config_cache)); - - net::ProxyInfo result; - result.UseDirect(); - delegate->OnResolveProxy(GURL(kHttpsUrl), - net::NetworkAnonymizationKey::CreateCrossSite( - net::SchemefulSite(GURL("https://top.com"))), - "GET", net::ProxyRetryInfoMap(), &result); - - EXPECT_TRUE(result.is_direct()); - EXPECT_FALSE(result.is_for_ip_protection()); -} - -TEST_F(NetworkServiceProxyDelegateTest, OnResolveProxy_AllowListDisabled) { - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitWithFeatures({}, - {net::features::kEnableIpProtectionProxy, - network::features::kMaskedDomainList}); - auto config = - NetworkServiceProxyAllowList::MakeIpProtectionCustomProxyConfig(); - - std::map<std::string, std::set<std::string>> first_party_map; - first_party_map["example.com"] = {}; - auto network_service_proxy_allow_list = - NetworkServiceProxyAllowList::CreateForTesting(first_party_map); - auto delegate = - CreateDelegate(std::move(config), &network_service_proxy_allow_list); - - auto ipp_config_cache = std::make_unique<MockIpProtectionConfigCache>(); - ipp_config_cache->SetNextAuthToken(MakeAuthToken("Bearer: a-token")); - ipp_config_cache->SetProxyList({{"proxy"}}); - delegate->SetIpProtectionConfigCache(std::move(ipp_config_cache)); - - net::ProxyInfo result; - result.UseDirect(); - delegate->OnResolveProxy(GURL(kHttpsUrl), - net::NetworkAnonymizationKey::CreateCrossSite( - net::SchemefulSite(GURL("https://top.com"))), - "GET", net::ProxyRetryInfoMap(), &result); - - EXPECT_TRUE(result.is_direct()); - EXPECT_FALSE(result.is_for_ip_protection()); -} - -TEST_F( - NetworkServiceProxyDelegateTest, - OnResolveProxyNetworkServiceProxyAllowListDoesNotMatch_ResourceNotAllowed) { - auto config = - NetworkServiceProxyAllowList::MakeIpProtectionCustomProxyConfig(); - - std::map<std::string, std::set<std::string>> first_party_map; - auto network_service_proxy_allow_list = - NetworkServiceProxyAllowList::CreateForTesting(first_party_map); - - auto delegate = - CreateDelegate(std::move(config), &network_service_proxy_allow_list); - - auto ipp_config_cache = std::make_unique<MockIpProtectionConfigCache>(); - ipp_config_cache->SetNextAuthToken(MakeAuthToken("Bearer: a-token")); - ipp_config_cache->SetProxyList({{"ippro-1"}, {"ippro-2"}}); - delegate->SetIpProtectionConfigCache(std::move(ipp_config_cache)); - - net::ProxyInfo result; - result.UseDirect(); - delegate->OnResolveProxy(GURL(kHttpsUrl), - net::NetworkAnonymizationKey::CreateCrossSite( - net::SchemefulSite(GURL("https://top.com"))), - "GET", net::ProxyRetryInfoMap(), &result); - - EXPECT_TRUE(result.is_direct()); - EXPECT_FALSE(result.is_for_ip_protection()); -} - -// When a `config` does not look like an IP Protection `CustomProxyConfig`, the -// result is direct and not flagged as for IP Protection. -TEST_F(NetworkServiceProxyDelegateTest, - OnResolveProxyIpProtectionDisabledByConfig) { +TEST_F(NetworkServiceProxyDelegateTest, OnResolveProxyNothingMatching) { auto config = mojom::CustomProxyConfig::New(); auto delegate = CreateDelegate(std::move(config)); - auto ipp_config_cache = std::make_unique<MockIpProtectionConfigCache>(); - ipp_config_cache->SetNextAuthToken(MakeAuthToken("Bearer: a-token")); - ipp_config_cache->SetProxyList({{"ippro-1"}, {"ippro-2"}}); - delegate->SetIpProtectionConfigCache(std::move(ipp_config_cache)); - net::ProxyInfo result; result.UseDirect(); delegate->OnResolveProxy(GURL(kLocalhost), @@ -966,129 +519,13 @@ EXPECT_FALSE(result.is_for_ip_protection()); } -// When a `config` does look like an IP Protection `CustomProxyConfig`, but the -// URLs do not match the allow list, the result is direct and not flagged as for -// IP protection. -TEST_F(NetworkServiceProxyDelegateTest, OnResolveProxyIpProtectionNoMatch) { - auto config = - NetworkServiceProxyAllowList::MakeIpProtectionCustomProxyConfig(); - std::map<std::string, std::set<std::string>> first_party_map; - auto network_service_proxy_allow_list = - NetworkServiceProxyAllowList::CreateForTesting(first_party_map); - auto delegate = - CreateDelegate(std::move(config), &network_service_proxy_allow_list); - - auto ipp_config_cache = std::make_unique<MockIpProtectionConfigCache>(); - ipp_config_cache->SetNextAuthToken(MakeAuthToken("Bearer: a-token")); - ipp_config_cache->SetProxyList({{"ippro-1"}, {"ippro-2"}}); - delegate->SetIpProtectionConfigCache(std::move(ipp_config_cache)); - - net::ProxyInfo result; - result.UseDirect(); - delegate->OnResolveProxy(GURL(kLocalhost), - net::NetworkAnonymizationKey::CreateCrossSite( - net::SchemefulSite(GURL("http://top.com"))), - "GET", net::ProxyRetryInfoMap(), &result); - EXPECT_TRUE(result.is_direct()); - EXPECT_FALSE(result.is_for_ip_protection()); -} - -// When a `config` does look like an IP Protection `CustomProxyConfig` but the -// URL is HTTP and single-proxy chains are used, the result is direct and not -// flagged as for IP Protection. -// TODO(https://crbug.com/1474932): Once IP Protection chains are guaranteed to -// be multi-proxy, we can remove this test. -TEST_F(NetworkServiceProxyDelegateTest, - OnResolveProxyIpProtectionSingleProxyHttpFailure) { - auto config = - NetworkServiceProxyAllowList::MakeIpProtectionCustomProxyConfig(); - std::map<std::string, std::set<std::string>> first_party_map; - first_party_map["example.com"] = {}; - auto network_service_proxy_allow_list = - NetworkServiceProxyAllowList::CreateForTesting(first_party_map); - auto delegate = - CreateDelegate(std::move(config), &network_service_proxy_allow_list); - - auto ipp_config_cache = std::make_unique<MockIpProtectionConfigCache>(); - ipp_config_cache->SetNextAuthToken(MakeAuthToken("Bearer: a-token")); - ipp_config_cache->SetProxyList({{"proxy"}}); - delegate->SetIpProtectionConfigCache(std::move(ipp_config_cache)); - - net::ProxyInfo result; - result.UseDirect(); - delegate->OnResolveProxy(GURL(kHttpUrl), - net::NetworkAnonymizationKey::CreateCrossSite( - net::SchemefulSite(GURL("http://top.com"))), - "GET", net::ProxyRetryInfoMap(), &result); - EXPECT_TRUE(result.is_direct()); - EXPECT_FALSE(result.is_for_ip_protection()); -} - -// When a `config` does look like an IP Protection `CustomProxyConfig` and the -// URL is HTTP and multi-proxy chains are used, the result is flagged as for IP -// protection and is not direct. -TEST_F(NetworkServiceProxyDelegateTest, - OnResolveProxyIpProtectionMultiProxyHttpSuccess) { - auto config = - NetworkServiceProxyAllowList::MakeIpProtectionCustomProxyConfig(); - std::map<std::string, std::set<std::string>> first_party_map; - first_party_map["example.com"] = {}; - auto network_service_proxy_allow_list = - NetworkServiceProxyAllowList::CreateForTesting(first_party_map); - auto delegate = - CreateDelegate(std::move(config), &network_service_proxy_allow_list); - - auto ipp_config_cache = std::make_unique<MockIpProtectionConfigCache>(); - ipp_config_cache->SetNextAuthToken(MakeAuthToken("Bearer: a-token")); - ipp_config_cache->SetProxyList({{"proxy1", "proxy2"}}); - delegate->SetIpProtectionConfigCache(std::move(ipp_config_cache)); - - net::ProxyInfo result; - result.UseDirect(); - delegate->OnResolveProxy(GURL(kHttpUrl), - net::NetworkAnonymizationKey::CreateCrossSite( - net::SchemefulSite(GURL("http://top.com"))), - "GET", net::ProxyRetryInfoMap(), &result); - EXPECT_FALSE(result.is_direct()); - EXPECT_TRUE(result.is_for_ip_protection()); -} - -// When a `config` does look like an IP Protection `CustomProxyConfig` and the -// URLs match the allow list, and a token is available, the result is flagged as -// for IP protection and is not direct. -TEST_F(NetworkServiceProxyDelegateTest, - OnResolveProxyIpProtectionHttpsSuccess) { - auto config = - NetworkServiceProxyAllowList::MakeIpProtectionCustomProxyConfig(); - std::map<std::string, std::set<std::string>> first_party_map; - first_party_map["example.com"] = {}; - auto network_service_proxy_allow_list = - NetworkServiceProxyAllowList::CreateForTesting(first_party_map); - auto delegate = - CreateDelegate(std::move(config), &network_service_proxy_allow_list); - - auto ipp_config_cache = std::make_unique<MockIpProtectionConfigCache>(); - ipp_config_cache->SetNextAuthToken(MakeAuthToken("Bearer: a-token")); - ipp_config_cache->SetProxyList({{"proxy"}}); - delegate->SetIpProtectionConfigCache(std::move(ipp_config_cache)); - - net::ProxyInfo result; - result.UseDirect(); - delegate->OnResolveProxy(GURL(kHttpsUrl), - net::NetworkAnonymizationKey::CreateCrossSite( - net::SchemefulSite(GURL("https://top.com"))), - "GET", net::ProxyRetryInfoMap(), &result); - EXPECT_FALSE(result.is_direct()); - EXPECT_TRUE(result.is_for_ip_protection()); -} - TEST_F(NetworkServiceProxyDelegateTest, InitialConfigUsedForProxy) { auto config = mojom::CustomProxyConfig::New(); config->rules.ParseFromString("http=foo"); mojo::Remote<mojom::CustomProxyConfigClient> client; auto delegate = std::make_unique<NetworkServiceProxyDelegate>( std::move(config), client.BindNewPipeAndPassReceiver(), - mojo::NullRemote(), nullptr); + mojo::NullRemote()); net::ProxyInfo result; result.UseDirect(); @@ -1118,26 +555,6 @@ EXPECT_EQ(TestObserver()->FallbackArgs()->second, net::ERR_FAILED); } -TEST_F(NetworkServiceProxyDelegateTest, OnFallback_IpProtection) { - auto ip_protection_proxy_chain = - net::ProxyChain::FromSchemeHostAndPort(net::ProxyServer::SCHEME_HTTPS, - "proxy.com", absl::nullopt) - .ForIpProtection(); - bool force_refresh_called = false; - - auto config = mojom::CustomProxyConfig::New(); - auto delegate = CreateDelegate(std::move(config)); - - auto ipp_config_cache = std::make_unique<MockIpProtectionConfigCache>(); - ipp_config_cache->SetOnRequestRefreshProxyList( - base::BindLambdaForTesting([&]() { force_refresh_called = true; })); - ipp_config_cache->SetProxyList({{"proxy.com"}}); - delegate->SetIpProtectionConfigCache(std::move(ipp_config_cache)); - - delegate->OnFallback(ip_protection_proxy_chain, net::ERR_FAILED); - EXPECT_TRUE(force_refresh_called); -} - TEST_F(NetworkServiceProxyDelegateTest, OnTunnelHeadersReceivedObserved) { net::ProxyChain proxy_chain({ net::ProxyServer(net::ProxyServer::SCHEME_HTTP,
diff --git a/services/on_device_model/ml/chrome_ml.cc b/services/on_device_model/ml/chrome_ml.cc index f3e0958..1175ee4 100644 --- a/services/on_device_model/ml/chrome_ml.cc +++ b/services/on_device_model/ml/chrome_ml.cc
@@ -67,8 +67,8 @@ kMaxValue = kDxgiErrorDeviceRemoved, }; -void FatalErrorFn(const char* msg) { - SCOPED_CRASH_KEY_STRING1024("ChromeML", "error_msg", msg); +void FatalGpuErrorFn(const char* msg) { + SCOPED_CRASH_KEY_STRING1024("ChromeML(GPU)", "error_msg", msg); std::string msg_str(msg); GpuErrorReason error_reason = GpuErrorReason::kOther; if (msg_str.find("DXGI_ERROR_DEVICE_HUNG") != std::string::npos) { @@ -79,12 +79,17 @@ base::UmaHistogramEnumeration("OnDeviceModel.GpuErrorReason", error_reason); if (error_reason == GpuErrorReason::kOther) { // Collect crash reports on unknown errors. - CHECK(false) << "ChromeML Error: " << msg; + CHECK(false) << "ChromeML(GPU) Error: " << msg; } else { base::Process::TerminateCurrentProcessImmediately(0); } } +void FatalErrorFn(const char* msg) { + SCOPED_CRASH_KEY_STRING1024("ChromeML", "error_msg", msg); + CHECK(false) << "ChromeML Error: " << msg; +} + } // namespace ChromeML::ChromeML(base::PassKey<ChromeML>, @@ -149,7 +154,10 @@ api->InitDawnProcs(dawn::native::GetProcs()); if (api->SetFatalErrorFn) { - api->SetFatalErrorFn(&FatalErrorFn); + api->SetFatalErrorFn(&FatalGpuErrorFn); + } + if (api->SetFatalErrorNonGpuFn) { + api->SetFatalErrorNonGpuFn(&FatalErrorFn); } return std::make_unique<ChromeML>(base::PassKey<ChromeML>(), std::move(scoped_library), api);
diff --git a/services/on_device_model/ml/chrome_ml_api.h b/services/on_device_model/ml/chrome_ml_api.h index fd2004b..d52889c 100644 --- a/services/on_device_model/ml/chrome_ml_api.h +++ b/services/on_device_model/ml/chrome_ml_api.h
@@ -211,7 +211,8 @@ // functions. void (*InitDawnProcs)(const DawnProcTable& procs); - // Sets an error handling function for fatal errors. + // Sets an error handling function for fatal errors in the GPU. See also + // SetFatalErrorNonGpuFn. void (*SetFatalErrorFn)(ChromeMLFatalErrorFn error_fn) = nullptr; // Creates a new ChromeML model instance as described by `model`. The returned @@ -238,6 +239,10 @@ // Returns the GpuConfig in `config`. Returns true on success, false if there // was an error calculating it. bool (*GetGpuConfig)(GpuConfig& config); + + // Same as SetFatalErrorFn(), but for fatal errors that occur outside of the + // gpu. + void (*SetFatalErrorNonGpuFn)(ChromeMLFatalErrorFn error_fn) = nullptr; }; // Signature of the GetChromeMLAPI() function which the shared library exports.
diff --git a/sql/recovery.cc b/sql/recovery.cc index 97f7318..4c3be723 100644 --- a/sql/recovery.cc +++ b/sql/recovery.cc
@@ -94,6 +94,7 @@ ? !BuiltInRecovery::ShouldAttemptRecovery(database, extended_error) : !database || !database->is_open() || database->DbPath(InternalApiToken()).empty() || + database->UseWALMode() || !Recovery::ShouldRecover(extended_error)) { return false; }
diff --git a/sql/recovery.h b/sql/recovery.h index e8a24250..93fedc7 100644 --- a/sql/recovery.h +++ b/sql/recovery.h
@@ -22,8 +22,15 @@ namespace sql { -// Recovery module for sql/. Please see the `RecoverIfPossible()` method for -// how to use this class. +// Recovery module for sql/. Please see the `RecoverIfPossible()` method for how +// to use this class. +// +// This module is capable of recovering databases which the legacy recovery +// module could not recover. These include: +// - tables with the WITHOUT ROWID optimization +// - databases which use Write-Ahead Log (i.e. WAL mode) +// - NOTE: as WAL mode is still experimental (see https://crbug.com/1416213) +// recovery should not be attempted on WAL databases for now. // // Uses SQLite's recovery extension: https://www.sqlite.org/recovery.html class COMPONENT_EXPORT(SQL) BuiltInRecovery {
diff --git a/sql/recovery_unittest.cc b/sql/recovery_unittest.cc index 47650956..5147ba2 100644 --- a/sql/recovery_unittest.cc +++ b/sql/recovery_unittest.cc
@@ -93,6 +93,9 @@ } protected: + explicit SqlRecoveryTestBase(DatabaseOptions options) + : db_(std::move(options)) {} + base::test::ScopedFeatureList scoped_feature_list_; base::ScopedTempDir temp_dir_; base::FilePath db_path_; @@ -102,15 +105,29 @@ // Tests both the legacy `sql::Recovery` interface and the newer // `sql::BuiltInRecovery` interface, if it's supported. -class SqlRecoveryTest : public SqlRecoveryTestBase, - public testing::WithParamInterface<bool> { +// +// Parameters are as follows: +// - Is BuiltInRecovery enabled? +// - Is WAL mode enabled? +class SqlRecoveryTest + : public SqlRecoveryTestBase, + public testing::WithParamInterface<std::tuple<bool, bool>> { public: - SqlRecoveryTest() { - scoped_feature_list_.InitWithFeatureState( - features::kUseBuiltInRecoveryIfSupported, GetParam()); + SqlRecoveryTest() + : SqlRecoveryTestBase(DatabaseOptions{.wal_mode = UseWalMode()}) { + scoped_feature_list_.InitWithFeatureStates( + {{features::kUseBuiltInRecoveryIfSupported, std::get<0>(GetParam())}, + {features::kEnableWALModeByDefault, UseWalMode()}}); } - bool UseBuiltIn() { return GetParam() && BuiltInRecovery::IsSupported(); } + bool UseBuiltIn() { + return std::get<0>(GetParam()) && BuiltInRecovery::IsSupported(); + } + + bool UseWalMode() { + // The legacy recovery module does not support recovering WAL databases. + return std::get<1>(GetParam()) && BuiltInRecovery::IsSupported(); + } }; // Tests specific to the newer `sql::BuiltInRecovery` interface. @@ -120,7 +137,7 @@ // the legacy `sql::Recovery` module. class SqlBuiltInRecoveryTest : public SqlRecoveryTestBase { public: - SqlBuiltInRecoveryTest() { + SqlBuiltInRecoveryTest() : SqlRecoveryTestBase(DatabaseOptions{}) { scoped_feature_list_.InitAndEnableFeature( features::kUseBuiltInRecoveryIfSupported); } @@ -133,9 +150,17 @@ // the new `sql::BuiltInRecovery` module. class SqlLegacyRecoveryTest : public SqlRecoveryTestBase { public: - SqlLegacyRecoveryTest() { + SqlLegacyRecoveryTest() + // The legacy recovery module does not support recovering WAL databases. + : SqlRecoveryTestBase(DatabaseOptions{.wal_mode = false}) { scoped_feature_list_.InitAndDisableFeature( features::kUseBuiltInRecoveryIfSupported); + + // TODO(https://crbug.com/1385500): All databases which use legacy recovery + // must either disable WAL mode manually or be migrated to the new recovery + // module before WAL mode may be turned on globally. This assertion is added + // here as a guard against accidental regression. + assert(!base::FeatureList::IsEnabled(features::kEnableWALModeByDefault)); } }; @@ -1328,15 +1353,15 @@ ASSERT_TRUE(sql::test::CorruptIndexRootPage(db_path_, "rows_index")); ASSERT_TRUE(Reopen()); - // Run recovery code, then rollback. Database remains the same. - { + if (!UseBuiltIn()) { + // Run recovery code, then rollback. Database remains the same. std::unique_ptr<Recovery> recovery = Recovery::BeginRecoverDatabase(&db_, db_path_); ASSERT_TRUE(recovery); Recovery::Rollback(std::move(recovery)); + db_.Close(); + ASSERT_TRUE(Reopen()); } - db_.Close(); - ASSERT_TRUE(Reopen()); static const char kIndexedCountSql[] = "SELECT SUM(indexed) FROM rows INDEXED BY rows_index"; @@ -1547,9 +1572,56 @@ IsSqliteSuccessCode(BuiltInRecovery::RecoverDatabase( &db_, BuiltInRecovery::Strategy::kRecoverOrRaze))); } + +// This test mimics the case where a database that was using WAL mode crashed, +// then next Chrome launch the database is not opened in WAL mode. This may +// occur when e.g. WAL mode if configured via Finch and the user not in the +// experiment group on the second launch of Chrome. +TEST_F(SqlBuiltInRecoveryTest, PRE_RecoverFormerlyWalDbAfterCrash) { + base::FilePath wal_db_path = + temp_dir_.GetPath().AppendASCII("recovery_wal_test.sqlite"); + + // Open the DB in WAL mode to set journal_mode="wal". + Database wal_db{{.wal_mode = true}}; + ASSERT_TRUE(wal_db.Open(wal_db_path)); + + EXPECT_TRUE(wal_db.UseWALMode()); + EXPECT_EQ(ExecuteWithResult(&wal_db, "PRAGMA journal_mode"), "wal"); + + // Crash the database somehow, foregoing the opportunity for any cleanup. + wal_db.set_error_callback(base::DoNothing()); + EXPECT_DCHECK_DEATH(wal_db.set_error_callback(base::DoNothing())); +} + +TEST_F(SqlBuiltInRecoveryTest, RecoverFormerlyWalDbAfterCrash) { + base::FilePath wal_db_path = + temp_dir_.GetPath().AppendASCII("recovery_wal_test.sqlite"); + + Database non_wal_db{{.wal_mode = false}}; + ASSERT_TRUE(non_wal_db.Open(wal_db_path)); + + auto run_recovery = base::BindLambdaForTesting([&]() { + EXPECT_EQ(BuiltInRecovery::RecoverDatabase( + &non_wal_db, + BuiltInRecovery::Strategy::kRecoverWithMetaVersionOrRaze), + SqliteResultCode::kOk); + }); + + TestRecoverDatabase(non_wal_db, wal_db_path, /*with_meta=*/true, + std::move(run_recovery)); +} + #endif // !BUILDFLAG(IS_FUCHSIA) -INSTANTIATE_TEST_SUITE_P(All, SqlRecoveryTest, testing::Bool()); +INSTANTIATE_TEST_SUITE_P( + All, + SqlRecoveryTest, + testing::Values( + std::tuple(true, true), // BuiltInRecovery with WAL databases. + std::tuple(true, false), // BuiltInRecovery with non-WAL databases. + std::tuple(false, false) // Legacy recovery with non-WAL databases. + // The legacy recovery module does not support recovering WAL databases. + )); } // namespace
diff --git a/testing/buildbot/filters/ios.use_blink.components_unittests.filter b/testing/buildbot/filters/ios.use_blink.components_unittests.filter index 812d693f..1865832d 100644 --- a/testing/buildbot/filters/ios.use_blink.components_unittests.filter +++ b/testing/buildbot/filters/ios.use_blink.components_unittests.filter
@@ -1,9 +1,11 @@ # TODO(crbug.com/1427365): remove lines as more tests are supported on the platform. -# TODO(crbug.com/1505584): currently fail with use_blink. +# TODO(crbug.com/1505584): currently fail with use_blink due to spinning up on +# an unexpected thread. -AutofillAcrossIframesTest.FeatureDisabled -AutofillAcrossIframesTest.NoChildFrames -AutofillAcrossIframesTest.WithChildFrames +-AutofillAcrossIframesTest.Resolve # TODO(crbug.com/1505321): Test currently fails on iOS blink. -AutofillAgentTests.OnFormDataFilledTestWithFrameMessagingUsingRendererIDs
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index 2bbc9e1..464fba67 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -3425,6 +3425,25 @@ ] } ], + "ChromeCompose": [ + { + "platforms": [ + "linux", + "mac", + "windows" + ], + "experiments": [ + { + "name": "Enabled", + "enable_features": [ + "AutofillContentEditables", + "Compose", + "ComposeNudge" + ] + } + ] + } + ], "ChromeLabs": [ { "platforms": [ @@ -12294,22 +12313,6 @@ ] } ], - "OnBeginFrameThrottleVideo": [ - { - "platforms": [ - "android", - "android_webview" - ], - "experiments": [ - { - "name": "Enabled_08072023", - "enable_features": [ - "OnBeginFrameThrottleVideo" - ] - } - ] - } - ], "OneCopyLegacyMPVideoFrameUploadViaSI": [ { "platforms": [ @@ -14509,6 +14512,7 @@ { "name": "Enabled", "enable_features": [ + "FledgeDelayPostAuctionInterestGroupUpdate", "FledgeUseInterestGroupCache" ] }
diff --git a/third_party/angle b/third_party/angle index 92bd009..2937ee2 160000 --- a/third_party/angle +++ b/third_party/angle
@@ -1 +1 @@ -Subproject commit 92bd0099204c0b5e8c6daecff9c691b895b87433 +Subproject commit 2937ee276cf5bd27fd5254091abdcf1e68a4155b
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc index 2915b16..8813d13 100644 --- a/third_party/blink/common/features.cc +++ b/third_party/blink/common/features.cc
@@ -314,6 +314,23 @@ const base::FeatureParam<int> kBoostImagePriorityTightMediumLimit{ &kBoostImagePriority, "tight_medium_limit", 2}; +// Boost the priority of certain loading tasks (https://crbug.com/1470003). +BASE_FEATURE(kBoostImageSetLoadingTaskPriority, + "BoostImageSetLoadingTaskPriority", + base::FEATURE_DISABLED_BY_DEFAULT); +BASE_FEATURE(kBoostFontLoadingTaskPriority, + "BoostFontLoadingTaskPriority", + base::FEATURE_DISABLED_BY_DEFAULT); +BASE_FEATURE(kBoostVideoLoadingTaskPriority, + "BoostVideoLoadingTaskPriority", + base::FEATURE_DISABLED_BY_DEFAULT); +BASE_FEATURE(kBoostRenderBlockingStyleLoadingTaskPriority, + "BoostRenderBlockingStyleLoadingTaskPriority", + base::FEATURE_DISABLED_BY_DEFAULT); +BASE_FEATURE(kBoostNonRenderBlockingStyleLoadingTaskPriority, + "BoostNonRenderBlockingStyleLoadingTaskPriority", + base::FEATURE_DISABLED_BY_DEFAULT); + // https://github.com/patcg-individual-drafts/topics // Kill switch for the Topics API. BASE_FEATURE(kBrowsingTopics,
diff --git a/third_party/blink/public/common/features.h b/third_party/blink/public/common/features.h index db5c80aa..3843fe53 100644 --- a/third_party/blink/public/common/features.h +++ b/third_party/blink/public/common/features.h
@@ -186,6 +186,15 @@ BLINK_COMMON_EXPORT extern const base::FeatureParam<int> kBoostImagePriorityTightMediumLimit; +// Boost the priority of certain loading tasks (https://crbug.com/1470003). +BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kBoostImageSetLoadingTaskPriority); +BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kBoostFontLoadingTaskPriority); +BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kBoostVideoLoadingTaskPriority); +BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE( + kBoostRenderBlockingStyleLoadingTaskPriority); +BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE( + kBoostNonRenderBlockingStyleLoadingTaskPriority); + BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kBrowsingTopics); BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE( kBrowsingTopicsBypassIPIsPubliclyRoutableCheck);
diff --git a/third_party/blink/public/mojom/frame/frame.mojom b/third_party/blink/public/mojom/frame/frame.mojom index 4a347a9..6304eaf 100644 --- a/third_party/blink/public/mojom/frame/frame.mojom +++ b/third_party/blink/public/mojom/frame/frame.mojom
@@ -399,6 +399,11 @@ UpdateTitle(mojo_base.mojom.String16? title, mojo_base.mojom.TextDirection title_direction); + // Updates the app title for a document. If non-empty, a web app displayed in an app + // window may use this string instead of the regular title. + // See https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/DocumentSubtitle/explainer.md + UpdateAppTitle(mojo_base.mojom.String16 app_title); + // Indicates that the user activation state in the current frame has been // updated, so the replicated states need to be synced (in the browser process // as well as in all other renderer processes).
diff --git a/third_party/blink/public/platform/platform.h b/third_party/blink/public/platform/platform.h index 7d91ca0..fc43276 100644 --- a/third_party/blink/public/platform/platform.h +++ b/third_party/blink/public/platform/platform.h
@@ -33,6 +33,7 @@ #include <memory> #include <string> +#include <string_view> #include <tuple> #include <vector> @@ -223,9 +224,7 @@ // Returns the hash for the given canonicalized URL for use in visited // link coloring. - virtual uint64_t VisitedLinkHash(const char* canonical_url, size_t length) { - return 0; - } + virtual uint64_t VisitedLinkHash(std::string_view canonical_url) { return 0; } // Returns whether the given link hash is in the user's history. The // hash must have been generated by calling VisitedLinkHash().
diff --git a/third_party/blink/public/platform/task_type.h b/third_party/blink/public/platform/task_type.h index 9b303c8..ccd3a060 100644 --- a/third_party/blink/public/platform/task_type.h +++ b/third_party/blink/public/platform/task_type.h
@@ -53,9 +53,11 @@ // This is a part of Networking task that should not be frozen when a page is // frozen. kNetworkingUnfreezable = 75, - // Tasks associated with image loading. Split off from kNetworkingUnfreezable - // so image loading tasks can be prioritized. - kNetworkingUnfreezableImageLoading = 83, + // Tasks associated with loading that should also block rendering. Split off + // from kNetworkingUnfreezable so tasks such as image loading can be + // prioritized above rendering. Note that not all render-blocking resources + // use this queue (e.g., script load tasks are not put here). + kNetworkingUnfreezableRenderBlockingLoading = 83, // This task source is used for control messages between kNetworking tasks. kNetworkingControl = 4, // Tasks used to run low priority scripts.
diff --git a/third_party/blink/renderer/core/BUILD.gn b/third_party/blink/renderer/core/BUILD.gn index d9349048b..a979a463 100644 --- a/third_party/blink/renderer/core/BUILD.gn +++ b/third_party/blink/renderer/core/BUILD.gn
@@ -1498,6 +1498,7 @@ sources += rebase_path(blink_core_tests_execution_context, "", "execution_context") sources += rebase_path(blink_core_tests_fetch, "", "fetch") + sources += rebase_path(blink_core_tests_fileapi, "", "fileapi") sources += rebase_path(blink_core_tests_frame, "", "frame") sources += rebase_path(blink_core_tests_fullscreen, "", "fullscreen") sources += rebase_path(blink_core_tests_geometry, "", "geometry")
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc index de3db04..3bf7f53 100644 --- a/third_party/blink/renderer/core/dom/document.cc +++ b/third_party/blink/renderer/core/dom/document.cc
@@ -7747,6 +7747,25 @@ return absl::nullopt; } +void Document::UpdateAppTitle() { + auto* root_element = documentElement(); + if (!root_element) { + return; + } + + for (HTMLMetaElement& meta_element : + Traversal<HTMLMetaElement>::DescendantsOf(*root_element)) { + if (EqualIgnoringASCIICase(meta_element.GetName(), "app-title")) { + GetFrame()->GetLocalFrameHostRemote().UpdateAppTitle( + meta_element.Content().GetString()); + return; + } + } + + // Handle case of meta tag being removed by setting app title to empty string. + GetFrame()->GetLocalFrameHostRemote().UpdateAppTitle(String("")); +} + void Document::ColorSchemeMetaChanged() { const CSSValue* color_scheme = nullptr; if (auto* root_element = documentElement()) {
diff --git a/third_party/blink/renderer/core/dom/document.h b/third_party/blink/renderer/core/dom/document.h index 13f49dd9..89f7857 100644 --- a/third_party/blink/renderer/core/dom/document.h +++ b/third_party/blink/renderer/core/dom/document.h
@@ -2016,6 +2016,9 @@ // it. bool HasAtLeastOneDataList() const { return data_list_count_; } + // Updates app title based to the latest app title meta tag value. + void UpdateAppTitle(); + void ResetAgent(Agent& agent); bool SupportsLegacyDOMMutations();
diff --git a/third_party/blink/renderer/core/editing/ime/input_method_controller.cc b/third_party/blink/renderer/core/editing/ime/input_method_controller.cc index 7b3a50a0..61df215 100644 --- a/third_party/blink/renderer/core/editing/ime/input_method_controller.cc +++ b/third_party/blink/renderer/core/editing/ime/input_method_controller.cc
@@ -58,6 +58,7 @@ #include "third_party/blink/renderer/core/frame/local_dom_window.h" #include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/frame/local_frame_client.h" +#include "third_party/blink/renderer/core/html/canvas/html_canvas_element.h" #include "third_party/blink/renderer/core/html/forms/html_input_element.h" #include "third_party/blink/renderer/core/html/forms/html_text_area_element.h" #include "third_party/blink/renderer/core/input/event_handler.h" @@ -1826,6 +1827,16 @@ } WebTextInputType InputMethodController::TextInputType() const { + // Since selection can never go inside a <canvas> element, if the user is + // editing inside a <canvas> with EditContext we need to handle that case + // directly before looking at the selection position. + if (GetActiveEditContext()) { + Element* element = GetDocument().FocusedElement(); + if (IsA<HTMLCanvasElement>(*element)) { + return kWebTextInputTypeContentEditable; + } + } + if (!GetFrame().Selection().IsAvailable()) { // "mouse-capture-inside-shadow.html" reaches here. return kWebTextInputTypeNone;
diff --git a/third_party/blink/renderer/core/editing/ime/input_method_controller_test.cc b/third_party/blink/renderer/core/editing/ime/input_method_controller_test.cc index 40777759..c6371e0c 100644 --- a/third_party/blink/renderer/core/editing/ime/input_method_controller_test.cc +++ b/third_party/blink/renderer/core/editing/ime/input_method_controller_test.cc
@@ -3719,4 +3719,23 @@ GetSelectionTextFromBody()); } +TEST_F(InputMethodControllerTest, EditContextCanvasHasEditableType) { + GetDocument().GetSettings()->SetScriptEnabled(true); + Element* noneditable_canvas = InsertHTMLElement( + "<canvas id='noneditable-canvas'></canvas>", "noneditable-canvas"); + Element* editable_canvas = InsertHTMLElement( + "<canvas id='editable-canvas'></canvas>", "editable-canvas"); + Element* script = GetDocument().CreateRawElement(html_names::kScriptTag); + script->setInnerHTML( + "document.getElementById('editable-canvas').editContext = new " + "EditContext()"); + GetDocument().body()->AppendChild(script); + UpdateAllLifecyclePhasesForTest(); + + noneditable_canvas->Focus(); + EXPECT_EQ(kWebTextInputTypeNone, Controller().TextInputType()); + + editable_canvas->Focus(); + EXPECT_EQ(kWebTextInputTypeContentEditable, Controller().TextInputType()); +} } // namespace blink
diff --git a/third_party/blink/renderer/core/fileapi/file_list_test.cc b/third_party/blink/renderer/core/fileapi/file_list_test.cc index 45082d13..d3019cf 100644 --- a/third_party/blink/renderer/core/fileapi/file_list_test.cc +++ b/third_party/blink/renderer/core/fileapi/file_list_test.cc
@@ -10,10 +10,12 @@ #include "third_party/blink/renderer/core/testing/null_execution_context.h" #include "third_party/blink/renderer/platform/blob/blob_data.h" #include "third_party/blink/renderer/platform/file_metadata.h" +#include "third_party/blink/renderer/platform/testing/task_environment.h" namespace blink { TEST(FileListTest, pathsForUserVisibleFiles) { + test::TaskEnvironment task_environment; ScopedNullExecutionContext context; auto* const file_list = MakeGarbageCollected<FileList>();
diff --git a/third_party/blink/renderer/core/fileapi/file_test.cc b/third_party/blink/renderer/core/fileapi/file_test.cc index e0ccab8b..f9a5f34 100644 --- a/third_party/blink/renderer/core/fileapi/file_test.cc +++ b/third_party/blink/renderer/core/fileapi/file_test.cc
@@ -24,6 +24,7 @@ #include "third_party/blink/renderer/platform/file_metadata.h" #include "third_party/blink/renderer/platform/heap/garbage_collected.h" #include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h" +#include "third_party/blink/renderer/platform/testing/task_environment.h" #include "third_party/blink/renderer/platform/wtf/cross_thread_copier_base.h" #include "third_party/blink/renderer/platform/wtf/cross_thread_copier_mojo.h" #include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h" @@ -176,6 +177,7 @@ } // namespace TEST(FileTest, NativeFileWithoutTimestamp) { + test::TaskEnvironment task_environment; ScopedNullExecutionContext context; auto* const file = MakeGarbageCollected<File>(&context.GetExecutionContext(), "/native/path"); @@ -188,6 +190,7 @@ } TEST(FileTest, NativeFileWithUnixEpochTimestamp) { + test::TaskEnvironment task_environment; ScopedNullExecutionContext context; auto* const file = MakeGarbageCollected<File>(&context.GetExecutionContext(), "/native/path"); @@ -199,6 +202,7 @@ } TEST(FileTest, NativeFileWithApocalypseTimestamp) { + test::TaskEnvironment task_environment; ScopedNullExecutionContext context; auto* const file = MakeGarbageCollected<File>(&context.GetExecutionContext(), "/native/path"); @@ -212,6 +216,7 @@ } TEST(FileTest, BlobBackingFileWithoutTimestamp) { + test::TaskEnvironment task_environment; auto* const file = MakeGarbageCollected<File>("name", absl::nullopt, BlobDataHandle::Create()); EXPECT_FALSE(file->HasBackingFile()); @@ -221,6 +226,7 @@ } TEST(FileTest, BlobBackingFileWithWindowsEpochTimestamp) { + test::TaskEnvironment task_environment; auto* const file = MakeGarbageCollected<File>("name", base::Time(), BlobDataHandle::Create()); EXPECT_FALSE(file->HasBackingFile()); @@ -232,6 +238,7 @@ } TEST(FileTest, BlobBackingFileWithUnixEpochTimestamp) { + test::TaskEnvironment task_environment; const scoped_refptr<BlobDataHandle> blob_data_handle = BlobDataHandle::Create(); auto* const file = MakeGarbageCollected<File>("name", base::Time::UnixEpoch(), @@ -244,6 +251,7 @@ } TEST(FileTest, BlobBackingFileWithApocalypseTimestamp) { + test::TaskEnvironment task_environment; constexpr base::Time kMaxTime = base::Time::Max(); auto* const file = MakeGarbageCollected<File>("name", kMaxTime, BlobDataHandle::Create()); @@ -256,6 +264,7 @@ } TEST(FileTest, fileSystemFileWithNativeSnapshot) { + test::TaskEnvironment task_environment; ScopedNullExecutionContext context; FileMetadata metadata; metadata.platform_path = "/native/snapshot"; @@ -267,6 +276,7 @@ } TEST(FileTest, fileSystemFileWithNativeSnapshotAndSize) { + test::TaskEnvironment task_environment; ScopedNullExecutionContext context; FileMetadata metadata; metadata.length = 1024ll; @@ -279,6 +289,7 @@ } TEST(FileTest, FileSystemFileWithWindowsEpochTimestamp) { + test::TaskEnvironment task_environment; ScopedNullExecutionContext context; FileMetadata metadata; metadata.length = INT64_C(1025); @@ -296,6 +307,7 @@ } TEST(FileTest, FileSystemFileWithUnixEpochTimestamp) { + test::TaskEnvironment task_environment; ScopedNullExecutionContext context; FileMetadata metadata; metadata.length = INT64_C(1025); @@ -312,6 +324,7 @@ } TEST(FileTest, FileSystemFileWithApocalypseTimestamp) { + test::TaskEnvironment task_environment; ScopedNullExecutionContext context; constexpr base::Time kMaxTime = base::Time::Max(); FileMetadata metadata; @@ -330,6 +343,7 @@ } TEST(FileTest, fileSystemFileWithoutNativeSnapshot) { + test::TaskEnvironment task_environment; KURL url("filesystem:http://example.com/isolated/hash/non-native-file"); FileMetadata metadata; metadata.length = 0; @@ -341,6 +355,7 @@ } TEST(FileTest, hsaSameSource) { + test::TaskEnvironment task_environment; ScopedNullExecutionContext context; auto* const native_file_a1 = MakeGarbageCollected<File>( &context.GetExecutionContext(), "/native/pathA"); @@ -388,6 +403,7 @@ } TEST(FileTest, createForFileSystem) { + test::TaskEnvironment task_environment; V8TestingScope scope(KURL("http://example.com")); Document& document = scope.GetDocument(); base::RunLoop run_loop;
diff --git a/third_party/blink/renderer/core/fileapi/public_url_manager_test.cc b/third_party/blink/renderer/core/fileapi/public_url_manager_test.cc index 6e34ccd..50f7bb2 100644 --- a/third_party/blink/renderer/core/fileapi/public_url_manager_test.cc +++ b/third_party/blink/renderer/core/fileapi/public_url_manager_test.cc
@@ -19,6 +19,7 @@ #include "third_party/blink/renderer/platform/blob/testing/fake_blob_url_store.h" #include "third_party/blink/renderer/platform/heap/persistent.h" #include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h" +#include "third_party/blink/renderer/platform/testing/task_environment.h" #include "third_party/blink/renderer/platform/weborigin/security_origin.h" namespace blink { @@ -125,6 +126,8 @@ } protected: + test::TaskEnvironment task_environment_; + PublicURLManagerTestCase test_case_; base::test::ScopedFeatureList scoped_feature_list_;
diff --git a/third_party/blink/renderer/core/frame/local_frame_view.cc b/third_party/blink/renderer/core/frame/local_frame_view.cc index 8cb1426..b6d0db6 100644 --- a/third_party/blink/renderer/core/frame/local_frame_view.cc +++ b/third_party/blink/renderer/core/frame/local_frame_view.cc
@@ -2005,8 +2005,6 @@ if (!resize_controller) return false; - DCHECK(Lifecycle().GetState() >= DocumentLifecycle::kPrePaintClean); - size_t min_depth = resize_controller->GatherObservations(); if (min_depth != ResizeObserverController::kDepthBottom) {
diff --git a/third_party/blink/renderer/core/html/custom/element_internals.cc b/third_party/blink/renderer/core/html/custom/element_internals.cc index 78a37b1..56e9124a 100644 --- a/third_party/blink/renderer/core/html/custom/element_internals.cc +++ b/third_party/blink/renderer/core/html/custom/element_internals.cc
@@ -334,6 +334,10 @@ void ElementInternals::SetElementAttribute(const QualifiedName& name, Element* element) { + if (!element) { + explicitly_set_attr_elements_map_.erase(name); + return; + } auto result = explicitly_set_attr_elements_map_.insert(name, nullptr); if (result.is_new_entry) { result.stored_value->value =
diff --git a/third_party/blink/renderer/core/html/html_meta_element.cc b/third_party/blink/renderer/core/html/html_meta_element.cc index 73c80be..53c6e6c 100644 --- a/third_party/blink/renderer/core/html/html_meta_element.cc +++ b/third_party/blink/renderer/core/html/html_meta_element.cc
@@ -547,6 +547,9 @@ EqualIgnoringASCIICase(name_value, "view-transition")) { ViewTransitionSupplement::From(GetDocument()) ->OnMetaTagChanged(g_null_atom); + } else if (RuntimeEnabledFeatures::AppTitleEnabled() && + EqualIgnoringASCIICase(name_value, "app-title")) { + GetDocument().UpdateAppTitle(); } } @@ -724,6 +727,9 @@ EqualIgnoringASCIICase(name_value, "view-transition")) { ViewTransitionSupplement::From(GetDocument()) ->OnMetaTagChanged(content_value); + } else if (RuntimeEnabledFeatures::AppTitleEnabled() && + EqualIgnoringASCIICase(name_value, "app-title")) { + GetDocument().UpdateAppTitle(); } }
diff --git a/third_party/blink/renderer/core/testing/fake_local_frame_host.cc b/third_party/blink/renderer/core/testing/fake_local_frame_host.cc index 48944ec9..974a3057 100644 --- a/third_party/blink/renderer/core/testing/fake_local_frame_host.cc +++ b/third_party/blink/renderer/core/testing/fake_local_frame_host.cc
@@ -112,6 +112,8 @@ const WTF::String& title, base::i18n::TextDirection title_direction) {} +void FakeLocalFrameHost::UpdateAppTitle(const WTF::String& app_title) {} + void FakeLocalFrameHost::UpdateUserActivationState( mojom::blink::UserActivationUpdateType update_type, mojom::UserActivationNotificationType notification_type) {}
diff --git a/third_party/blink/renderer/core/testing/fake_local_frame_host.h b/third_party/blink/renderer/core/testing/fake_local_frame_host.h index 6334fe6..d4ef3eb 100644 --- a/third_party/blink/renderer/core/testing/fake_local_frame_host.h +++ b/third_party/blink/renderer/core/testing/fake_local_frame_host.h
@@ -84,6 +84,7 @@ void NavigateEventHandlerPresenceChanged(bool present) override {} void UpdateTitle(const WTF::String& title, base::i18n::TextDirection title_direction) override; + void UpdateAppTitle(const WTF::String& app_title) override; void UpdateUserActivationState( mojom::blink::UserActivationUpdateType update_type, mojom::UserActivationNotificationType notification_type) override;
diff --git a/third_party/blink/renderer/core/timing/soft_navigation_heuristics.cc b/third_party/blink/renderer/core/timing/soft_navigation_heuristics.cc index 092aae3..9f125a44 100644 --- a/third_party/blink/renderer/core/timing/soft_navigation_heuristics.cc +++ b/third_party/blink/renderer/core/timing/soft_navigation_heuristics.cc
@@ -120,11 +120,11 @@ void SoftNavigationHeuristics::ResetHeuristic() { // Reset previously seen indicators and task IDs. - potential_soft_navigation_task_ids_.clear(); + has_potential_soft_navigation_task_ = false; + potential_soft_navigation_tasks_.clear(); interaction_task_id_to_interaction_data_.clear(); last_interaction_task_id_ = 0; last_soft_navigation_ancestor_task_ = absl::nullopt; - disposed_soft_navigation_tasks_ = 0; soft_navigation_descendant_cache_.clear(); SetIsTrackingSoftNavigationHeuristicsOnDocument(false); did_reset_paints_ = false; @@ -191,7 +191,7 @@ ScriptState* script_state) { using IterationStatus = scheduler::TaskAttributionTracker::IterationStatus; - if (potential_soft_navigation_task_ids_.empty()) { + if (potential_soft_navigation_tasks_.empty()) { return absl::nullopt; } ThreadScheduler* scheduler = ThreadScheduler::Current(); @@ -208,12 +208,11 @@ return cached_result->value; } absl::optional<scheduler::TaskAttributionId> ancestor_task_id; - // Check if any of `potential_soft_navigation_task_ids_` is an ancestor of + // Check if any of `potential_soft_navigation_tasks_` is an ancestor of // `task`. tracker->ForEachAncestor( *task, [&](const scheduler::TaskAttributionInfo& ancestor) { - if (potential_soft_navigation_task_ids_.Contains( - ancestor.Id().value())) { + if (potential_soft_navigation_tasks_.Contains(&ancestor)) { ancestor_task_id = ancestor.Id(); return IterationStatus::kStop; } @@ -498,6 +497,13 @@ void SoftNavigationHeuristics::Trace(Visitor* visitor) const { Supplement<LocalDOMWindow>::Trace(visitor); + visitor->Trace(potential_soft_navigation_tasks_); + // Register a custom weak callback, which runs after processing weakness for + // the container. This allows us to observe the collection becoming empty + // without needing to observe individual element disposal. + visitor->RegisterWeakCallbackMethod< + SoftNavigationHeuristics, + &SoftNavigationHeuristics::ProcessCustomWeakness>(this); } void SoftNavigationHeuristics::OnCreateTaskScope( @@ -510,12 +516,12 @@ if (!tracker) { return; } - tracker->SetObserverForTaskDisposal(task.Id(), this); // We're inside a click event handler, so need to add this task to the set of // potential soft navigation root tasks. TRACE_EVENT1("scheduler", "SoftNavigationHeuristics::OnCreateTaskScope", "task_id", task.Id().value()); - potential_soft_navigation_task_ids_.insert(task.Id().value()); + potential_soft_navigation_tasks_.insert(&task); + has_potential_soft_navigation_task_ = true; if (!pending_interaction_timestamp_.is_null()) { PerInteractionData data; data.user_interaction_timestamp = pending_interaction_timestamp_; @@ -534,17 +540,18 @@ } } -void SoftNavigationHeuristics::OnTaskDisposal( - const scheduler::TaskAttributionInfo& task) { - if (potential_soft_navigation_task_ids_.Contains(task.Id().value())) { - if (++disposed_soft_navigation_tasks_ >= - potential_soft_navigation_task_ids_.size()) { - // When all the soft navigation tasks were garbage collected, that means - // that all their descendant tasks are done, and there's no need to - // continue searching for soft navigation signals, at least not until the - // next user interaction. - ResetHeuristic(); - } +void SoftNavigationHeuristics::ProcessCustomWeakness( + const LivenessBroker& info) { + // When all the soft navigation tasks were garbage collected, that means that + // all their descendant tasks are done, and there's no need to continue + // searching for soft navigation signals, at least not until the next user + // interaction. + // + // Note: This is not allowed to do Oilpan allocations. If that's needed, this + // can schedule a task or microtask to reset the heuristic. + if (has_potential_soft_navigation_task_ && + potential_soft_navigation_tasks_.empty()) { + ResetHeuristic(); } }
diff --git a/third_party/blink/renderer/core/timing/soft_navigation_heuristics.h b/third_party/blink/renderer/core/timing/soft_navigation_heuristics.h index a1cdeab..1d204ecb 100644 --- a/third_party/blink/renderer/core/timing/soft_navigation_heuristics.h +++ b/third_party/blink/renderer/core/timing/soft_navigation_heuristics.h
@@ -9,6 +9,7 @@ #include "third_party/blink/public/common/scheduler/task_attribution_id.h" #include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/core/frame/local_dom_window.h" +#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h" #include "third_party/blink/renderer/platform/heap/garbage_collected.h" #include "third_party/blink/renderer/platform/scheduler/public/task_attribution_tracker.h" #include "third_party/blink/renderer/platform/supplementable.h" @@ -73,7 +74,6 @@ // TaskAttributionTracker::Observer's implementation. void OnCreateTaskScope(scheduler::TaskAttributionInfo&, ScriptState*) override; - void OnTaskDisposal(const scheduler::TaskAttributionInfo&) override; ExecutionContext* GetExecutionContext() override; void RecordPaint(LocalFrame*, @@ -87,10 +87,19 @@ // current_event_parameters_ and return true. Otherwise, return false. bool PopNestedEventParametersIfNeeded(); + // This method is called during the weakness processing stage of garbage + // collection, and it's used to detect `potential_soft_navigation_tasks_` + // becoming empty. + void ProcessCustomWeakness(const LivenessBroker& info); + bool GetInitialInteractionEncounteredForTest() { return initial_interaction_encountered_; } + scheduler::TaskAttributionIdType GetLastInteractionTaskIdForTest() const { + return last_interaction_task_id_; + } + private: enum FlagType : uint8_t { kURLChange, @@ -124,9 +133,8 @@ PerInteractionData* GetCurrentInteractionData(scheduler::TaskAttributionId); - WTF::HashSet<scheduler::TaskAttributionIdType> - potential_soft_navigation_task_ids_; - size_t disposed_soft_navigation_tasks_ = 0; + HeapHashSet<WeakMember<const scheduler::TaskAttributionInfo>> + potential_soft_navigation_tasks_; WTF::HashMap<scheduler::TaskAttributionIdType, absl::optional<scheduler::TaskAttributionId>> soft_navigation_descendant_cache_; @@ -159,12 +167,15 @@ EventParameters top_event_parameters_; WTF::Deque<EventParameters> nested_event_parameters_; EventParameters* current_event_parameters_ = nullptr; + // Used to synchronize resetting the heuristic when + // `potential_soft_navigation_tasks_` becomes empty during GC. + bool has_potential_soft_navigation_task_ = false; }; // This class defines a scope that would cover click or navigation related // events, in order for the SoftNavigationHeuristics class to be able to keep // track of them and their descendant tasks. -class SoftNavigationEventScope { +class CORE_EXPORT SoftNavigationEventScope { public: SoftNavigationEventScope(SoftNavigationHeuristics* heuristics, SoftNavigationHeuristics::EventScopeType type,
diff --git a/third_party/blink/renderer/core/timing/soft_navigation_heuristics_test.cc b/third_party/blink/renderer/core/timing/soft_navigation_heuristics_test.cc index 64eaab78..691d682 100644 --- a/third_party/blink/renderer/core/timing/soft_navigation_heuristics_test.cc +++ b/third_party/blink/renderer/core/timing/soft_navigation_heuristics_test.cc
@@ -10,9 +10,16 @@ #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h" #include "third_party/blink/renderer/core/testing/dummy_page_holder.h" #include "third_party/blink/renderer/platform/bindings/script_state.h" +#include "third_party/blink/renderer/platform/heap/thread_state.h" +#include "third_party/blink/renderer/platform/scheduler/public/task_attribution_info.h" +#include "third_party/blink/renderer/platform/scheduler/public/task_attribution_tracker.h" +#include "third_party/blink/renderer/platform/scheduler/public/thread_scheduler.h" namespace blink { +using TaskScope = scheduler::TaskAttributionTracker::TaskScope; +using TaskScopeType = scheduler::TaskAttributionTracker::TaskScopeType; + class SoftNavigationHeuristicsTest : public testing::Test { protected: void SetUp() override { @@ -114,4 +121,47 @@ kUserInteractionTsAndReferenceTsBothNotNull, 1); } + +TEST_F(SoftNavigationHeuristicsTest, ResetHeuristicOnSetBecameEmpty) { + auto* heuristics = CreateSoftNavigationHeuristicsForTest(); + ASSERT_TRUE(heuristics); + auto* tracker = ThreadScheduler::Current()->GetTaskAttributionTracker(); + ASSERT_TRUE(tracker); + + auto* script_state = GetScriptStateForTest(); + Persistent<scheduler::TaskAttributionInfo> root_task = nullptr; + // Simulate a click. + { + SoftNavigationEventScope event_scope( + heuristics, SoftNavigationHeuristics::EventScopeType::kClick, + /*is_new_interaction=*/true); + std::unique_ptr<TaskScope> task_scope = tracker->CreateTaskScope( + script_state, /*parent_task=*/nullptr, TaskScopeType::kCallback); + root_task = tracker->RunningTask(script_state); + } + EXPECT_TRUE(root_task); + EXPECT_GT(heuristics->GetLastInteractionTaskIdForTest(), 0u); + + // Simulate a descendant task. + Persistent<scheduler::TaskAttributionInfo> descendant_task = nullptr; + { + std::unique_ptr<TaskScope> task_scope = tracker->CreateTaskScope( + script_state, root_task, TaskScopeType::kCallback); + descendant_task = tracker->RunningTask(script_state); + } + EXPECT_TRUE(descendant_task); + + root_task = nullptr; + ThreadState::Current()->CollectAllGarbageForTesting(); + // The heuristics still should not have been reset since there is a live + // root task, which is being held onto by its descendant task. + EXPECT_GT(heuristics->GetLastInteractionTaskIdForTest(), 0u); + + // Finally, this should allow the click task to be GCed, which should cause + // the heuristics to be reset. + descendant_task = nullptr; + ThreadState::Current()->CollectAllGarbageForTesting(); + EXPECT_EQ(heuristics->GetLastInteractionTaskIdForTest(), 0u); +} + } // namespace blink
diff --git a/third_party/blink/renderer/modules/scheduler/task_attribution_tracker_impl.cc b/third_party/blink/renderer/modules/scheduler/task_attribution_tracker_impl.cc index a9b9a6fc..35192144 100644 --- a/third_party/blink/renderer/modules/scheduler/task_attribution_tracker_impl.cc +++ b/third_party/blink/renderer/modules/scheduler/task_attribution_tracker_impl.cc
@@ -184,23 +184,6 @@ return ScriptWrappableTaskState::GetCurrent(script_state); } -TaskAttributionTracker::Observer* -TaskAttributionTrackerImpl::GetObserverForTaskDisposal(TaskAttributionId id) { - auto it = task_id_observers_.find(id.value()); - if (it == task_id_observers_.end()) { - return nullptr; - } - auto* observer = it->value.Get(); - task_id_observers_.erase(it); - return observer; -} - -void TaskAttributionTrackerImpl::SetObserverForTaskDisposal( - TaskAttributionId id, - Observer* observer) { - task_id_observers_.insert(id.value(), observer); -} - // TaskScope's implementation ////////////////////////////////////// TaskAttributionTrackerImpl::TaskScopeImpl::TaskScopeImpl(
diff --git a/third_party/blink/renderer/modules/scheduler/task_attribution_tracker_impl.h b/third_party/blink/renderer/modules/scheduler/task_attribution_tracker_impl.h index db6be50..343d244 100644 --- a/third_party/blink/renderer/modules/scheduler/task_attribution_tracker_impl.h +++ b/third_party/blink/renderer/modules/scheduler/task_attribution_tracker_impl.h
@@ -90,9 +90,6 @@ virtual ScriptWrappableTaskState* GetCurrentTaskContinuationData( ScriptState*) const; - Observer* GetObserverForTaskDisposal(TaskAttributionId) override; - void SetObserverForTaskDisposal(TaskAttributionId, Observer*) override; - private: struct TaskAttributionIdPair { TaskAttributionIdPair() = default; @@ -149,9 +146,6 @@ Persistent<TaskAttributionInfo> running_task_ = nullptr; WTF::HashSet<WeakPersistent<TaskAttributionTracker::Observer>> observers_; - WTF::HashMap<TaskAttributionIdType, - WeakPersistent<TaskAttributionTracker::Observer>> - task_id_observers_; // A queue of TaskAttributionInfo objects representing tasks that initiated a // same-document navigation that was sent to the browser side. They are kept
diff --git a/third_party/blink/renderer/modules/storage/cached_storage_area.cc b/third_party/blink/renderer/modules/storage/cached_storage_area.cc index 771cb77..cb7bf9e 100644 --- a/third_party/blink/renderer/modules/storage/cached_storage_area.cc +++ b/third_party/blink/renderer/modules/storage/cached_storage_area.cc
@@ -244,7 +244,7 @@ remote_area_.Bind(std::move(new_area), task_runner); } else if (storage_namespace_) { storage_namespace_->BindStorageArea( - *local_dom_window, + storage_key_, local_dom_window->GetLocalFrameToken(), remote_area_.BindNewPipeAndPassReceiver(task_runner)); } else { return;
diff --git a/third_party/blink/renderer/modules/storage/storage_namespace.cc b/third_party/blink/renderer/modules/storage/storage_namespace.cc index 91696379..f7c3a7e 100644 --- a/third_party/blink/renderer/modules/storage/storage_namespace.cc +++ b/third_party/blink/renderer/modules/storage/storage_namespace.cc
@@ -230,17 +230,15 @@ } void StorageNamespace::BindStorageArea( - const LocalDOMWindow& local_dom_window, + const BlinkStorageKey& storage_key, + const LocalFrameToken& local_frame_token, mojo::PendingReceiver<mojom::blink::StorageArea> receiver) { if (IsSessionStorage()) { controller_->dom_storage()->BindSessionStorageArea( - local_dom_window.GetSessionStorageKey(), - local_dom_window.GetLocalFrameToken(), namespace_id_, - std::move(receiver)); + storage_key, local_frame_token, namespace_id_, std::move(receiver)); } else { - controller_->dom_storage()->OpenLocalStorage( - local_dom_window.GetStorageKey(), local_dom_window.GetLocalFrameToken(), - std::move(receiver)); + controller_->dom_storage()->OpenLocalStorage(storage_key, local_frame_token, + std::move(receiver)); } }
diff --git a/third_party/blink/renderer/modules/storage/storage_namespace.h b/third_party/blink/renderer/modules/storage/storage_namespace.h index f62b185..6ae87db 100644 --- a/third_party/blink/renderer/modules/storage/storage_namespace.h +++ b/third_party/blink/renderer/modules/storage/storage_namespace.h
@@ -119,7 +119,8 @@ // Called by areas in `cached_areas_` to bind/rebind their StorageArea // interface. void BindStorageArea( - const LocalDOMWindow& local_dom_window, + const BlinkStorageKey& storage_key, + const LocalFrameToken& local_frame_token, mojo::PendingReceiver<mojom::blink::StorageArea> receiver); // If this StorageNamespace was previously connected to the backend, this
diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn index bd01cf48..732e7e9 100644 --- a/third_party/blink/renderer/platform/BUILD.gn +++ b/third_party/blink/renderer/platform/BUILD.gn
@@ -16,6 +16,7 @@ import("//third_party/blink/renderer/build/scripts/scripts.gni") import("//third_party/blink/renderer/config.gni") import("//third_party/blink/renderer/platform/platform_generated.gni") +import("//third_party/libgav1/options.gni") import("//v8/gni/v8.gni") if (is_ios) { @@ -1310,6 +1311,8 @@ "peerconnection/gpu_codec_support_waiter.h", "peerconnection/linear_histogram.cc", "peerconnection/linear_histogram.h", + "peerconnection/resolution_monitor.cc", + "peerconnection/resolution_monitor.h", "peerconnection/rtc_answer_options_platform.h", "peerconnection/rtc_api_name.h", "peerconnection/rtc_dtmf_sender_handler.cc", @@ -1667,6 +1670,8 @@ "//third_party/blink/renderer/platform/scheduler", ] + assert(use_libgav1_parser) + public_deps = [ ":allow_discouraged_type", ":blink_platform_public_deps", @@ -1714,6 +1719,7 @@ "//media/capture:capture_switches", "//media/capture/mojom:video_capture", "//media/mojo/clients:clients", + "//media/parsers", "//media/webrtc:webrtc", "//mojo/public/cpp/bindings:wtf_support", "//services/metrics/public/cpp:ukm_builders", @@ -1732,6 +1738,7 @@ "//third_party/ced", "//third_party/emoji-segmenter", "//third_party/icu", + "//third_party/libgav1:libgav1_parser", "//third_party/libyuv", "//third_party/one_euro_filter", "//third_party/snappy:snappy", @@ -2174,6 +2181,7 @@ "peerconnection/linear_histogram_test.cc", "peerconnection/low_precision_timer_test.cc", "peerconnection/metronome_source_test.cc", + "peerconnection/resolution_monitor_unittest.cc", "peerconnection/rtc_encoded_audio_stream_transformer_test.cc", "peerconnection/rtc_encoded_video_stream_transformer_test.cc", "peerconnection/rtc_rtp_source_test.cc",
diff --git a/third_party/blink/renderer/platform/link_hash.cc b/third_party/blink/renderer/platform/link_hash.cc index 5c618f9..dc7fafa 100644 --- a/third_party/blink/renderer/platform/link_hash.cc +++ b/third_party/blink/renderer/platform/link_hash.cc
@@ -30,10 +30,11 @@ #include "third_party/blink/renderer/platform/link_hash.h" +#include <string_view> + #include "third_party/blink/public/platform/platform.h" #include "third_party/blink/renderer/platform/weborigin/kurl.h" #include "third_party/blink/renderer/platform/wtf/text/string_utf8_adaptor.h" - #include "url/url_util.h" namespace blink { @@ -62,7 +63,9 @@ url::RawCanonOutput<2048> buffer; if (!ResolveRelative(base, relative.GetString(), &buffer)) return 0; - return Platform::Current()->VisitedLinkHash(buffer.data(), buffer.length()); + + return Platform::Current()->VisitedLinkHash( + std::string_view(buffer.data(), buffer.length())); } } // namespace blink
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc index 77ef55e..16ba1cc 100644 --- a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc +++ b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
@@ -1347,6 +1347,37 @@ resource->SetRevalidatingRequest(revalidating_request); } +namespace { + +bool UseRenderBlockingTaskPriority(const ResourceRequestHead& request) { + switch (request.GetRequestContext()) { + case mojom::blink::RequestContextType::IMAGE: + // Always boost the priority of images (see: https://crbug.com/1416030). + return true; + case mojom::blink::RequestContextType::IMAGE_SET: + return base::FeatureList::IsEnabled( + features::kBoostImageSetLoadingTaskPriority); + case mojom::blink::RequestContextType::FONT: + return base::FeatureList::IsEnabled( + features::kBoostFontLoadingTaskPriority); + case mojom::blink::RequestContextType::VIDEO: + return base::FeatureList::IsEnabled( + features::kBoostVideoLoadingTaskPriority); + case mojom::blink::RequestContextType::STYLE: + if (request.GetRenderBlockingBehavior() == + RenderBlockingBehavior::kBlocking) { + return base::FeatureList::IsEnabled( + features::kBoostRenderBlockingStyleLoadingTaskPriority); + } + return base::FeatureList::IsEnabled( + features::kBoostNonRenderBlockingStyleLoadingTaskPriority); + default: + return false; + } +} + +} // namespace + std::unique_ptr<URLLoader> ResourceFetcher::CreateURLLoader( const ResourceRequestHead& request, const ResourceLoaderOptions& options) { @@ -1376,13 +1407,12 @@ frame_scheduler->GetAgentGroupScheduler()->DefaultTaskRunner(); } } - } else if (request.GetRequestContext() == - mojom::blink::RequestContextType::IMAGE) { + } else if (UseRenderBlockingTaskPriority(request)) { if (auto* frame_or_worker_scheduler = GetFrameOrWorkerScheduler()) { if (auto* frame_scheduler = frame_or_worker_scheduler->ToFrameScheduler()) { task_runner = frame_scheduler->GetTaskRunner( - TaskType::kNetworkingUnfreezableImageLoading); + TaskType::kNetworkingUnfreezableRenderBlockingLoading); } } }
diff --git a/third_party/blink/renderer/platform/peerconnection/DEPS b/third_party/blink/renderer/platform/peerconnection/DEPS index d26b9a6e..8994d0de 100644 --- a/third_party/blink/renderer/platform/peerconnection/DEPS +++ b/third_party/blink/renderer/platform/peerconnection/DEPS
@@ -19,8 +19,10 @@ "+media/capture/video/video_capture_feedback.h", "+media/filters/decoder_stream.h", "+media/filters/resolution_monitor.h", + "+media/filters/vp9_parser.h", "+media/media_buildflags.h", "+media/mojo/clients/mojo_video_encoder_metrics_provider.h", + "+media/parsers/vp8_parser.h", # This is only needed for a cast to DecoderFactory. "+media/renderers/default_decoder_factory.h", "+media/video/gpu_video_accelerator_factories.h", @@ -47,4 +49,7 @@ "+media/mojo/clients/mojo_video_encoder_metrics_provider.h", "+third_party/blink/renderer/platform/testing/video_frame_utils.h", ], + "resolution_monitor_unittest.cc" : [ + "+media/filters/ivf_parser.h", + ] }
diff --git a/media/filters/resolution_monitor.cc b/third_party/blink/renderer/platform/peerconnection/resolution_monitor.cc similarity index 73% rename from media/filters/resolution_monitor.cc rename to third_party/blink/renderer/platform/peerconnection/resolution_monitor.cc index c2afde4..5d6a649 100644 --- a/media/filters/resolution_monitor.cc +++ b/third_party/blink/renderer/platform/peerconnection/resolution_monitor.cc
@@ -2,8 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "media/filters/resolution_monitor.h" +#include "third_party/blink/renderer/platform/peerconnection/resolution_monitor.h" +#include "base/containers/span.h" #include "base/logging.h" #include "base/memory/ptr_util.h" #include "base/notreached.h" @@ -11,26 +12,28 @@ #include "media/base/decoder_buffer.h" #include "media/filters/vp9_parser.h" #include "media/parsers/vp8_parser.h" -#include "media/video/h264_parser.h" #include "third_party/abseil-cpp/absl/types/variant.h" #include "third_party/libgav1/src/src/buffer_pool.h" #include "third_party/libgav1/src/src/decoder_state.h" #include "third_party/libgav1/src/src/obu_parser.h" +#include "third_party/webrtc/common_video/h264/h264_common.h" +#include "third_party/webrtc/common_video/h264/sps_parser.h" -namespace media { +namespace blink { + namespace { class Vp8ResolutionMonitor : public ResolutionMonitor { public: Vp8ResolutionMonitor() = default; absl::optional<gfx::Size> GetResolution( - const DecoderBuffer& buffer) override { + const media::DecoderBuffer& buffer) override { if (!buffer.is_key_frame()) { return current_resolution_; } - Vp8Parser parser; - Vp8FrameHeader frame_header; + media::Vp8Parser parser; + media::Vp8FrameHeader frame_header; if (!parser.ParseFrame(buffer.data(), buffer.data_size(), &frame_header)) { DLOG(ERROR) << "Failed to parse vp8 stream"; current_resolution_ = absl::nullopt; @@ -42,7 +45,7 @@ return current_resolution_; } - VideoCodec codec() const override { return media::VideoCodec::kVP8; } + media::VideoCodec codec() const override { return media::VideoCodec::kVP8; } private: absl::optional<gfx::Size> current_resolution_; @@ -55,7 +58,7 @@ ~Vp9ResolutionMonitor() override = default; absl::optional<gfx::Size> GetResolution( - const DecoderBuffer& buffer) override { + const media::DecoderBuffer& buffer) override { std::vector<uint32_t> frame_sizes; if (buffer.has_side_data()) { frame_sizes = buffer.side_data()->spatial_layers; @@ -78,21 +81,21 @@ return parse_error ? absl::nullopt : max_resolution; } - VideoCodec codec() const override { return media::VideoCodec::kVP9; } + media::VideoCodec codec() const override { return media::VideoCodec::kVP9; } private: bool GetNextFrameSize(gfx::Size& frame_size, bool& parse_error) { - Vp9FrameHeader frame_header; + media::Vp9FrameHeader frame_header; gfx::Size allocate_size; - Vp9Parser::Result result = parser_.ParseNextFrame( + media::Vp9Parser::Result result = parser_.ParseNextFrame( &frame_header, &allocate_size, /*frame_decrypt_config=*/nullptr); switch (result) { - case Vp9Parser::Result::kOk: + case media::Vp9Parser::Result::kOk: frame_size.SetSize(frame_header.frame_width, frame_header.frame_height); return true; - case Vp9Parser::Result::kEOStream: + case media::Vp9Parser::Result::kEOStream: return false; - case Vp9Parser::Result::kInvalidStream: + case media::Vp9Parser::Result::kInvalidStream: DLOG(ERROR) << "Failed parsing vp9 frame"; parse_error = true; return false; @@ -100,7 +103,7 @@ NOTREACHED_NORETURN() << "Unexpected result: " << static_cast<int>(result); } - Vp9Parser parser_; + media::Vp9Parser parser_; }; class Av1ResolutionMonitor : public ResolutionMonitor { @@ -116,7 +119,7 @@ ~Av1ResolutionMonitor() override = default; absl::optional<gfx::Size> GetResolution( - const DecoderBuffer& buffer) override { + const media::DecoderBuffer& buffer) override { auto parser = base::WrapUnique(new (std::nothrow) libgav1::ObuParser( buffer.data(), buffer.data_size(), kDefaultOperatingPoint, &buffer_pool_, &decoder_state_)); @@ -161,7 +164,7 @@ return max_resolution; } - VideoCodec codec() const override { return VideoCodec::kAV1; } + media::VideoCodec codec() const override { return media::VideoCodec::kAV1; } private: // Returns true iff the current decode sequence has multiple spatial layers. @@ -224,69 +227,45 @@ ~H264ResolutionMonitor() override = default; absl::optional<gfx::Size> GetResolution( - const DecoderBuffer& buffer) override { + const media::DecoderBuffer& buffer) override { if (!buffer.is_key_frame()) { return current_resolution_; } - H264Parser h264_parser; - h264_parser.SetStream(buffer.data(), - base::checked_cast<off_t>(buffer.data_size())); - size_t nalus_count = 0; - H264NALU nalu; absl::optional<gfx::Size> resolution; - bool parse_error = false; - while (GetNextNALU(h264_parser, nalu, parse_error)) { - nalus_count += 1; - if (nalu.nal_unit_type == H264NALU::Type::kSPS) { - int sps_id = 0; - if (h264_parser.ParseSPS(&sps_id) != H264Parser::kOk) { - DLOG(ERROR) << "Failed parsing h264 SPS"; + std::vector<webrtc::H264::NaluIndex> nalu_indices = + webrtc::H264::FindNaluIndices(buffer.data(), buffer.data_size()); + for (const auto& nalu_index : nalu_indices) { + base::span<const uint8_t> nalu_payload( + buffer.data() + nalu_index.payload_start_offset, + nalu_index.payload_size); + if (webrtc::H264::ParseNaluType(nalu_payload[0]) == + webrtc::H264::NaluType::kSps) { + if (nalu_payload.size() < webrtc::H264::kNaluTypeSize + 1) { + DLOG(ERROR) << "H.264 SPS NALU size too small for parsing."; return absl::nullopt; } - const H264SPS* sps = h264_parser.GetSPS(sps_id); - if (!sps) { - DLOG(ERROR) << "Failed getting h264 SPS: id=" << sps_id; + // Parse without NALU header. + absl::optional<webrtc::SpsParser::SpsState> sps = + webrtc::SpsParser::ParseSps( + nalu_payload.data() + webrtc::H264::kNaluTypeSize, + nalu_payload.size() - webrtc::H264::kNaluTypeSize); + if (!sps || !sps->width || !sps->height) { + DLOG(ERROR) << "Failed parsing H.264 SPS."; return absl::nullopt; } - absl::optional<gfx::Size> coded_size = sps->GetCodedSize(); - if (!coded_size) { - DLOG(ERROR) << "Failed getting coded size"; - return absl::nullopt; - } - resolution = *coded_size; + resolution = gfx::Size(sps->width, sps->height); + break; } } - if (parse_error || nalus_count == 0) { - return absl::nullopt; - } - current_resolution_ = resolution; return current_resolution_; } - VideoCodec codec() const override { return VideoCodec::kH264; } + media::VideoCodec codec() const override { return media::VideoCodec::kH264; } private: - bool GetNextNALU(H264Parser& h264_parser, - H264NALU& nalu, - bool& parse_error) const { - H264Parser::Result result = h264_parser.AdvanceToNextNALU(&nalu); - switch (result) { - case H264Parser::Result::kOk: - return true; - case H264Parser::Result::kEOStream: - return false; - case H264Parser::Result::kInvalidStream: - case H264Parser::Result::kUnsupportedStream: - DLOG(ERROR) << "Failed parsing h264 NALU"; - parse_error = true; - return false; - } - NOTREACHED_NORETURN() << "Unexpected result: " << static_cast<int>(result); - } - absl::optional<gfx::Size> current_resolution_; }; } // namespace @@ -294,20 +273,21 @@ ResolutionMonitor::~ResolutionMonitor() = default; // static -std::unique_ptr<ResolutionMonitor> ResolutionMonitor::Create(VideoCodec codec) { +std::unique_ptr<ResolutionMonitor> ResolutionMonitor::Create( + media::VideoCodec codec) { switch (codec) { - case VideoCodec::kH264: + case media::VideoCodec::kH264: return std::make_unique<H264ResolutionMonitor>(); - case VideoCodec::kVP8: + case media::VideoCodec::kVP8: return std::make_unique<Vp8ResolutionMonitor>(); - case VideoCodec::kVP9: + case media::VideoCodec::kVP9: return std::make_unique<Vp9ResolutionMonitor>(); - case VideoCodec::kAV1: + case media::VideoCodec::kAV1: return std::make_unique<Av1ResolutionMonitor>(); - // TODO(bugs.webrtc.org/13485): Add H265. default: - DLOG(ERROR) << "Unsupported codec: " << GetCodecName(codec); + DLOG(ERROR) << "Unsupported codec: " << media::GetCodecName(codec); return nullptr; } } -} // namespace media + +} // namespace blink
diff --git a/third_party/blink/renderer/platform/peerconnection/resolution_monitor.h b/third_party/blink/renderer/platform/peerconnection/resolution_monitor.h new file mode 100644 index 0000000..c8537129 --- /dev/null +++ b/third_party/blink/renderer/platform/peerconnection/resolution_monitor.h
@@ -0,0 +1,39 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_PEERCONNECTION_RESOLUTION_MONITOR_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_PEERCONNECTION_RESOLUTION_MONITOR_H_ + +#include <memory> + +#include "base/sequence_checker.h" +#include "media/base/video_codecs.h" +#include "third_party/abseil-cpp/absl/types/optional.h" +#include "third_party/blink/renderer/platform/platform_export.h" +#include "ui/gfx/geometry/size.h" + +namespace media { +class DecoderBuffer; +} // namespace media + +namespace blink { + +// Resolution monitor acquires a resolution of DecoderBuffer by parsing it. We +// can know the stream resolution before the first keyframe is decoded. This +// avoids requesting a sender to produce a keyframe again when a software +// decoder fallback happens due to stream resolution change. +class PLATFORM_EXPORT ResolutionMonitor { + public: + virtual ~ResolutionMonitor(); + + static std::unique_ptr<ResolutionMonitor> Create(media::VideoCodec codec); + + virtual absl::optional<gfx::Size> GetResolution( + const media::DecoderBuffer& buffer) = 0; + virtual media::VideoCodec codec() const = 0; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_PEERCONNECTION_RESOLUTION_MONITOR_H_
diff --git a/media/filters/resolution_monitor_unittest.cc b/third_party/blink/renderer/platform/peerconnection/resolution_monitor_unittest.cc similarity index 60% rename from media/filters/resolution_monitor_unittest.cc rename to third_party/blink/renderer/platform/peerconnection/resolution_monitor_unittest.cc index ecc7dcb8..43b524f 100644 --- a/media/filters/resolution_monitor_unittest.cc +++ b/third_party/blink/renderer/platform/peerconnection/resolution_monitor_unittest.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "media/filters/resolution_monitor.h" +#include "third_party/blink/renderer/platform/peerconnection/resolution_monitor.h" #include "base/files/file_util.h" #include "media/base/decoder_buffer.h" @@ -10,24 +10,25 @@ #include "media/filters/ivf_parser.h" #include "testing/gtest/include/gtest/gtest.h" -namespace media { +namespace blink { + namespace { -const VideoCodec kCodecs[] = { - VideoCodec::kH264, - VideoCodec::kVP8, - VideoCodec::kVP9, - VideoCodec::kAV1, +const media::VideoCodec kCodecs[] = { + media::VideoCodec::kH264, + media::VideoCodec::kVP8, + media::VideoCodec::kVP9, + media::VideoCodec::kAV1, }; class ResolutionMonitorTestWithInvalidFrame - : public ::testing::TestWithParam<VideoCodec> { + : public ::testing::TestWithParam<media::VideoCodec> { protected: std::string kInvalidData = "This is invalid data and causes a parser error"; }; TEST_P(ResolutionMonitorTestWithInvalidFrame, ReturnNullOpt) { - const VideoCodec codec = GetParam(); - auto invalid_buffer = DecoderBuffer::CopyFrom( + const media::VideoCodec codec = GetParam(); + auto invalid_buffer = media::DecoderBuffer::CopyFrom( reinterpret_cast<const uint8_t*>(kInvalidData.data()), kInvalidData.size()); invalid_buffer->set_is_key_frame(true); @@ -43,7 +44,7 @@ struct FrameData { std::string file_name; - VideoCodec codec; + media::VideoCodec codec; gfx::Size resolution; }; @@ -52,7 +53,7 @@ TEST_P(ResolutionMonitorTestWithValidFrame, ReturnExpectedResolution) { const auto param = GetParam(); - auto buffer = ReadTestDataFile(param.file_name); + auto buffer = media::ReadTestDataFile(param.file_name); ASSERT_TRUE(buffer); buffer->set_is_key_frame(true); @@ -62,30 +63,30 @@ } const FrameData kH264Frames[] = { - // 320x192 because we acquire coded size. - {"h264-320x180-frame-0", VideoCodec::kH264, gfx::Size(320, 192)}, - {"bear-320x192-baseline-frame-0.h264", VideoCodec::kH264, + // 320x180 because we acquire visible size here. + {"h264-320x180-frame-0", media::VideoCodec::kH264, gfx::Size(320, 180)}, + {"bear-320x192-baseline-frame-0.h264", media::VideoCodec::kH264, gfx::Size(320, 192)}, - {"bear-320x192-high-frame-0.h264", VideoCodec::kH264, gfx::Size(320, 192)}, + {"bear-320x192-high-frame-0.h264", media::VideoCodec::kH264, gfx::Size(320, 192)}, }; const FrameData kVP8Frames[] = { - {"vp8-I-frame-160x240", VideoCodec::kVP8, gfx::Size(160, 240)}, - {"vp8-I-frame-320x120", VideoCodec::kVP8, gfx::Size(320, 120)}, - {"vp8-I-frame-320x240", VideoCodec::kVP8, gfx::Size(320, 240)}, - {"vp8-I-frame-320x480", VideoCodec::kVP8, gfx::Size(320, 480)}, - {"vp8-I-frame-640x240", VideoCodec::kVP8, gfx::Size(640, 240)}, + {"vp8-I-frame-160x240", media::VideoCodec::kVP8, gfx::Size(160, 240)}, + {"vp8-I-frame-320x120", media::VideoCodec::kVP8, gfx::Size(320, 120)}, + {"vp8-I-frame-320x240", media::VideoCodec::kVP8, gfx::Size(320, 240)}, + {"vp8-I-frame-320x480", media::VideoCodec::kVP8, gfx::Size(320, 480)}, + {"vp8-I-frame-640x240", media::VideoCodec::kVP8, gfx::Size(640, 240)}, }; const FrameData kVP9Frames[] = { - {"vp9-I-frame-1280x720", VideoCodec::kVP9, gfx::Size(1280, 720)}, - {"vp9-I-frame-320x240", VideoCodec::kVP9, gfx::Size(320, 240)}, + {"vp9-I-frame-1280x720", media::VideoCodec::kVP9, gfx::Size(1280, 720)}, + {"vp9-I-frame-320x240", media::VideoCodec::kVP9, gfx::Size(320, 240)}, }; const FrameData kAV1Frames[] = { - {"av1-I-frame-320x240", VideoCodec::kAV1, gfx::Size(320, 240)}, - {"av1-I-frame-1280x720", VideoCodec::kAV1, gfx::Size(1280, 720)}, - {"av1-monochrome-I-frame-320x240-8bpp", VideoCodec::kAV1, + {"av1-I-frame-320x240", media::VideoCodec::kAV1, gfx::Size(320, 240)}, + {"av1-I-frame-1280x720", media::VideoCodec::kAV1, gfx::Size(1280, 720)}, + {"av1-monochrome-I-frame-320x240-8bpp", media::VideoCodec::kAV1, gfx::Size(320, 240)}, }; @@ -102,22 +103,22 @@ ResolutionMonitorTestWithValidFrame, ::testing::ValuesIn(kAV1Frames)); -std::vector<scoped_refptr<DecoderBuffer>> ReadIVF(const std::string& fname) { +std::vector<scoped_refptr<media::DecoderBuffer>> ReadIVF(const std::string& fname) { std::string ivf_data; - auto input_file = GetTestDataFilePath(fname); + auto input_file = media::GetTestDataFilePath(fname); EXPECT_TRUE(base::ReadFileToString(input_file, &ivf_data)); - IvfParser ivf_parser; - IvfFileHeader ivf_header{}; + media::IvfParser ivf_parser; + media::IvfFileHeader ivf_header{}; EXPECT_TRUE( ivf_parser.Initialize(reinterpret_cast<const uint8_t*>(ivf_data.data()), ivf_data.size(), &ivf_header)); - std::vector<scoped_refptr<DecoderBuffer>> buffers; - IvfFrameHeader ivf_frame_header{}; + std::vector<scoped_refptr<media::DecoderBuffer>> buffers; + media::IvfFrameHeader ivf_frame_header{}; const uint8_t* data; while (ivf_parser.ParseNextFrame(&ivf_frame_header, &data)) { - buffers.push_back(DecoderBuffer::CopyFrom( + buffers.push_back(media::DecoderBuffer::CopyFrom( reinterpret_cast<const uint8_t*>(data), ivf_frame_header.frame_size)); } return buffers; @@ -125,7 +126,7 @@ struct VideoData { std::string file_name; - VideoCodec codec; + media::VideoCodec codec; gfx::Size resolution; }; @@ -144,20 +145,20 @@ } const VideoData kVP8Videos[] = { - {"test-25fps.vp8", VideoCodec::kVP8, gfx::Size(320, 240)}, - {"bear-1280x720.ivf", VideoCodec::kVP8, gfx::Size(1280, 720)}, + {"test-25fps.vp8", media::VideoCodec::kVP8, gfx::Size(320, 240)}, + {"bear-1280x720.ivf", media::VideoCodec::kVP8, gfx::Size(1280, 720)}, }; const VideoData kVP9Videos[] = { - {"test-25fps.vp9", VideoCodec::kVP9, gfx::Size(320, 240)}, - {"test-25fps.vp9_2", VideoCodec::kVP9, gfx::Size(320, 240)}, - {"bear-vp9.ivf", VideoCodec::kVP9, gfx::Size(320, 240)}, + {"test-25fps.vp9", media::VideoCodec::kVP9, gfx::Size(320, 240)}, + {"test-25fps.vp9_2", media::VideoCodec::kVP9, gfx::Size(320, 240)}, + {"bear-vp9.ivf", media::VideoCodec::kVP9, gfx::Size(320, 240)}, }; const VideoData kAV1Videos[] = { - {"test-25fps.av1.ivf", VideoCodec::kAV1, gfx::Size(320, 240)}, - {"av1-show_existing_frame.ivf", VideoCodec::kAV1, gfx::Size(208, 144)}, - {"av1-svc-L1T2.ivf", VideoCodec::kAV1, gfx::Size(640, 360)}, + {"test-25fps.av1.ivf", media::VideoCodec::kAV1, gfx::Size(320, 240)}, + {"av1-show_existing_frame.ivf", media::VideoCodec::kAV1, gfx::Size(208, 144)}, + {"av1-svc-L1T2.ivf", media::VideoCodec::kAV1, gfx::Size(640, 360)}, }; INSTANTIATE_TEST_SUITE_P(VP8, @@ -169,5 +170,7 @@ INSTANTIATE_TEST_SUITE_P(AV1, ResolutionMonitorTestWithValidVideo, ::testing::ValuesIn(kAV1Videos)); + } // namespace -} // namespace media + +} // namespace blink
diff --git a/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_adapter.cc b/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_adapter.cc index ca9ea29..a3aebc4 100644 --- a/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_adapter.cc +++ b/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_adapter.cc
@@ -494,7 +494,7 @@ std::unique_ptr<RTCVideoDecoderAdapter> RTCVideoDecoderAdapter::Create( media::GpuVideoAcceleratorFactories* gpu_factories, const webrtc::SdpVideoFormat& format, - std::unique_ptr<media::ResolutionMonitor> resolution_monitor) { + std::unique_ptr<ResolutionMonitor> resolution_monitor) { DVLOG(1) << __func__ << "(" << format.name << ")"; const webrtc::VideoCodecType video_codec_type = @@ -514,7 +514,7 @@ config.set_is_rtc(true); if (!resolution_monitor) { - resolution_monitor = media::ResolutionMonitor::Create(config.codec()); + resolution_monitor = ResolutionMonitor::Create(config.codec()); if (!resolution_monitor) { DLOG(ERROR) << "Failed to create ResolutionMonitor for codec: " << media::GetCodecName(config.codec()); @@ -544,7 +544,7 @@ RTCVideoDecoderAdapter::RTCVideoDecoderAdapter( media::GpuVideoAcceleratorFactories* gpu_factories, const media::VideoDecoderConfig& config, - std::unique_ptr<media::ResolutionMonitor> resolution_monitor) + std::unique_ptr<ResolutionMonitor> resolution_monitor) : media_task_runner_(gpu_factories->GetTaskRunner()), config_(config), resolution_monitor_(std::move(resolution_monitor)) {
diff --git a/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_adapter.h b/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_adapter.h index 23b2eb5..acb8aa8 100644 --- a/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_adapter.h +++ b/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_adapter.h
@@ -16,7 +16,7 @@ #include "build/build_config.h" #include "media/base/decoder.h" #include "media/base/video_decoder_config.h" -#include "media/filters/resolution_monitor.h" +#include "third_party/blink/renderer/platform/peerconnection/resolution_monitor.h" #include "third_party/blink/renderer/platform/platform_export.h" #include "third_party/webrtc/api/video_codecs/sdp_video_format.h" #include "third_party/webrtc/api/video_codecs/video_decoder.h" @@ -65,7 +65,7 @@ static std::unique_ptr<RTCVideoDecoderAdapter> Create( media::GpuVideoAcceleratorFactories* gpu_factories, const webrtc::SdpVideoFormat& format, - std::unique_ptr<media::ResolutionMonitor> resolution_monitor = nullptr); + std::unique_ptr<ResolutionMonitor> resolution_monitor = nullptr); RTCVideoDecoderAdapter(const RTCVideoDecoderAdapter&) = delete; RTCVideoDecoderAdapter& operator=(const RTCVideoDecoderAdapter&) = delete; @@ -108,10 +108,9 @@ }; // Called on the worker thread. - RTCVideoDecoderAdapter( - media::GpuVideoAcceleratorFactories* gpu_factories, - const media::VideoDecoderConfig& config, - std::unique_ptr<media::ResolutionMonitor> resolution_monitor); + RTCVideoDecoderAdapter(media::GpuVideoAcceleratorFactories* gpu_factories, + const media::VideoDecoderConfig& config, + std::unique_ptr<ResolutionMonitor> resolution_monitor); bool InitializeSync(const media::VideoDecoderConfig& config); absl::optional<DecodeResult> DecodeInternal( @@ -130,7 +129,7 @@ // Construction parameters. media::VideoDecoderConfig config_; - const std::unique_ptr<media::ResolutionMonitor> resolution_monitor_ + const std::unique_ptr<ResolutionMonitor> resolution_monitor_ GUARDED_BY_CONTEXT(decoding_sequence_checker_); // Decoding thread members.
diff --git a/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_adapter_test.cc b/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_adapter_test.cc index 4c57b01..d4d6119 100644 --- a/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_adapter_test.cc +++ b/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_adapter_test.cc
@@ -29,10 +29,10 @@ #include "media/base/video_decoder_config.h" #include "media/base/video_frame.h" #include "media/base/video_types.h" -#include "media/filters/resolution_monitor.h" #include "media/video/mock_gpu_video_accelerator_factories.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/renderer/platform/peerconnection/resolution_monitor.h" #include "third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_adapter.h" #include "third_party/blink/renderer/platform/webrtc/webrtc_video_utils.h" #include "third_party/webrtc/api/video_codecs/video_codec.h" @@ -52,7 +52,7 @@ namespace { -class FakeResolutionMonitor : public media::ResolutionMonitor { +class FakeResolutionMonitor : public ResolutionMonitor { public: explicit FakeResolutionMonitor(bool pass_resolution_monitor, const webrtc::SdpVideoFormat& format)
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5 index 9b4465f..21dd205 100644 --- a/third_party/blink/renderer/platform/runtime_enabled_features.json5 +++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -327,6 +327,10 @@ base_feature: "none", }, { + name: "AppTitle", + status: "experimental", + }, + { // crbug.com/484651 name: "ArrowKeysInVerticalWritingModes", status: "stable", @@ -2419,7 +2423,7 @@ { name: "MediaSessionEnterPictureInPicture", public: true, - status: "experimental", + status: "stable", }, { name: "MediaSessionSlides", @@ -4265,7 +4269,7 @@ }, { name: "WebGLDrawingBufferStorage", - status: "experimental", + status: "stable", base_feature: "none", }, {
diff --git a/third_party/blink/renderer/platform/scheduler/BUILD.gn b/third_party/blink/renderer/platform/scheduler/BUILD.gn index 04beb3b..34291347 100644 --- a/third_party/blink/renderer/platform/scheduler/BUILD.gn +++ b/third_party/blink/renderer/platform/scheduler/BUILD.gn
@@ -44,7 +44,6 @@ "common/simple_main_thread_scheduler.h", "common/single_thread_idle_task_runner.cc", "common/single_thread_idle_task_runner.h", - "common/task_attribution_info.cc", "common/task_priority.cc", "common/task_priority.h", "common/thread.cc",
diff --git a/third_party/blink/renderer/platform/scheduler/common/task_attribution_info.cc b/third_party/blink/renderer/platform/scheduler/common/task_attribution_info.cc deleted file mode 100644 index 57738d0..0000000 --- a/third_party/blink/renderer/platform/scheduler/common/task_attribution_info.cc +++ /dev/null
@@ -1,21 +0,0 @@ -// Copyright 2023 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "third_party/blink/renderer/platform/scheduler/public/task_attribution_info.h" -#include "third_party/blink/renderer/platform/scheduler/public/task_attribution_tracker.h" -#include "third_party/blink/renderer/platform/scheduler/public/thread_scheduler.h" - -namespace blink::scheduler { - -void TaskAttributionInfo::Dispose() { - auto* tracker = ThreadScheduler::Current()->GetTaskAttributionTracker(); - if (!tracker) { - return; - } - if (auto* observer = tracker->GetObserverForTaskDisposal(task_id_)) { - observer->OnTaskDisposal(*this); - } -} - -} // namespace blink::scheduler
diff --git a/third_party/blink/renderer/platform/scheduler/common/tracing_helper.cc b/third_party/blink/renderer/platform/scheduler/common/tracing_helper.cc index 07d3a38..6fed7dc8 100644 --- a/third_party/blink/renderer/platform/scheduler/common/tracing_helper.cc +++ b/third_party/blink/renderer/platform/scheduler/common/tracing_helper.cc
@@ -196,9 +196,9 @@ TASK_TYPE_MAIN_THREAD_TASK_QUEUE_IPC_TRACKING; case TaskType::kNetworkingUnfreezable: return RendererMainThreadTaskExecution::TASK_TYPE_NETWORKING_UNFREEZABLE; - case TaskType::kNetworkingUnfreezableImageLoading: + case TaskType::kNetworkingUnfreezableRenderBlockingLoading: return RendererMainThreadTaskExecution:: - TASK_TYPE_NETWORKING_UNFREEZABLE_IMAGE_LOADING; + TASK_TYPE_NETWORKING_UNFREEZABLE_RENDER_BLOCKING_LOADING; case TaskType::kWakeLock: return RendererMainThreadTaskExecution::TASK_TYPE_WAKE_LOCK; case TaskType::kInternalInputBlocking:
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc index f604eda..7074f8e 100644 --- a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc +++ b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc
@@ -448,7 +448,7 @@ return IsInflightNetworkRequestBackForwardCacheSupportEnabled() ? UnfreezableLoadingTaskQueueTraits() : LoadingTaskQueueTraits(); - case TaskType::kNetworkingUnfreezableImageLoading: { + case TaskType::kNetworkingUnfreezableRenderBlockingLoading: { QueueTraits queue_traits = IsInflightNetworkRequestBackForwardCacheSupportEnabled() ? UnfreezableLoadingTaskQueueTraits()
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc index 4e151825..a0a376d 100644 --- a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc +++ b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc
@@ -122,7 +122,7 @@ TaskType::kInternalLoading, TaskType::kNetworking, TaskType::kNetworkingUnfreezable, - TaskType::kNetworkingUnfreezableImageLoading, + TaskType::kNetworkingUnfreezableRenderBlockingLoading, TaskType::kNetworkingControl, TaskType::kLowPriorityScriptExecution, TaskType::kDOMManipulation, @@ -1453,9 +1453,9 @@ TaskPriority::kHighestPriority); } -TEST_F(FrameSchedulerImplTest, RenderBlockingImageLoading) { +TEST_F(FrameSchedulerImplTest, RenderBlockingRenderBlockingLoading) { auto render_blocking_task_queue = - GetTaskQueue(TaskType::kNetworkingUnfreezableImageLoading); + GetTaskQueue(TaskType::kNetworkingUnfreezableRenderBlockingLoading); page_scheduler_->SetPageVisible(false); EXPECT_EQ(render_blocking_task_queue->GetQueuePriority(), TaskPriority::kNormalPriority);
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl_unittest.cc b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl_unittest.cc index a9ebb170..bc7f2ad9 100644 --- a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl_unittest.cc +++ b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl_unittest.cc
@@ -491,7 +491,7 @@ prioritised_local_frame_task_runner_ = main_frame_scheduler_->GetTaskRunner( blink::TaskType::kInternalHighPriorityLocalFrame); render_blocking_task_runner_ = main_frame_scheduler_->GetTaskRunner( - blink::TaskType::kNetworkingUnfreezableImageLoading); + blink::TaskType::kNetworkingUnfreezableRenderBlockingLoading); } MainThreadTaskQueue* compositor_task_queue() {
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/task_type_names.cc b/third_party/blink/renderer/platform/scheduler/main_thread/task_type_names.cc index db08540..2fa51954 100644 --- a/third_party/blink/renderer/platform/scheduler/main_thread/task_type_names.cc +++ b/third_party/blink/renderer/platform/scheduler/main_thread/task_type_names.cc
@@ -23,8 +23,8 @@ return "Networking"; case TaskType::kNetworkingUnfreezable: return "NetworkingUnfreezable"; - case TaskType::kNetworkingUnfreezableImageLoading: - return "NetworkingUnfreezableImageLoading"; + case TaskType::kNetworkingUnfreezableRenderBlockingLoading: + return "NetworkingUnfreezableRenderBlockingLoading"; case TaskType::kNetworkingControl: return "NetworkingControl"; case TaskType::kLowPriorityScriptExecution:
diff --git a/third_party/blink/renderer/platform/scheduler/public/task_attribution_info.h b/third_party/blink/renderer/platform/scheduler/public/task_attribution_info.h index 4c005447..73867d90 100644 --- a/third_party/blink/renderer/platform/scheduler/public/task_attribution_info.h +++ b/third_party/blink/renderer/platform/scheduler/public/task_attribution_info.h
@@ -8,15 +8,12 @@ #include "third_party/blink/public/common/scheduler/task_attribution_id.h" #include "third_party/blink/renderer/platform/heap/garbage_collected.h" #include "third_party/blink/renderer/platform/heap/member.h" -#include "third_party/blink/renderer/platform/heap/prefinalizer.h" #include "third_party/blink/renderer/platform/heap/visitor.h" #include "third_party/blink/renderer/platform/scheduler/public/task_attribution_tracker.h" namespace blink::scheduler { class TaskAttributionInfo final : public GarbageCollected<TaskAttributionInfo> { - USING_PRE_FINALIZER(TaskAttributionInfo, Dispose); - public: TaskAttributionInfo(TaskAttributionId task_id, TaskAttributionInfo* parent) : task_id_(task_id), @@ -25,7 +22,6 @@ ~TaskAttributionInfo() = default; - PLATFORM_EXPORT void Dispose(); TaskAttributionId Id() const { return task_id_; } TaskAttributionInfo* Parent() const { return parent_.Get(); } bool MaxChainLengthReached() const {
diff --git a/third_party/blink/renderer/platform/scheduler/public/task_attribution_tracker.h b/third_party/blink/renderer/platform/scheduler/public/task_attribution_tracker.h index 0efdcde..65d7ef1 100644 --- a/third_party/blink/renderer/platform/scheduler/public/task_attribution_tracker.h +++ b/third_party/blink/renderer/platform/scheduler/public/task_attribution_tracker.h
@@ -53,7 +53,6 @@ class Observer : public GarbageCollectedMixin { public: virtual void OnCreateTaskScope(TaskAttributionInfo&, ScriptState*) = 0; - virtual void OnTaskDisposal(const TaskAttributionInfo&) = 0; virtual ExecutionContext* GetExecutionContext() = 0; }; @@ -99,8 +98,6 @@ virtual void ResetSameDocumentNavigationTasks() = 0; virtual TaskAttributionInfo* CommitSameDocumentNavigation( TaskAttributionId) = 0; - virtual Observer* GetObserverForTaskDisposal(TaskAttributionId) = 0; - virtual void SetObserverForTaskDisposal(TaskAttributionId, Observer*) = 0; }; } // namespace blink::scheduler
diff --git a/third_party/blink/renderer/platform/scheduler/worker/worker_scheduler_impl.cc b/third_party/blink/renderer/platform/scheduler/worker/worker_scheduler_impl.cc index b2568b36..5aa78605 100644 --- a/third_party/blink/renderer/platform/scheduler/worker/worker_scheduler_impl.cc +++ b/third_party/blink/renderer/platform/scheduler/worker/worker_scheduler_impl.cc
@@ -217,7 +217,7 @@ // Get(LocalFrame). (https://crbug.com/670534) return unpausable_task_queue_->CreateTaskRunner(type); case TaskType::kNetworkingUnfreezable: - case TaskType::kNetworkingUnfreezableImageLoading: + case TaskType::kNetworkingUnfreezableRenderBlockingLoading: return IsInflightNetworkRequestBackForwardCacheSupportEnabled() ? unpausable_task_queue_->CreateTaskRunner(type) : pausable_non_vt_task_queue_->CreateTaskRunner(type);
diff --git a/third_party/blink/web_tests/FlagExpectations/enable-skia-graphite b/third_party/blink/web_tests/FlagExpectations/enable-skia-graphite index 78ea935..18a7296f4 100644 --- a/third_party/blink/web_tests/FlagExpectations/enable-skia-graphite +++ b/third_party/blink/web_tests/FlagExpectations/enable-skia-graphite
@@ -1,3 +1,9 @@ # tags: [ Android Fuchsia Linux Mac Mac11 Mac12 Mac13 Mac13-arm64 Win Win10.20h2 Win11 Win11-arm64 ] # tags: [ Release Debug ] # results: [ Timeout Crash Pass Failure Slow Skip ] + +# ====== New tests from wpt-importer added here ====== +crbug.com/626703 external/wpt/css/css-masking/mask-image/mask-opacity-1e.html [ Failure ] +crbug.com/626703 external/wpt/png/apng/acTL-plays-two.html [ Timeout ] +crbug.com/626703 external/wpt/screen-capture/getdisplaymedia-capture-controller.https.window.html [ Crash ] +crbug.com/626703 external/wpt/screen-capture/getdisplaymedia.https.html [ Crash ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index e0a51de..2b906e4 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -6657,6 +6657,9 @@ # rebaseline tool reports this test is flaky crbug.com/1481730 [ Linux ] external/wpt/html/canvas/element/manual/wide-gamut-canvas/canvas-display-p3-drawImage-video.html [ Failure ] +crbug.com/1481209 [ Mac ] http/tests/inspector-protocol/target/browser-auto-attach-tab.js [ Failure Pass Timeout ] +crbug.com/1481209 [ Linux ] http/tests/inspector-protocol/target/browser-auto-attach-tab.js [ Failure Pass Timeout ] + # Gardener 2023-10-09 crbug.com/1476826 [ Win ] http/tests/xmlhttprequest/small-chunks-response-text.html [ Failure Pass ] @@ -6744,10 +6747,8 @@ crbug.com/1502794 external/wpt/html/semantics/invokers/invoketarget-on-video-behavior.tentative.html [ Failure Pass Timeout ] # Gardener 2023-11-17 -crbug.com/1503108 [ Debug Mac13-arm64 ] external/wpt/credential-management/fedcm-disconnect.sub.https.html [ Timeout ] -crbug.com/1503108 [ Mac11 Release ] external/wpt/credential-management/fedcm-disconnect.sub.https.html [ Timeout ] -crbug.com/1503108 [ Mac12 Release ] external/wpt/credential-management/fedcm-disconnect.sub.https.html [ Timeout ] -crbug.com/1503108 [ Mac13 ] external/wpt/credential-management/fedcm-disconnect.sub.https.html [ Timeout ] +crbug.com/1503108 [ Mac ] external/wpt/credential-management/fedcm-disconnect.sub.https.html [ Timeout ] +crbug.com/1503108 [ Win ] external/wpt/credential-management/fedcm-disconnect.sub.https.html [ Timeout ] crbug.com/1503051 [ Mac ] virtual/keepalive-in-browser-migration/external/wpt/fetch/metadata/generated/audioworklet.https.sub.html [ Failure Pass ] crbug.com/1503119 [ Mac11 ] external/wpt/webtransport/echo-large-bidirectional-streams.https.any.html [ Timeout ]
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites index 1f1d346..db35e55c 100644 --- a/third_party/blink/web_tests/VirtualTestSuites +++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -1654,6 +1654,103 @@ "expires": "Mar 1, 2024" }, { + "prefix": "boost-image-set-loading-task-priority", + "platforms": ["Linux"], + "bases": [ + "fast/dom/HTMLImageElement/image-sizes-js-change.html" + ], + "args": [ + "--enable-features=BoostImageSetLoadingTaskPriority" + ], + "owners": [ + "pdr@chromium.org", + "shaseley@chromium.org" + ], + "expires": "May 1, 2024" + }, + { + "prefix": "boost-font-loading-task-priority", + "platforms": ["Linux"], + "bases": [ + "external/wpt/css/css-fonts/font-display/font-display.html" + ], + "args": [ + "--enable-features=BoostFontLoadingTaskPriority" + ], + "owners": [ + "pdr@chromium.org", + "shaseley@chromium.org" + ], + "expires": "May 1, 2024" + }, + { + "prefix": "boost-video-loading-task-priority", + "platforms": ["Linux"], + "bases": [ + "media/video-src-change.html" + ], + "args": [ + "--enable-features=BoostVideoLoadingTaskPriority" + ], + "owners": [ + "pdr@chromium.org", + "shaseley@chromium.org" + ], + "expires": "May 1, 2024" + }, + "Boost non render blocking style loading task priority.", + { + "prefix": "boost-non-render-blocking-style-priority", + "platforms": ["Linux"], + "bases": [ + "external/wpt/css/cssom/HTMLLinkElement-load-event-002.html" + ], + "args": [ + "--enable-features=BoostNonRenderBlockingStyleLoadingTaskPriority" + ], + "owners": [ + "pdr@chromium.org", + "shaseley@chromium.org" + ], + "expires": "May 1, 2024" + }, + "Boost render blocking style loading task priority.", + { + "prefix": "boost-render-blocking-style-priority", + "platforms": ["Linux"], + "bases": [ + "external/wpt/css/cssom/cssimportrule.html" + ], + "args": [ + "--enable-features=BoostRenderBlockingStyleLoadingTaskPriority" + ], + "owners": [ + "pdr@chromium.org", + "shaseley@chromium.org" + ], + "expires": "May 1, 2024" + }, + "Boosts all of the cases in go/boost-loading-task-priority", + { + "prefix": "boost-loading-task-priority", + "platforms": ["Linux"], + "bases": [ + "external/wpt/css/cssom/cssimportrule.html", + "external/wpt/css/cssom/HTMLLinkElement-load-event-002.html", + "media/video-src-change.html", + "external/wpt/css/css-fonts/font-display/font-display.html", + "fast/dom/HTMLImageElement/image-sizes-js-change.html" + ], + "args": [ + "--enable-features=BoostImageSetLoadingTaskPriority,BoostFontLoadingTaskPriority,BoostVideoLoadingTaskPriority,BoostNonRenderBlockingStyleLoadingTaskPriority,BoostRenderBlockingStyleLoadingTaskPriority" + ], + "owners": [ + "pdr@chromium.org", + "shaseley@chromium.org" + ], + "expires": "May 1, 2024" + }, + { "prefix": "browsing-topics", "platforms": ["Linux", "Mac", "Win"], "bases": [
diff --git a/third_party/blink/web_tests/custom-elements/element-internals-aria-element-reflection.html b/third_party/blink/web_tests/custom-elements/element-internals-aria-element-reflection.html index a249467..52de41fd 100644 --- a/third_party/blink/web_tests/custom-elements/element-internals-aria-element-reflection.html +++ b/third_party/blink/web_tests/custom-elements/element-internals-aria-element-reflection.html
@@ -7,13 +7,13 @@ class CustomElement extends HTMLElement { constructor() { super(); - this.i = this.attachInternals(); + this.internals = this.attachInternals(); } } customElements.define('custom-element', CustomElement); </script> - <custom-element></custom-element> + <custom-element id="custom1"></custom-element> <div id="activedescendant">Active descendant</div> <div id="controls">Controls</div> <div id="describedby">Described by</div> @@ -36,27 +36,51 @@ ['ariaOwnsElements', 'owns']]; test(t => { - const custom = document.body.querySelector('custom-element'); + const custom = document.getElementById('custom1'); for (const [property, id] of element_properties) { - assert_equals(custom.i[property], null, `Could not retrieve ${property} from ElementInternals`); + assert_equals(custom.internals[property], null, `Could not retrieve ${property} from ElementInternals`); } for (const [property, id] of array_properties) { - assert_equals(custom.i[property], null, `Could not retrieve ${property} from ElementInternals`); + assert_equals(custom.internals[property], null, `Could not retrieve ${property} from ElementInternals`); } }, "Getting previously-unset ARIA element reflection properties on ElementInternals should return null, and not crash"); test(t => { - const custom = document.body.querySelector('custom-element'); + const custom = document.getElementById('custom1'); for (const [property, id] of element_properties) { const related = document.getElementById(id); - custom.i[property] = related; - assert_equals(custom.i[property], related, `Could not retrieve ${property} from ElementInternals`); + custom.internals[property] = related; + assert_equals(custom.internals[property], related, `Could not retrieve ${property} from ElementInternals`); } for (const [property, id] of array_properties) { const related = document.getElementById(id); - custom.i[property] = [related]; - assert_array_equals(custom.i[property], [related], `Could not retrieve ${property} from ElementInternals`); + custom.internals[property] = [related]; + assert_array_equals(custom.internals[property], [related], `Could not retrieve ${property} from ElementInternals`); } }, "Getting ARIA element reflection properties on ElementInternals should return the value that was set, and not crash"); + + test(t => { + const custom = document.getElementById('custom1'); + for (const [property, id] of element_properties) { + const related = document.getElementById(id); + custom.internals[property] = related; + assert_equals(custom.internals[property], related); + + custom.internals[property] = null; + assert_equals(custom.internals[property], null, `Could not retrieve null ${property} from ElementInternals`); + } + for (const [property, id] of array_properties) { + const related = document.getElementById(id); + custom.internals[property] = [related]; + assert_array_equals(custom.internals[property], [related]); + + custom.internals[property] = []; + assert_array_equals(custom.internals[property], []); + + custom.internals[property] = null; + assert_equals(custom.internals[property], null, `Could not retrieve ${property} from ElementInternals`); + } + }, "Setting ARIA element reflection properties on ElementInternals to null should delete any previous value, and not crash"); + </script> -</body> +</body> \ No newline at end of file
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 f3b6686..34db7ce 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
@@ -63,6 +63,13 @@ {} ] ], + "aria-owned-with-role-change.html": [ + "c5b2130969c018dce682e2d1a404570f5c26f4e9", + [ + null, + {} + ] + ], "aria-owns-destroyed-by-content-replacement.html": [ "b64ebaa6024f50f68249204d21b60b1a2109179b", [ @@ -98,6 +105,13 @@ {} ] ], + "aria-owns-with-role-change.html": [ + "13e1eaff6dd097c06d6275ebc9fe6646850454bf", + [ + null, + {} + ] + ], "bdo-table-cell.html": [ "ae12541f8d8cb97248a7a7f3a3683f753aa96377", [ @@ -290321,15 +290335,15 @@ ], "derive_bits_keys": { "cfrg_curves_bits.https.any-expected.txt": [ - "6c24f78fa10b6691207b0fdcce14569b7d0c774c", + "f0efe8e79931b6f6de9581b8ef578162c704196d", [] ], "cfrg_curves_bits.https.any.worker-expected.txt": [ - "6c24f78fa10b6691207b0fdcce14569b7d0c774c", + "f0efe8e79931b6f6de9581b8ef578162c704196d", [] ], "cfrg_curves_bits.js": [ - "4e12ca0eb711fae5168eb1a17db756588ef4eab6", + "ef6905e574c1581d0e5397ba9d5f955acec41b2c", [] ], "cfrg_curves_bits_fixtures.js": [ @@ -290357,7 +290371,7 @@ [] ], "ecdh_bits.js": [ - "e52ffc6bfdb6f6d4655cfa14b835adbebd088a2a", + "cb9747a529fd53530df926ddc99759e5a9126ee9", [] ], "ecdh_keys.js": [ @@ -290397,7 +290411,7 @@ [] ], "hkdf.js": [ - "2bb58533473eb9997151b43d342b7ef9ec06701d", + "3903da5cddff941c9ff82b19b0967ba41f0737f5", [] ], "hkdf_vectors.js": [ @@ -290477,7 +290491,7 @@ [] ], "pbkdf2.js": [ - "0403f382e1479c7c5018e91aba2ceb31b89998dc", + "4e4ae79d800a402b7a0933b752da9a5fb151bc2f", [] ], "pbkdf2_vectors.js": [ @@ -343827,7 +343841,7 @@ [] ], "cssstyledeclaration-csstext-all-shorthand-expected.txt": [ - "073ac7545b4d7c5e365b37a90089ffb917bca3f4", + "49cc4f9fc9a173d6057e3640301d0a683acd0635", [] ], "cssstyledeclaration-csstext-expected.txt": [ @@ -362204,6 +362218,10 @@ "b450c530ad031e1e0dcefc456be0b1ed10e2cded", [] ], + "dir-assorted.window-expected.txt": [ + "3ca95eb87ec727376dcdce80a9e01209d19b1d6a", + [] + ], "dir-shadow-01-ref.html": [ "3462b908b3df0d5550e74fa2ea93e9b2ff959b9b", [] @@ -396268,11 +396286,11 @@ [] ], "elementwise_unary.https.any-expected.txt": [ - "9fdb626319cca2f172ef8179356dab207e64da0f", + "a11e68d8b08a475139166b86754c7cadeb791cea", [] ], "elementwise_unary.https.any.worker-expected.txt": [ - "40d851efd058a1ed37ba820e91b638ca604c9eb6", + "ce037b1a3346ba752e8742e2e01a9a4ad740644f", [] ], "elu.https.any-expected.txt": [ @@ -396300,11 +396318,11 @@ [] ], "hard_sigmoid.https.any-expected.txt": [ - "a6dcfda56729e4c27d13cfacaaf6931d3144f5e5", + "17e72f17a0ccb9c6e2eb15a95c745ca94dd62d39", [] ], "hard_sigmoid.https.any.worker-expected.txt": [ - "3406fcea5517acf68af941a859d2dd7d72f51bf2", + "40e838b8951361508bf0ef73cbea05dd924119d3", [] ], "hard_swish.https.any.worker-expected.txt": [ @@ -396312,11 +396330,11 @@ [] ], "idlharness.https.any-expected.txt": [ - "f335321c701a7fdfe3c57de5a05025d51483b321", + "d1751d0346b82f35c9bbbbc572a55deb81bf17a8", [] ], "idlharness.https.any.worker-expected.txt": [ - "bfc4b9ac5a56439425525b43fd3c2c4c11c46e52", + "1ff95783a70afcc82c75f6eadbfdf5e8756af5c4", [] ], "leaky_relu.https.any.worker-expected.txt": [ @@ -480471,6 +480489,13 @@ "dom/observable/tentative/observable-event-target.any.worker.html", {} ] + ], + "observable-event-target.window.js": [ + "77a137a3622e8dbbfb4c3f177f512c0cd509b509", + [ + "dom/observable/tentative/observable-event-target.window.html", + {} + ] ] } }, @@ -500964,6 +500989,13 @@ {} ] ], + "report-event-sandboxed-iframe.https.html": [ + "7298f39e6945255de783362396fc89f9754b6ef0", + [ + null, + {} + ] + ], "resize-lock-input.https.html": [ "261c9a737eff4b85723214b7f4735b8fe9423a65", [ @@ -517200,9 +517232,9 @@ ] ], "direct-from-seller-signals.https.window.js": [ - "0ae1efd8d3780efe9ff1a0886e6f79d4c17c2558", + "339bc32ee564320d155f43e1a555847da7ec125b", [ - "fledge/tentative/direct-from-seller-signals.https.window.html?1-5", + "fledge/tentative/direct-from-seller-signals.https.window.html?1-4", { "script_metadata": [ [ @@ -517227,30 +517259,42 @@ ], [ "variant", - "?1-5" + "?1-4" ], [ "variant", - "?6-10" + "?5-8" ], [ "variant", - "?11-15" + "?9-12" ], [ "variant", - "?16-20" + "?13-16" ], [ "variant", - "?21-last" + "?17-20" + ], + [ + "variant", + "?21-24" + ], + [ + "variant", + "?25-28" + ], + [ + "variant", + "?29-last" ] ], "timeout": "long" } ], [ - "fledge/tentative/direct-from-seller-signals.https.window.html?11-15", + "fledge/tentative/direct-from-seller-signals.https.window.html?13-16", { "script_metadata": [ [ @@ -517275,30 +517319,42 @@ ], [ "variant", - "?1-5" + "?1-4" ], [ "variant", - "?6-10" + "?5-8" ], [ "variant", - "?11-15" + "?9-12" ], [ "variant", - "?16-20" + "?13-16" ], [ "variant", - "?21-last" + "?17-20" + ], + [ + "variant", + "?21-24" + ], + [ + "variant", + "?25-28" + ], + [ + "variant", + "?29-last" ] ], "timeout": "long" } ], [ - "fledge/tentative/direct-from-seller-signals.https.window.html?16-20", + "fledge/tentative/direct-from-seller-signals.https.window.html?17-20", { "script_metadata": [ [ @@ -517323,30 +517379,42 @@ ], [ "variant", - "?1-5" + "?1-4" ], [ "variant", - "?6-10" + "?5-8" ], [ "variant", - "?11-15" + "?9-12" ], [ "variant", - "?16-20" + "?13-16" ], [ "variant", - "?21-last" + "?17-20" + ], + [ + "variant", + "?21-24" + ], + [ + "variant", + "?25-28" + ], + [ + "variant", + "?29-last" ] ], "timeout": "long" } ], [ - "fledge/tentative/direct-from-seller-signals.https.window.html?21-last", + "fledge/tentative/direct-from-seller-signals.https.window.html?21-24", { "script_metadata": [ [ @@ -517371,30 +517439,42 @@ ], [ "variant", - "?1-5" + "?1-4" ], [ "variant", - "?6-10" + "?5-8" ], [ "variant", - "?11-15" + "?9-12" ], [ "variant", - "?16-20" + "?13-16" ], [ "variant", - "?21-last" + "?17-20" + ], + [ + "variant", + "?21-24" + ], + [ + "variant", + "?25-28" + ], + [ + "variant", + "?29-last" ] ], "timeout": "long" } ], [ - "fledge/tentative/direct-from-seller-signals.https.window.html?6-10", + "fledge/tentative/direct-from-seller-signals.https.window.html?25-28", { "script_metadata": [ [ @@ -517419,23 +517499,215 @@ ], [ "variant", - "?1-5" + "?1-4" ], [ "variant", - "?6-10" + "?5-8" ], [ "variant", - "?11-15" + "?9-12" ], [ "variant", - "?16-20" + "?13-16" ], [ "variant", - "?21-last" + "?17-20" + ], + [ + "variant", + "?21-24" + ], + [ + "variant", + "?25-28" + ], + [ + "variant", + "?29-last" + ] + ], + "timeout": "long" + } + ], + [ + "fledge/tentative/direct-from-seller-signals.https.window.html?29-last", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/common/utils.js" + ], + [ + "script", + "resources/fledge-util.sub.js" + ], + [ + "script", + "/common/subset-tests.js" + ], + [ + "timeout", + "long" + ], + [ + "variant", + "?1-4" + ], + [ + "variant", + "?5-8" + ], + [ + "variant", + "?9-12" + ], + [ + "variant", + "?13-16" + ], + [ + "variant", + "?17-20" + ], + [ + "variant", + "?21-24" + ], + [ + "variant", + "?25-28" + ], + [ + "variant", + "?29-last" + ] + ], + "timeout": "long" + } + ], + [ + "fledge/tentative/direct-from-seller-signals.https.window.html?5-8", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/common/utils.js" + ], + [ + "script", + "resources/fledge-util.sub.js" + ], + [ + "script", + "/common/subset-tests.js" + ], + [ + "timeout", + "long" + ], + [ + "variant", + "?1-4" + ], + [ + "variant", + "?5-8" + ], + [ + "variant", + "?9-12" + ], + [ + "variant", + "?13-16" + ], + [ + "variant", + "?17-20" + ], + [ + "variant", + "?21-24" + ], + [ + "variant", + "?25-28" + ], + [ + "variant", + "?29-last" + ] + ], + "timeout": "long" + } + ], + [ + "fledge/tentative/direct-from-seller-signals.https.window.html?9-12", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/common/utils.js" + ], + [ + "script", + "resources/fledge-util.sub.js" + ], + [ + "script", + "/common/subset-tests.js" + ], + [ + "timeout", + "long" + ], + [ + "variant", + "?1-4" + ], + [ + "variant", + "?5-8" + ], + [ + "variant", + "?9-12" + ], + [ + "variant", + "?13-16" + ], + [ + "variant", + "?17-20" + ], + [ + "variant", + "?21-24" + ], + [ + "variant", + "?25-28" + ], + [ + "variant", + "?29-last" ] ], "timeout": "long" @@ -557869,7 +558141,7 @@ ] ], "dir-assorted.window.js": [ - "038b3f78d4d373286da051a6240493d0dce12112", + "0d4e4b82d9b9531087ed631fd38d9eb6ab6215e0", [ "html/dom/elements/global-attributes/dir-assorted.window.html", {} @@ -585241,6 +585513,13 @@ {} ] ], + "resized-image-not-reconsidered.html": [ + "6e195b89f9ef5dfbfc126e3fe7170d00dc93376f", + [ + null, + {} + ] + ], "same-origin-redirects.html": [ "b5cf9da2d120d4e03852954057fc7171fad9901f", [ @@ -590119,7 +590398,7 @@ ] ], "GUM-non-applicable-constraint.https.html": [ - "3e9481bfa445cfb77556bfe4b63c74faeb9298b8", + "e9fd6665dcface83218869a0a0fd1284c12f924f", [ null, { @@ -590230,7 +590509,7 @@ ] ], "MediaDevices-getSupportedConstraints.https.html": [ - "453184a16919a63ea72068538bca4f7c038957cf", + "7d374b5336ea5c12d1bf6c6d65c1766ebd2b9347", [ null, {} @@ -590397,7 +590676,7 @@ ] ], "MediaStreamTrack-getCapabilities.https.html": [ - "b67a8d51561a3d2c33047780014d890c1c2682a4", + "7d600c0e1b97c905cbeb172d0aae0a33ed961c9e", [ null, { @@ -590406,7 +590685,7 @@ ] ], "MediaStreamTrack-getSettings.https.html": [ - "1bda4c748ac5a0c0711cc231710c18ed5afa7c25", + "3bae50c346dd3c83d15f37eca598b58838250c46", [ null, {
diff --git a/third_party/blink/web_tests/external/wpt/fenced-frame/automatic-beacon-anchor-click-handler.https.html b/third_party/blink/web_tests/external/wpt/fenced-frame/automatic-beacon-anchor-click-handler.https.html index c3161fd..8ee1cb51 100644 --- a/third_party/blink/web_tests/external/wpt/fenced-frame/automatic-beacon-anchor-click-handler.https.html +++ b/third_party/blink/web_tests/external/wpt/fenced-frame/automatic-beacon-anchor-click-handler.https.html
@@ -9,6 +9,7 @@ <script src="/resources/testdriver-actions.js"></script> <script src="/resources/testdriver-vendor.js"></script> <script src="/common/get-host-info.sub.js"></script> +<script src="resources/automatic-beacon-helper.js"></script> <body> <script> @@ -18,10 +19,13 @@ {generator_api: 'fledge', automatic_beacon: true, origin: get_host_info().HTTPS_REMOTE_ORIGIN}); const new_url = new URL("resources/dummy.html", location.href); - const beacon_data = "This is the second test's beacon data!"; - const beacon_type = "reserved.top_navigation_commit"; + let beacon_event = { + eventType: "reserved.top_navigation_commit", + eventData: "This is the second test's beacon data!", + destination: ["buyer"], + } - await fencedframe.execute((new_url, beacon_data, beacon_type) => { + await fencedframe.execute((new_url, beacon_event) => { let a = document.createElement('a'); a.textContent = "Click me!"; a.href = new_url; @@ -36,16 +40,11 @@ // before the navigation happens. This test checks to make sure that the // data makes it to the correct place by the time the navigation commits. a.onclick = () => { - let beacon_event = { - eventType: beacon_type, - eventData: beacon_data, - destination: ["buyer"], - } window.fence.setReportEventDataForAutomaticBeacons(beacon_event); }; document.body.appendChild(a); - }, [new_url, beacon_data, beacon_type]); + }, [new_url, beacon_event]); // This will trigger the beacon data storing + navigation. await actions.pointerMove(0, 0, {origin: fencedframe.element}) @@ -53,9 +52,7 @@ .pointerUp() .send(); - const beacon_initiator_origin = - await nextAutomaticBeacon(beacon_type, beacon_data); - assert_equals(beacon_initiator_origin, get_host_info().HTTPS_ORIGIN); + await verifyBeaconData(beacon_event.eventType, beacon_event.eventData); // Leaving this fenced frame around for subsequent tests can lead to // flakiness.
diff --git a/third_party/blink/web_tests/external/wpt/fenced-frame/automatic-beacon-click-handler.https.html b/third_party/blink/web_tests/external/wpt/fenced-frame/automatic-beacon-click-handler.https.html index 0fe3fbb..31392fd 100644 --- a/third_party/blink/web_tests/external/wpt/fenced-frame/automatic-beacon-click-handler.https.html +++ b/third_party/blink/web_tests/external/wpt/fenced-frame/automatic-beacon-click-handler.https.html
@@ -9,6 +9,7 @@ <script src="/resources/testdriver-actions.js"></script> <script src="/resources/testdriver-vendor.js"></script> <script src="/common/get-host-info.sub.js"></script> +<script src="resources/automatic-beacon-helper.js"></script> <body> <script> @@ -17,12 +18,8 @@ const fencedframe = await attachFencedFrameContext( {generator_api: 'fledge', automatic_beacon: true, origin: get_host_info().HTTPS_REMOTE_ORIGIN}); - const new_url = new URL("resources/dummy.html", location.href); - const start_beacon_data = "This is the start beacon data!"; - const commit_beacon_data = "This is the commit beacon data!"; - await fencedframe.execute( - (new_url, start_beacon_data, commit_beacon_data) => { + await fencedframe.execute(() => { // This tests that old automatic beacon data is overwritten in subsequent // calls to setReportEventDataForAutomaticBeacons(). let start_beacon_event_old = { @@ -31,34 +28,29 @@ destination: ["buyer"], } window.fence.setReportEventDataForAutomaticBeacons(start_beacon_event_old); - addEventListener("click", (event) => { - let start_beacon_event = { - eventType: "reserved.top_navigation_start", - eventData: start_beacon_data, - destination: ["buyer"], - } - window.fence.setReportEventDataForAutomaticBeacons(start_beacon_event); - let commit_beacon_event = { - eventType: "reserved.top_navigation_commit", - eventData: commit_beacon_data, - destination: ["buyer"], - } - window.fence.setReportEventDataForAutomaticBeacons(commit_beacon_event); - window.open(new_url, "_blank"); - }); - }, [new_url, start_beacon_data, commit_beacon_data]); + }); + const start_event = { + eventType: "reserved.top_navigation_start", + eventData: "This is the start data", + destination: ["buyer"], + } + const commit_event = { + eventType: "reserved.top_navigation_commit", + eventData: "This is the commit data", + destination: ["buyer"], + } + // This will only set the automatic beacon data when the fenced frame is + // clicked. + await setupAutomaticBeacon(fencedframe, [start_event, commit_event], + NavigationTrigger.Click); await actions.pointerMove(0, 0, {origin: fencedframe.element}) .pointerDown() .pointerUp() .send(); - const beacon_1_initiator_origin = await nextAutomaticBeacon( - "reserved.top_navigation_start", start_beacon_data); - assert_equals(beacon_1_initiator_origin, get_host_info().HTTPS_ORIGIN); - const beacon_2_initiator_origin = await nextAutomaticBeacon( - "reserved.top_navigation_commit", commit_beacon_data); - assert_equals(beacon_2_initiator_origin, get_host_info().HTTPS_ORIGIN); + await verifyBeaconData(start_event.eventType, start_event.eventData); + await verifyBeaconData(commit_event.eventType, commit_event.eventData); // Leaving this fenced frame around for subsequent tests can lead to // flakiness.
diff --git a/third_party/blink/web_tests/external/wpt/fenced-frame/automatic-beacon-component-ad.https.html b/third_party/blink/web_tests/external/wpt/fenced-frame/automatic-beacon-component-ad.https.html index 132b123..1b1ef27 100644 --- a/third_party/blink/web_tests/external/wpt/fenced-frame/automatic-beacon-component-ad.https.html +++ b/third_party/blink/web_tests/external/wpt/fenced-frame/automatic-beacon-component-ad.https.html
@@ -8,6 +8,8 @@ <script src="/resources/testdriver.js"></script> <script src="/resources/testdriver-actions.js"></script> <script src="/resources/testdriver-vendor.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script src="resources/automatic-beacon-helper.js"></script> <body> <script> @@ -21,16 +23,14 @@ headers: [["Allow-Fenced-Frame-Automatic-Beacons", "true"]] }); const new_url = new URL("resources/close.html", location.href); - const beacon_type = "reserved.top_navigation_start"; - const beacon_data = "this is the beacon data"; + const beacon_event = { + eventType: "reserved.top_navigation_start", + eventData: "this is the beacon data", + destination: ["buyer"], + crossOriginExposed: true, + } - await fencedframe.execute(async (new_url, beacon_type, beacon_data) => { - let beacon_event = { - eventType: beacon_type, - eventData: "this is the beacon data", - destination: ["buyer"], - crossOriginExposed: true, - } + await fencedframe.execute(async (new_url, beacon_event) => { window.fence.setReportEventDataForAutomaticBeacons(beacon_event); // Add an ad component that will perform the top-level navigation. @@ -41,7 +41,7 @@ window.open(new_url); }); }, [new_url]); - }, [new_url, beacon_type]); + }, [new_url, beacon_event]); await actions.pointerMove(0, 0, {origin: fencedframe.element}) .pointerDown() @@ -49,9 +49,7 @@ .send(); // The component frame should not use the data set in its parent. - const expected_beacon_data = "<No data>"; - const received_beacon_data = await nextAutomaticBeacon( - beacon_type, expected_beacon_data); + await verifyBeaconData(beacon_event.eventType, "<No data>"); }, 'Automatic beacon in an ad component should send without data with a ' + 'header opt-in.'); </script>
diff --git a/third_party/blink/web_tests/external/wpt/fenced-frame/automatic-beacon-cross-origin-false.https.html b/third_party/blink/web_tests/external/wpt/fenced-frame/automatic-beacon-cross-origin-false.https.html index ccd86349..24440e4 100644 --- a/third_party/blink/web_tests/external/wpt/fenced-frame/automatic-beacon-cross-origin-false.https.html +++ b/third_party/blink/web_tests/external/wpt/fenced-frame/automatic-beacon-cross-origin-false.https.html
@@ -9,6 +9,8 @@ <script src="/resources/testdriver.js"></script> <script src="/resources/testdriver-actions.js"></script> <script src="/resources/testdriver-vendor.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script src="resources/automatic-beacon-helper.js"></script> <body> <script> @@ -18,38 +20,22 @@ generator_api: 'fledge', automatic_beacon: true, }); - const new_url = new URL("resources/close.html", location.href); - const beacon_type = "reserved.top_navigation_start"; + const beacon_event = { + eventType: "reserved.top_navigation_start", + eventData: "this is the beacon data", + destination: ["buyer"], + crossOriginExposed: false, + } - await fencedframe.execute(async (new_url, beacon_type) => { - let beacon_event = { - eventType: beacon_type, - eventData: "this is the beacon data", - destination: ["buyer"], - crossOriginExposed: false, - } - window.fence.setReportEventDataForAutomaticBeacons(beacon_event); - - // Add a cross-origin iframe that will perform the top-level navigation. - const iframe = await attachIFrameContext({ - origin: get_host_info().HTTPS_REMOTE_ORIGIN, - headers: [["Allow-Fenced-Frame-Automatic-Beacons", "true"]], - }); - await iframe.execute(async (new_url) => { - addEventListener("click", (event) => { - window.open(new_url); - }); - }, [new_url]); - }, [new_url, beacon_type]); + await setupAutomaticBeacon(fencedframe, [beacon_event], + "resources/close.html", NavigationTrigger.CrossOriginClick); await actions.pointerMove(0, 0, {origin: fencedframe.element}) .pointerDown() .pointerUp() .send(); - const expected_beacon_data = "<No data>"; - const received_beacon_data = await nextAutomaticBeacon( - "reserved.top_navigation_start", expected_beacon_data); + await verifyBeaconData(beacon_event.eventType, "<No data>"); }, 'Automatic beacon in a cross-origin subframe should send without data ' + 'when crossOrigin=false.'); </script>
diff --git a/third_party/blink/web_tests/external/wpt/fenced-frame/automatic-beacon-cross-origin-navigation.https.html b/third_party/blink/web_tests/external/wpt/fenced-frame/automatic-beacon-cross-origin-navigation.https.html index 5a19117..c476e804 100644 --- a/third_party/blink/web_tests/external/wpt/fenced-frame/automatic-beacon-cross-origin-navigation.https.html +++ b/third_party/blink/web_tests/external/wpt/fenced-frame/automatic-beacon-cross-origin-navigation.https.html
@@ -8,6 +8,8 @@ <script src="/resources/testdriver.js"></script> <script src="/resources/testdriver-actions.js"></script> <script src="/resources/testdriver-vendor.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script src="resources/automatic-beacon-helper.js"></script> <body> <script> @@ -17,30 +19,16 @@ generator_api: 'fledge', automatic_beacon: true }); - const new_url = new URL("resources/close.html", location.href); - const beacon_data = "this is the beacon data"; - const beacon_type = "reserved.top_navigation_start"; - await fencedframe.execute(async (new_url, beacon_data, beacon_type) => { - let beacon_event = { - eventType: beacon_type, - eventData: beacon_data, - destination: ["buyer"], - crossOriginExposed: true, - } - window.fence.setReportEventDataForAutomaticBeacons(beacon_event); + let beacon_event = { + eventType: "reserved.top_navigation_start", + eventData: "this is the beacon data", + destination: ["buyer"], + crossOriginExposed: true, + } - // Add a cross-origin iframe that will perform the top-level navigation. - const iframe = await attachIFrameContext({ - origin: get_host_info().HTTPS_REMOTE_ORIGIN, - headers: [["Allow-Fenced-Frame-Automatic-Beacons", "true"]] - }); - await iframe.execute(async (new_url) => { - addEventListener("click", (event) => { - window.open(new_url, "_blank"); - }); - }, [new_url]); - }, [new_url, beacon_data, beacon_type]); + await setupAutomaticBeacon(fencedframe, [beacon_event], + "resources/close.html", NavigationTrigger.CrossOriginClick); await actions.pointerMove(0, 0, {origin: fencedframe.element}) .pointerDown() @@ -48,7 +36,7 @@ .send(); const received_beacon_data = - await nextAutomaticBeacon(beacon_type, beacon_data); + await nextAutomaticBeacon(beacon_event.eventType, beacon_event.eventData); }, 'Automatic beacon in a cross-origin subframe'); </script> </body>
diff --git a/third_party/blink/web_tests/external/wpt/fenced-frame/automatic-beacon-cross-origin-no-data.https.html b/third_party/blink/web_tests/external/wpt/fenced-frame/automatic-beacon-cross-origin-no-data.https.html index 1b57100..dd00721 100644 --- a/third_party/blink/web_tests/external/wpt/fenced-frame/automatic-beacon-cross-origin-no-data.https.html +++ b/third_party/blink/web_tests/external/wpt/fenced-frame/automatic-beacon-cross-origin-no-data.https.html
@@ -8,6 +8,8 @@ <script src="/resources/testdriver.js"></script> <script src="/resources/testdriver-actions.js"></script> <script src="/resources/testdriver-vendor.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script src="resources/automatic-beacon-helper.js"></script> <body> <script> @@ -38,13 +40,8 @@ .pointerUp() .send(); - const expected_beacon_data = "<No data>"; - const received_beacon_data = - await nextAutomaticBeacon( - "reserved.top_navigation_start", expected_beacon_data); - const received_beacon_data_commit = - await nextAutomaticBeacon( - "reserved.top_navigation_commit", expected_beacon_data); + await verifyBeaconData("reserved.top_navigation_start", "<No data>"); + await verifyBeaconData("reserved.top_navigation_commit", "<No data>"); }, 'Automatic beacon in a cross-origin subframe with no beacon data set'); </script> </body>
diff --git a/third_party/blink/web_tests/external/wpt/fenced-frame/automatic-beacon-cross-origin-no-opt-in.https.html b/third_party/blink/web_tests/external/wpt/fenced-frame/automatic-beacon-cross-origin-no-opt-in.https.html index 6d43a73..fa19d17 100644 --- a/third_party/blink/web_tests/external/wpt/fenced-frame/automatic-beacon-cross-origin-no-opt-in.https.html +++ b/third_party/blink/web_tests/external/wpt/fenced-frame/automatic-beacon-cross-origin-no-opt-in.https.html
@@ -8,6 +8,8 @@ <script src="/resources/testdriver.js"></script> <script src="/resources/testdriver-actions.js"></script> <script src="/resources/testdriver-vendor.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script src="resources/automatic-beacon-helper.js"></script> <body> <script> @@ -17,41 +19,26 @@ generator_api: 'fledge', automatic_beacon: true }); - const new_url = new URL("resources/close.html", location.href); - const beacon_data = "this is the beacon data"; - const beacon_type = "reserved.top_navigation_start"; - await fencedframe.execute(async (new_url, beacon_data, beacon_type) => { - let beacon_event = { - eventType: beacon_type, - eventData: beacon_data, - destination: ["buyer"], - crossOriginExposed: true, - } - window.fence.setReportEventDataForAutomaticBeacons(beacon_event); - - // Add a cross-origin iframe that will perform the top-level navigation. - // Do not set the 'Allow-Fenced-Frame-Automatic-Beacons' header to true. - const iframe = await attachIFrameContext({ - origin: get_host_info().HTTPS_REMOTE_ORIGIN, - headers: [["Allow-Fenced-Frame-Automatic-Beacons", "false"]] - }); - await iframe.execute(async (new_url) => { - addEventListener("click", (event) => { - window.open(new_url, "_blank"); - }); - }, [new_url]); - }, [new_url, beacon_data, beacon_type]); + let beacon_event = { + eventType: "reserved.top_navigation_start", + eventData: "this is the beacon data", + destination: ["buyer"], + crossOriginExposed: true, + } + // Add a cross-origin iframe that will perform the top-level navigation. + // Do not set the 'Allow-Fenced-Frame-Automatic-Beacons' header to true. + await setupAutomaticBeacon(fencedframe, [beacon_event], + "resources/close.html", NavigationTrigger.CrossOriginClickNoOptIn, + "_blank"); await actions.pointerMove(0, 0, {origin: fencedframe.element}) .pointerDown() .pointerUp() .send(); - const timeout = new Promise(resolve => t.step_timeout(resolve, 1000)); - const result = await Promise.race( - [nextAutomaticBeacon(beacon_type, beacon_data), timeout]); - assert_true(typeof result === "undefined"); + await verifyBeaconData(beacon_event.eventType, beacon_event.eventData, false, + t); }, 'Automatic beacon in a cross-origin subframe with no opt-in header should ' + 'not send.'); </script>
diff --git a/third_party/blink/web_tests/external/wpt/fenced-frame/automatic-beacon-no-destination.https.html b/third_party/blink/web_tests/external/wpt/fenced-frame/automatic-beacon-no-destination.https.html index c3fa3d6..696c17f 100644 --- a/third_party/blink/web_tests/external/wpt/fenced-frame/automatic-beacon-no-destination.https.html +++ b/third_party/blink/web_tests/external/wpt/fenced-frame/automatic-beacon-no-destination.https.html
@@ -9,6 +9,7 @@ <script src="/resources/testdriver-actions.js"></script> <script src="/resources/testdriver-vendor.js"></script> <script src="/common/get-host-info.sub.js"></script> +<script src="resources/automatic-beacon-helper.js"></script> <body> <script> @@ -19,24 +20,13 @@ automatic_beacon: true, origin: get_host_info().HTTPS_REMOTE_ORIGIN }); - const new_url = new URL("resources/dummy.html", location.href); - const beacon_data = "This is the beacon data!"; - const beacon_type = "reserved.top_navigation_commit"; - await fencedframe.execute( - (new_url, beacon_data, beacon_type) => { - addEventListener("click", (event) => { - let beacon_event = { - eventType: beacon_type, - eventData: beacon_data, - destination: ["component-seller"], - }; - window.fence.setReportEventDataForAutomaticBeacons(beacon_event); - window.open(new_url, "_blank"); - }); - }, - [new_url, beacon_data, beacon_type] - ); + let beacon_event = { + eventType: "reserved.top_navigation_commit", + eventData: "This is the beacon data!", + destination: ["component-seller"], + }; + await setupAutomaticBeacon(fencedframe, [beacon_event]); await actions .pointerMove(0, 0, { origin: fencedframe.element }) @@ -47,10 +37,7 @@ // An automatic beacon should be sent out, but no data should be sent as part // of the beacon because the "buyer" destination was not specified in // setReportEventDataForAutomaticBeacons(). - const expected_data = "<No data>"; - const beacon_initiator_origin = - await nextAutomaticBeacon(beacon_type, expected_data); - assert_equals(beacon_initiator_origin, get_host_info().HTTPS_ORIGIN); + await verifyBeaconData(beacon_event.eventType, "<No data>"); }, "Set and trigger an automatic beacon with no destination specified"); </script>
diff --git a/third_party/blink/web_tests/external/wpt/fenced-frame/automatic-beacon-no-opt-in.https.html b/third_party/blink/web_tests/external/wpt/fenced-frame/automatic-beacon-no-opt-in.https.html index 5a815a8..177a7c6 100644 --- a/third_party/blink/web_tests/external/wpt/fenced-frame/automatic-beacon-no-opt-in.https.html +++ b/third_party/blink/web_tests/external/wpt/fenced-frame/automatic-beacon-no-opt-in.https.html
@@ -8,6 +8,8 @@ <script src="/resources/testdriver.js"></script> <script src="/resources/testdriver-actions.js"></script> <script src="/resources/testdriver-vendor.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script src="resources/automatic-beacon-helper.js"></script> <body> <script> @@ -38,11 +40,8 @@ .pointerDown() .pointerUp() .send(); - const timeout = new Promise(resolve => t.step_timeout(resolve, 1000)); - const result = await Promise.race( - [nextAutomaticBeacon("reserved.top_navigation_start", "<No data>"), - timeout]); - assert_true(typeof result === "undefined"); + await verifyBeaconData("reserved.top_navigation_start", "<No data>", false, + t); }, "Automatic beacons will not send if the document does not opt in."); </script>
diff --git a/third_party/blink/web_tests/external/wpt/fenced-frame/automatic-beacon-shared-storage.https.html b/third_party/blink/web_tests/external/wpt/fenced-frame/automatic-beacon-shared-storage.https.html index 093e55b..4ee1d0d0 100644 --- a/third_party/blink/web_tests/external/wpt/fenced-frame/automatic-beacon-shared-storage.https.html +++ b/third_party/blink/web_tests/external/wpt/fenced-frame/automatic-beacon-shared-storage.https.html
@@ -10,6 +10,7 @@ <script src="/resources/testdriver-actions.js"></script> <script src="/resources/testdriver-vendor.js"></script> <script src="/common/get-host-info.sub.js"></script> +<script src="resources/automatic-beacon-helper.js"></script> <body> <script> @@ -18,40 +19,26 @@ const fencedframe = await attachFencedFrameContext( {generator_api: 'sharedstorage', origin: get_host_info().HTTPS_REMOTE_ORIGIN}); - const new_url = new URL("resources/dummy.html", location.href); - const start_beacon_data = "This is the start beacon data!"; - const commit_beacon_data = "This is the commit beacon data!"; - await fencedframe.execute((new_url, start_beacon_data, - commit_beacon_data) => { - addEventListener("click", (event) => { - let start_beacon_event = { - eventType: "reserved.top_navigation_start", - eventData: start_beacon_data, - destination: ["shared-storage-select-url"], - } - window.fence.setReportEventDataForAutomaticBeacons(start_beacon_event); - let commit_beacon_event = { - eventType: "reserved.top_navigation_commit", - eventData: commit_beacon_data, - destination: ["shared-storage-select-url"], - } - window.fence.setReportEventDataForAutomaticBeacons(commit_beacon_event); - window.open(new_url, "_blank"); - }); - }, [new_url, start_beacon_data, commit_beacon_data]); + let start_event = { + eventType: "reserved.top_navigation_start", + eventData: "This is the start beacon data!", + destination: ["shared-storage-select-url"], + } + let commit_event = { + eventType: "reserved.top_navigation_commit", + eventData: "This is the commit beacon data!", + destination: ["shared-storage-select-url"], + } + await setupAutomaticBeacon(fencedframe, [start_event, commit_event]); await actions.pointerMove(0, 0, {origin: fencedframe.element}) .pointerDown() .pointerUp() .send(); - const beacon_1_initiator_origin = await nextAutomaticBeacon( - "reserved.top_navigation_start", start_beacon_data); - assert_equals(beacon_1_initiator_origin, get_host_info().HTTPS_ORIGIN); - const beacon_2_initiator_origin = await nextAutomaticBeacon( - "reserved.top_navigation_commit", commit_beacon_data); - assert_equals(beacon_2_initiator_origin, get_host_info().HTTPS_ORIGIN); + await verifyBeaconData(start_event.eventType, start_event.eventData); + await verifyBeaconData(commit_event.eventType, commit_event.eventData); }, 'Set and trigger an automatic beacon in a click handler for SharedStorage'); </script>
diff --git a/third_party/blink/web_tests/external/wpt/fenced-frame/automatic-beacon-two-events-clear.https.html b/third_party/blink/web_tests/external/wpt/fenced-frame/automatic-beacon-two-events-clear.https.html index f59fda5..f759c062 100644 --- a/third_party/blink/web_tests/external/wpt/fenced-frame/automatic-beacon-two-events-clear.https.html +++ b/third_party/blink/web_tests/external/wpt/fenced-frame/automatic-beacon-two-events-clear.https.html
@@ -9,6 +9,7 @@ <script src="/resources/testdriver-actions.js"></script> <script src="/resources/testdriver-vendor.js"></script> <script src="/common/get-host-info.sub.js"></script> +<script src="resources/automatic-beacon-helper.js"></script> <body> <script> @@ -17,22 +18,15 @@ const fencedframe = await attachFencedFrameContext( {generator_api: 'fledge', automatic_beacon: true, origin: get_host_info().HTTPS_REMOTE_ORIGIN}); - const new_url = new URL("resources/dummy.html", location.href); - const beacon_data = "This is the beacon data!"; - const beacon_type = "reserved.top_navigation_commit"; - await fencedframe.execute((new_url, beacon_data, beacon_type) => { - let beacon_event = { - eventType: beacon_type, - eventData: beacon_data, - destination: ["buyer"], - once: true, - } - window.fence.setReportEventDataForAutomaticBeacons(beacon_event); - addEventListener("click", (event) => { - window.open(new_url, "_blank"); - }); - }, [new_url, beacon_data, beacon_type]); + let beacon_event = { + eventType: "reserved.top_navigation_commit", + eventData: "This is the beacon data!", + destination: ["buyer"], + once: true, + } + await setupAutomaticBeacon(fencedframe, [beacon_event], + "resources/dummy.html", NavigationTrigger.ClickOnce); // The first click should trigger the automatic beacon and clear the beacon // data. @@ -40,9 +34,7 @@ .pointerDown() .pointerUp() .send(); - const beacon_initiator_origin = - await nextAutomaticBeacon(beacon_type, beacon_data); - assert_equals(beacon_initiator_origin, get_host_info().HTTPS_ORIGIN); + await verifyBeaconData(beacon_event.eventType, beacon_event.eventData); // The second click should not have any associated automatic beacon info, so // no beacon should be sent. @@ -52,10 +44,8 @@ .pointerDown() .pointerUp() .send(); - const timeout = new Promise(resolve => t.step_timeout(resolve, 1000)); - const result = await Promise.race( - [nextAutomaticBeacon(beacon_type, beacon_data), timeout]); - assert_true(typeof result === "undefined"); + await verifyBeaconData(beacon_event.eventType, beacon_event.eventData, false, + t); }, 'Set expiring automatic beacon but trigger two events in a click handler'); </script>
diff --git a/third_party/blink/web_tests/external/wpt/fenced-frame/automatic-beacon-two-events-persist.https.html b/third_party/blink/web_tests/external/wpt/fenced-frame/automatic-beacon-two-events-persist.https.html index 4da4f89..906a7a0 100644 --- a/third_party/blink/web_tests/external/wpt/fenced-frame/automatic-beacon-two-events-persist.https.html +++ b/third_party/blink/web_tests/external/wpt/fenced-frame/automatic-beacon-two-events-persist.https.html
@@ -9,6 +9,7 @@ <script src="/resources/testdriver-actions.js"></script> <script src="/resources/testdriver-vendor.js"></script> <script src="/common/get-host-info.sub.js"></script> +<script src="resources/automatic-beacon-helper.js"></script> <body> <script> @@ -17,22 +18,14 @@ const fencedframe = await attachFencedFrameContext( {generator_api: 'fledge', automatic_beacon: true, origin: get_host_info().HTTPS_REMOTE_ORIGIN}); - const new_url = new URL("resources/dummy.html", location.href); - const beacon_data = "This is the beacon data!"; - const beacon_type = "reserved.top_navigation_commit"; + // `once` defaults to false. + let beacon_event = { + eventType: "reserved.top_navigation_commit", + eventData: "This is the beacon data!", + destination: ["buyer"], + } - await fencedframe.execute((new_url, beacon_data, beacon_type) => { - // `once` defaults to false. - let beacon_event = { - eventType: beacon_type, - eventData: beacon_data, - destination: ["buyer"], - } - window.fence.setReportEventDataForAutomaticBeacons(beacon_event); - addEventListener("click", (event) => { - window.open(new_url, "_blank"); - }); - }, [new_url, beacon_data, beacon_type]); + await setupAutomaticBeacon(fencedframe, [beacon_event]); // The first click should trigger the automatic beacon, but the beacon data // should not be cleared out. @@ -40,9 +33,7 @@ .pointerDown() .pointerUp() .send(); - const beacon_1_initiator_origin = - await nextAutomaticBeacon(beacon_type, beacon_data); - assert_equals(beacon_1_initiator_origin, get_host_info().HTTPS_ORIGIN); + await verifyBeaconData(beacon_event.eventType, beacon_event.eventData); // The second click should still have associated automatic beacon data, and a // beacon should be sent. @@ -50,9 +41,7 @@ .pointerDown() .pointerUp() .send(); - const beacon_2_initiator_origin = - await nextAutomaticBeacon(beacon_type, beacon_data); - assert_equals(beacon_2_initiator_origin, get_host_info().HTTPS_ORIGIN); + await verifyBeaconData(beacon_event.eventType, beacon_event.eventData); }, 'Set persisting automatic beacon but trigger two events in a click handler'); </script>
diff --git a/third_party/blink/web_tests/external/wpt/fenced-frame/automatic-beacon-unfenced-top.https.html b/third_party/blink/web_tests/external/wpt/fenced-frame/automatic-beacon-unfenced-top.https.html index 945e8092..342e133 100644 --- a/third_party/blink/web_tests/external/wpt/fenced-frame/automatic-beacon-unfenced-top.https.html +++ b/third_party/blink/web_tests/external/wpt/fenced-frame/automatic-beacon-unfenced-top.https.html
@@ -9,6 +9,7 @@ <script src="/resources/testdriver-actions.js"></script> <script src="/resources/testdriver-vendor.js"></script> <script src="/common/get-host-info.sub.js"></script> +<script src="resources/automatic-beacon-helper.js"></script> <body> <script> @@ -27,22 +28,16 @@ const fencedframe = await attachFencedFrameContext( {generator_api: 'fledge', automatic_beacon: true, origin: get_host_info().HTTPS_REMOTE_ORIGIN}); - const new_url = new URL("resources/automatic-beacon-unfenced-page.html", - location.href); - await fencedframe.execute((new_url) => { - const beacon_data = "This is the beacon data!"; - let beacon_event = { - eventType: "reserved.top_navigation_commit", - eventData: beacon_data, - destination: ["buyer"], - randomField: "blah", - } - window.fence.setReportEventDataForAutomaticBeacons(beacon_event); - addEventListener("click", (event) => { - window.open(new_url, "_unfencedTop"); - }); - }, [new_url]); + const beacon_event = { + eventType: "reserved.top_navigation_commit", + eventData: "This is the beacon data!", + destination: ["buyer"], + randomField: "blah", + } + await setupAutomaticBeacon(fencedframe, [beacon_event], + "resources/automatic-beacon-unfenced-page.html", NavigationTrigger.Click, + "_unfencedTop"); await actions.setContext(window) .pointerMove(0, 0, {origin: fencedframe.element})
diff --git a/third_party/blink/web_tests/external/wpt/fenced-frame/resize-lock-input.https.html b/third_party/blink/web_tests/external/wpt/fenced-frame/resize-lock-input.https.html index 261c9a73..9cee650 100644 --- a/third_party/blink/web_tests/external/wpt/fenced-frame/resize-lock-input.https.html +++ b/third_party/blink/web_tests/external/wpt/fenced-frame/resize-lock-input.https.html
@@ -14,6 +14,7 @@ promise_test(async t => { const resize_lock_inner_page_is_ready_key = token(); const resize_lock_resize_is_done_key = token(); + const resize_lock_frame_requested_after_resize_key = token(); const resize_lock_report_click_location_key = token(); const resize_lock_report_click_location_key_after_resize = token(); const resize_lock_report_click_location_key_after_resize_2 = token(); @@ -22,6 +23,7 @@ "resources/resize-lock-inner-input.html", [resize_lock_inner_page_is_ready_key, resize_lock_resize_is_done_key, + resize_lock_frame_requested_after_resize_key, resize_lock_report_click_location_key, resize_lock_report_click_location_key_after_resize, resize_lock_report_click_location_key_after_resize_2])); @@ -39,7 +41,7 @@ let result = await nextValueFromServer(resize_lock_report_click_location_key); - assert_equals(result, "0,0", "fenced frame event before resize"); + assert_equals(result, "0,0", "fenced frame event before resize 1"); // The frame should be frozen at 300x150. Resize to create a 2x scale // and a horizontal offset of 50px. @@ -47,6 +49,7 @@ frame.height = "300"; writeValueToServer(resize_lock_resize_is_done_key, "outer_page_attempted_resize"); + await nextValueFromServer(resize_lock_frame_requested_after_resize_key); // The hit-test data is replicated in the browser and updated // asynchronously. Wait to ensure the update has finished. @@ -78,7 +81,7 @@ .pointerUp({sourceName: "finger1"}) .send(); result = await nextValueFromServer(resize_lock_report_click_location_key_after_resize); - assert_equals(result, "0,0", "fenced frame event before resize"); + assert_equals(result, "0,0", "fenced frame event before resize 2"); // Send an event where the bottom left of the scaled frame should // render. @@ -90,7 +93,7 @@ .pointerUp({sourceName: "finger1"}) .send(); result = await nextValueFromServer(resize_lock_report_click_location_key_after_resize_2); - assert_equals(result, "300,150", "fenced frame event before resize"); + assert_equals(result, "300,150", "fenced frame event before resize 3"); }, 1000); }, "Test Resize Lock"); </script>
diff --git a/third_party/blink/web_tests/external/wpt/fenced-frame/resources/automatic-beacon-helper.js b/third_party/blink/web_tests/external/wpt/fenced-frame/resources/automatic-beacon-helper.js new file mode 100644 index 0000000..d0a4133 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/fenced-frame/resources/automatic-beacon-helper.js
@@ -0,0 +1,104 @@ +// This is a helper file used for the automatic-beacon-*.https.html tests. +// To use this, make sure you import these scripts: +// <script src="/resources/testharness.js"></script> +// <script src="/resources/testharnessreport.js"></script> +// <script src="/common/utils.js"></script> +// <script src="/common/dispatcher/dispatcher.js"></script> +// <script src="resources/utils.js"></script> +// <script src="/resources/testdriver.js"></script> +// <script src="/resources/testdriver-actions.js"></script> +// <script src="/resources/testdriver-vendor.js"></script> +// <script src="/common/get-host-info.sub.js"></script> + +const NavigationTrigger = { + Click: 0, + ClickOnce: 1, + CrossOriginClick: 2, + CrossOriginClickNoOptIn: 3 +}; + +// Registers an automatic beacon in a given remote context frame, and registers +// the navigation handler for the frame that will trigger the beacon. +// remote_context: The context for the fenced frame or URN iframe. +// beacon_events: An array of FenceEvents to register with the frame. +// navigation_url: The URL the frame will navigate to. +// navigation_trigger: How the navigation will be performed. Either through a +// click, a click with a `once` event, a click in a +// cross-origin subframe, or a click in a cross-origin +// subframe with no opt-in header. +// target: the target of the navigation. Either '_blank' or +// '_unfencedTop'. +async function setupAutomaticBeacon( + remote_context, beacon_events, navigation_url = 'resources/dummy.html', + navigation_trigger = NavigationTrigger.Click, target = '_blank') { + const full_url = new URL(navigation_url, location.href); + await remote_context.execute( + async ( + NavigationTrigger, beacon_events, navigation_trigger, full_url, + target) => { + switch (navigation_trigger) { + case NavigationTrigger.Click: + addEventListener('click', (event) => { + beacon_events.forEach((beacon_event) => { + window.fence.setReportEventDataForAutomaticBeacons( + beacon_event); + }); + window.open(full_url, target); + }); + break; + case NavigationTrigger.ClickOnce: + beacon_events.forEach((beacon_event) => { + window.fence.setReportEventDataForAutomaticBeacons(beacon_event); + }); + addEventListener('click', (event) => { + window.open(full_url, target); + }); + break; + case NavigationTrigger.CrossOriginClick: + case NavigationTrigger.CrossOriginClickNoOptIn: + beacon_events.forEach((beacon_event) => { + window.fence.setReportEventDataForAutomaticBeacons(beacon_event); + }); + // Add a cross-origin iframe that will perform the top-level + // navigation. Do not set the 'Allow-Fenced-Frame-Automatic-Beacons' + // header to true. + const iframe = await attachIFrameContext({ + origin: get_host_info().HTTPS_REMOTE_ORIGIN, + headers: [[ + 'Allow-Fenced-Frame-Automatic-Beacons', + navigation_trigger == NavigationTrigger.CrossOriginClick ? + 'true' : + 'false' + ]] + }); + await iframe.execute(async (full_url, target) => { + addEventListener('click', (event) => { + window.open(full_url, target); + }); + }, [full_url, target]); + break; + } + }, + [NavigationTrigger, beacon_events, navigation_trigger, full_url, target]); +} + +// Checks if an automatic beacon of type `event_type` with contents `event_data` +// was sent out or not. +// event_type: The automatic beacon type to check. +// event_data: The automatic beacon data to check. +// expected_success: Whether we expect the automatic beacon to be sent. +// t: The WPT's test object. Only required if +// expected_success = false. +async function verifyBeaconData( + event_type, event_data, expected_success = true, t) { + if (expected_success) { + const beacon_initiator_origin = + await nextAutomaticBeacon(event_type, event_data); + assert_equals(beacon_initiator_origin, get_host_info().HTTPS_ORIGIN); + } else { + const timeout = new Promise(r => t.step_timeout(r, 1000)); + const result = await Promise.race( + [nextAutomaticBeacon(event_type, event_data), timeout]); + assert_true(typeof result === 'undefined'); + } +}
diff --git a/third_party/blink/web_tests/external/wpt/fenced-frame/resources/resize-lock-inner-input.html b/third_party/blink/web_tests/external/wpt/fenced-frame/resources/resize-lock-inner-input.html index cb17789..5513f89 100644 --- a/third_party/blink/web_tests/external/wpt/fenced-frame/resources/resize-lock-inner-input.html +++ b/third_party/blink/web_tests/external/wpt/fenced-frame/resources/resize-lock-inner-input.html
@@ -15,6 +15,7 @@ async function init() { const [resize_lock_inner_page_is_ready_key, resize_lock_resize_is_done_key, + resize_lock_frame_requested_after_resize_key, resize_lock_report_click_location_key, resize_lock_report_click_location_key_after_resize, resize_lock_report_click_location_key_after_resize_2] = parseKeylist(); @@ -25,6 +26,8 @@ if (eventCount == 1) { writeValueToServer(resize_lock_report_click_location_key, point); await nextValueFromServer(resize_lock_resize_is_done_key) + await new Promise(resolve => requestAnimationFrame(resolve)); + writeValueToServer(resize_lock_frame_requested_after_resize_key, "ready"); } else if (eventCount == 2) { writeValueToServer( resize_lock_report_click_location_key_after_resize, point);
diff --git a/third_party/blink/web_tests/external/wpt/html/dom/elements/global-attributes/dir-assorted.window-expected.txt b/third_party/blink/web_tests/external/wpt/html/dom/elements/global-attributes/dir-assorted.window-expected.txt new file mode 100644 index 0000000..3ca95eb --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/dom/elements/global-attributes/dir-assorted.window-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[FAIL] directionality of bdi elements: no dir attribute empty in rtl parent + assert_true: expected true got false +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/html/dom/elements/global-attributes/dir-assorted.window.js b/third_party/blink/web_tests/external/wpt/html/dom/elements/global-attributes/dir-assorted.window.js index 038b3f7..0d4e4b8 100644 --- a/third_party/blink/web_tests/external/wpt/html/dom/elements/global-attributes/dir-assorted.window.js +++ b/third_party/blink/web_tests/external/wpt/html/dom/elements/global-attributes/dir-assorted.window.js
@@ -80,3 +80,36 @@ assert_false(e1.matches(":dir(ltr)"), "parent is RTL after changing text in child"); assert_false(e2.matches(":dir(ltr)"), "child is RTL after changing text in child"); }, "text changes apply to dir=auto on further ancestor after removing dir=auto from closer ancestor"); + +for (const bdi_test of [ + { markup: "<bdi dir=ltr>A</bdi>", expected: "ltr", desc: "dir=ltr with LTR contents" }, + { markup: "<bdi dir=ltr>\u05d0</bdi>", expected: "ltr", desc: "dir=ltr with RTL contents" }, + { markup: "<bdi dir=ltr></bdi>", expected: "ltr", desc: "dir=ltr empty" }, + { markup: "<bdi dir=rtl>A</bdi>", expected: "rtl", desc: "dir=rtl with LTR contents" }, + { markup: "<bdi dir=rtl>\u05d0</bdi>", expected: "rtl", desc: "dir=rtl with RTL contents" }, + { markup: "<bdi dir=rtl></bdi>", expected: "rtl", desc: "dir=rtl empty" }, + { markup: "<bdi dir=auto>A</bdi>", expected: "ltr", desc: "dir=auto with LTR contents" }, + { markup: "<bdi dir=auto>\u05d0</bdi>", expected: "rtl", desc: "dir=auto with RTL contents" }, + { markup: "<bdi dir=auto></bdi>", expected: "parent", desc: "dir=auto empty" }, + { markup: "<bdi>A</bdi>", expected: "ltr", desc: "no dir attribute with LTR contents" }, + { markup: "<bdi>\u05d0</bdi>", expected: "rtl", desc: "no dir attribute with RTL contents" }, + { markup: "<bdi></bdi>", expected: "parent", desc: "no dir attribute empty" }, +]) { + for (const parent_dir of [ "ltr", "rtl" ]) { + test(() => { + const parent_element = document.createElement("div"); + parent_element.dir = parent_dir; + document.body.appendChild(parent_element); + parent_element.innerHTML = bdi_test.markup; + const bdi_element = parent_element.querySelector("bdi"); + let expected = bdi_test.expected; + if (expected == "parent") { + expected = parent_dir; + } + const not_expected = (expected == "ltr") ? "rtl" : "ltr"; + assert_true(bdi_element.matches(`:dir(${expected})`)); + assert_false(bdi_element.matches(`:dir(${not_expected})`)); + parent_element.remove(); + }, `directionality of bdi elements: ${bdi_test.desc} in ${parent_dir} parent`); + } +}
diff --git a/third_party/blink/web_tests/external/wpt/resize-observer/multiple-observers-with-mutation-crash.html b/third_party/blink/web_tests/external/wpt/resize-observer/multiple-observers-with-mutation-crash.html new file mode 100644 index 0000000..c844854e5 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/resize-observer/multiple-observers-with-mutation-crash.html
@@ -0,0 +1,49 @@ +<!doctype html> +<html class="test-wait"> +<!-- + This test is for crbug.com/1368458 which is a crash where we expected + up-to-date style&layout when delivering resize observations. We would crash + if a resize observer in one frame caused a modification in the presence of a + resize observer in another frame. +--> +<iframe id="iframe" style="border: none;" srcdoc=" + <!doctype html> + <style>body { margin: 0; }</style> + <div id='inner_element'>hello</div> + <script> + const resizeObserver = new ResizeObserver((entries) => { + const size = entries[0].borderBoxSize[0].inlineSize; + const event = new CustomEvent('onIframeResizeObserved', {detail: size}); + parent.document.dispatchEvent(event); + }); + resizeObserver.observe(inner_element); + </script> +"></iframe> +<div id="outer_element" style="width: 200px;">world</div> + +<script> + const onInnerElementInitialResize = (event) => { + // `inner_element` should result in an initial observation of width 300px. + window.document.removeEventListener( + 'onIframeResizeObserved', onInnerElementInitialResize, false); + + const resizeObserver = new ResizeObserver((entries) => { + // `outer_element` should result in an initial observation of width 200px. + + // Modify styles so that inner_element is resized. + iframe.contentDocument.body.style.width = "200px"; + }); + resizeObserver.observe(outer_element); + + const onInnerElementSecondResize = (event) => { + // `inner_element` should result in a second observation of width 100px. + + // Finish the test. + document.documentElement.classList.remove('test-wait'); + }; + window.document.addEventListener( + 'onIframeResizeObserved', onInnerElementSecondResize, false); + }; + window.document.addEventListener( + 'onIframeResizeObserved', onInnerElementInitialResize, false); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/storage-access-api/resources/storage-access-beyond-cookies-iframe.sub.html b/third_party/blink/web_tests/external/wpt/storage-access-api/resources/storage-access-beyond-cookies-iframe.sub.html index 364e5d7..3f486cc 100644 --- a/third_party/blink/web_tests/external/wpt/storage-access-api/resources/storage-access-beyond-cookies-iframe.sub.html +++ b/third_party/blink/web_tests/external/wpt/storage-access-api/resources/storage-access-beyond-cookies-iframe.sub.html
@@ -18,12 +18,24 @@ if (!!handle.sessionStorage.getItem("test")) { message = "Cross-site first-party Session Storage should be empty"; } + handle.sessionStorage.setItem("test2", id); + if (window.sessionStorage.getItem("test2") == id) { + message = "Handle bound partitioned instead of unpartitioned Session Storage"; + } + handle.sessionStorage.clear(); + window.sessionStorage.clear(); break; } case "localStorage": { if (!!handle.localStorage.getItem("test")) { message = "Cross-site first-party Local Storage should be empty"; } + handle.localStorage.setItem("test2", id); + if (window.localStorage.getItem("test2") == id) { + message = "Handle bound partitioned instead of unpartitioned Local Storage"; + } + handle.localStorage.clear(); + window.localStorage.clear(); break; } case "indexedDB": {
diff --git a/third_party/blink/web_tests/flag-specific/enable-skia-graphite/external/wpt/mediacapture-record/MediaRecorder-canvas-media-source.https-expected.txt b/third_party/blink/web_tests/flag-specific/enable-skia-graphite/external/wpt/mediacapture-record/MediaRecorder-canvas-media-source.https-expected.txt new file mode 100644 index 0000000..ed20109 --- /dev/null +++ b/third_party/blink/web_tests/flag-specific/enable-skia-graphite/external/wpt/mediacapture-record/MediaRecorder-canvas-media-source.https-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[FAIL] MediaRecorder returns frames containing video content + assert_greater_than: expected a number greater than 1500 but got 1 +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/issues/third-party-cookie-phaseout-exclusion.js b/third_party/blink/web_tests/http/tests/inspector-protocol/issues/third-party-cookie-phaseout-exclusion.js index 283e441..d33ec0b 100644 --- a/third_party/blink/web_tests/http/tests/inspector-protocol/issues/third-party-cookie-phaseout-exclusion.js +++ b/third_party/blink/web_tests/http/tests/inspector-protocol/issues/third-party-cookie-phaseout-exclusion.js
@@ -5,13 +5,15 @@ await dp.Network.enable(); await dp.Audits.enable(); - // Set the cookie. + // Set the cookie. Make sure the cookie won't be excluded by other reasons + // other than EXCLUDE_THIRD_PARTY_PHASEOUT. const response = await dp.Network.setCookie({ url: 'https://example.test:8443', secure: true, name: 'foo', value: 'bar', sameSite: 'None', + sourcePort: 8443, }); if (response.error)
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/issues/third-party-cookie-phaseout-warning.js b/third_party/blink/web_tests/http/tests/inspector-protocol/issues/third-party-cookie-phaseout-warning.js index 5a13e6a0..dad3e685 100644 --- a/third_party/blink/web_tests/http/tests/inspector-protocol/issues/third-party-cookie-phaseout-warning.js +++ b/third_party/blink/web_tests/http/tests/inspector-protocol/issues/third-party-cookie-phaseout-warning.js
@@ -5,13 +5,15 @@ await dp.Network.enable(); await dp.Audits.enable(); - // Set the cookie. + // Set the cookie. Make sure the cookie won't be excluded by other reasons + // to be able to have the WARN_THIRD_PARTY_PHASEOUT reason. const response = await dp.Network.setCookie({ url: 'https://example.test:8443', secure: true, name: 'foo', value: 'bar', sameSite: 'None', + sourcePort: 8443, }); if (response.error)
diff --git a/third_party/blink/web_tests/platform/linux/virtual/dir-pseudo-disabled/external/wpt/html/dom/elements/global-attributes/dir-assorted.window-expected.txt b/third_party/blink/web_tests/platform/linux/virtual/dir-pseudo-disabled/external/wpt/html/dom/elements/global-attributes/dir-assorted.window-expected.txt new file mode 100644 index 0000000..f4ddc7a0 --- /dev/null +++ b/third_party/blink/web_tests/platform/linux/virtual/dir-pseudo-disabled/external/wpt/html/dom/elements/global-attributes/dir-assorted.window-expected.txt
@@ -0,0 +1,67 @@ +This is a testharness.js-based test. +[FAIL] Root element has a direction + Failed to execute 'matches' on 'Element': ':dir(ltr)' is not a valid selector. +[FAIL] Element outside the document tree has a direction + Failed to execute 'matches' on 'Element': ':dir(ltr)' is not a valid selector. +[FAIL] Non-HTML element outside the document tree has a direction + Failed to execute 'matches' on 'Element': ':dir(ltr)' is not a valid selector. +[FAIL] Element without direction has parent element direction + Failed to execute 'matches' on 'Element': ':dir(rtl)' is not a valid selector. +[FAIL] Non-HTML element without direction has parent element direction + Failed to execute 'matches' on 'Element': ':dir(rtl)' is not a valid selector. +[FAIL] dir inheritance is correct after insertion and removal from document + Failed to execute 'matches' on 'Element': ':dir(ltr)' is not a valid selector. +[FAIL] Non-HTML element text contents influence dir=auto + Failed to execute 'matches' on 'Element': ':dir(rtl)' is not a valid selector. +[FAIL] text changes apply to dir=auto on further ancestor after removing dir=auto from closer ancestor + Failed to execute 'matches' on 'Element': ':dir(ltr)' is not a valid selector. +[FAIL] directionality of bdi elements: dir=ltr with LTR contents in ltr parent + Failed to execute 'matches' on 'Element': ':dir(ltr)' is not a valid selector. +[FAIL] directionality of bdi elements: dir=ltr with LTR contents in rtl parent + Failed to execute 'matches' on 'Element': ':dir(ltr)' is not a valid selector. +[FAIL] directionality of bdi elements: dir=ltr with RTL contents in ltr parent + Failed to execute 'matches' on 'Element': ':dir(ltr)' is not a valid selector. +[FAIL] directionality of bdi elements: dir=ltr with RTL contents in rtl parent + Failed to execute 'matches' on 'Element': ':dir(ltr)' is not a valid selector. +[FAIL] directionality of bdi elements: dir=ltr empty in ltr parent + Failed to execute 'matches' on 'Element': ':dir(ltr)' is not a valid selector. +[FAIL] directionality of bdi elements: dir=ltr empty in rtl parent + Failed to execute 'matches' on 'Element': ':dir(ltr)' is not a valid selector. +[FAIL] directionality of bdi elements: dir=rtl with LTR contents in ltr parent + Failed to execute 'matches' on 'Element': ':dir(rtl)' is not a valid selector. +[FAIL] directionality of bdi elements: dir=rtl with LTR contents in rtl parent + Failed to execute 'matches' on 'Element': ':dir(rtl)' is not a valid selector. +[FAIL] directionality of bdi elements: dir=rtl with RTL contents in ltr parent + Failed to execute 'matches' on 'Element': ':dir(rtl)' is not a valid selector. +[FAIL] directionality of bdi elements: dir=rtl with RTL contents in rtl parent + Failed to execute 'matches' on 'Element': ':dir(rtl)' is not a valid selector. +[FAIL] directionality of bdi elements: dir=rtl empty in ltr parent + Failed to execute 'matches' on 'Element': ':dir(rtl)' is not a valid selector. +[FAIL] directionality of bdi elements: dir=rtl empty in rtl parent + Failed to execute 'matches' on 'Element': ':dir(rtl)' is not a valid selector. +[FAIL] directionality of bdi elements: dir=auto with LTR contents in ltr parent + Failed to execute 'matches' on 'Element': ':dir(ltr)' is not a valid selector. +[FAIL] directionality of bdi elements: dir=auto with LTR contents in rtl parent + Failed to execute 'matches' on 'Element': ':dir(ltr)' is not a valid selector. +[FAIL] directionality of bdi elements: dir=auto with RTL contents in ltr parent + Failed to execute 'matches' on 'Element': ':dir(rtl)' is not a valid selector. +[FAIL] directionality of bdi elements: dir=auto with RTL contents in rtl parent + Failed to execute 'matches' on 'Element': ':dir(rtl)' is not a valid selector. +[FAIL] directionality of bdi elements: dir=auto empty in ltr parent + Failed to execute 'matches' on 'Element': ':dir(ltr)' is not a valid selector. +[FAIL] directionality of bdi elements: dir=auto empty in rtl parent + Failed to execute 'matches' on 'Element': ':dir(rtl)' is not a valid selector. +[FAIL] directionality of bdi elements: no dir attribute with LTR contents in ltr parent + Failed to execute 'matches' on 'Element': ':dir(ltr)' is not a valid selector. +[FAIL] directionality of bdi elements: no dir attribute with LTR contents in rtl parent + Failed to execute 'matches' on 'Element': ':dir(ltr)' is not a valid selector. +[FAIL] directionality of bdi elements: no dir attribute with RTL contents in ltr parent + Failed to execute 'matches' on 'Element': ':dir(rtl)' is not a valid selector. +[FAIL] directionality of bdi elements: no dir attribute with RTL contents in rtl parent + Failed to execute 'matches' on 'Element': ':dir(rtl)' is not a valid selector. +[FAIL] directionality of bdi elements: no dir attribute empty in ltr parent + Failed to execute 'matches' on 'Element': ':dir(ltr)' is not a valid selector. +[FAIL] directionality of bdi elements: no dir attribute empty in rtl parent + Failed to execute 'matches' on 'Element': ':dir(rtl)' is not a valid selector. +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/platform/mac/virtual/gpu/external/wpt/mediacapture-record/MediaRecorder-canvas-media-source.https-expected.txt b/third_party/blink/web_tests/platform/mac/virtual/gpu/external/wpt/mediacapture-record/MediaRecorder-canvas-media-source.https-expected.txt new file mode 100644 index 0000000..5b37deb --- /dev/null +++ b/third_party/blink/web_tests/platform/mac/virtual/gpu/external/wpt/mediacapture-record/MediaRecorder-canvas-media-source.https-expected.txt
@@ -0,0 +1,4 @@ +This is a testharness.js-based test. +All subtests passed and are omitted for brevity. +See https://chromium.googlesource.com/chromium/src/+/HEAD/docs/testing/writing_web_tests.md#Text-Test-Baselines for details. +Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/mac/virtual/oopr-canvas2d/external/wpt/mediacapture-record/MediaRecorder-canvas-media-source.https-expected.txt b/third_party/blink/web_tests/platform/mac/virtual/oopr-canvas2d/external/wpt/mediacapture-record/MediaRecorder-canvas-media-source.https-expected.txt new file mode 100644 index 0000000..5b37deb --- /dev/null +++ b/third_party/blink/web_tests/platform/mac/virtual/oopr-canvas2d/external/wpt/mediacapture-record/MediaRecorder-canvas-media-source.https-expected.txt
@@ -0,0 +1,4 @@ +This is a testharness.js-based test. +All subtests passed and are omitted for brevity. +See https://chromium.googlesource.com/chromium/src/+/HEAD/docs/testing/writing_web_tests.md#Text-Test-Baselines for details. +Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/virtual/boost-font-loading-task-priority/README.md b/third_party/blink/web_tests/virtual/boost-font-loading-task-priority/README.md new file mode 100644 index 0000000..7bbf9390 --- /dev/null +++ b/third_party/blink/web_tests/virtual/boost-font-loading-task-priority/README.md
@@ -0,0 +1,4 @@ +This virtual suite runs tests with the BoostFontLoadingTaskPriority +feature enabled. + +Bug: crbug.com/1470003 \ No newline at end of file
diff --git a/third_party/blink/web_tests/virtual/boost-image-set-loading-task-priority/README.md b/third_party/blink/web_tests/virtual/boost-image-set-loading-task-priority/README.md new file mode 100644 index 0000000..f0eca47 --- /dev/null +++ b/third_party/blink/web_tests/virtual/boost-image-set-loading-task-priority/README.md
@@ -0,0 +1,4 @@ +This virtual suite runs tests with the BoostImageSetLoadingTaskPriority +feature enabled. + +Bug: crbug.com/1470003 \ No newline at end of file
diff --git a/third_party/blink/web_tests/virtual/boost-loading-task-priority/README.md b/third_party/blink/web_tests/virtual/boost-loading-task-priority/README.md new file mode 100644 index 0000000..167d402e --- /dev/null +++ b/third_party/blink/web_tests/virtual/boost-loading-task-priority/README.md
@@ -0,0 +1,8 @@ +This virtual suite runs tests with the following features enabled: + BoostImageSetLoadingTaskPriority + BoostFontLoadingTaskPriority + BoostVideoLoadingTaskPriority + BoostNonRenderBlockingStyleLoadingTaskPriority + BoostRenderBlockingStyleLoadingTaskPriority + +Bug: crbug.com/1470003 \ No newline at end of file
diff --git a/third_party/blink/web_tests/virtual/boost-non-render-blocking-style-priority/README.md b/third_party/blink/web_tests/virtual/boost-non-render-blocking-style-priority/README.md new file mode 100644 index 0000000..d52bb7f --- /dev/null +++ b/third_party/blink/web_tests/virtual/boost-non-render-blocking-style-priority/README.md
@@ -0,0 +1,4 @@ +This virtual suite runs tests with the +BoostNonRenderBlockingStyleLoadingTaskPriority feature enabled. + +Bug: crbug.com/1470003 \ No newline at end of file
diff --git a/third_party/blink/web_tests/virtual/boost-render-blocking-style-priority/README.md b/third_party/blink/web_tests/virtual/boost-render-blocking-style-priority/README.md new file mode 100644 index 0000000..f3bb1a6 --- /dev/null +++ b/third_party/blink/web_tests/virtual/boost-render-blocking-style-priority/README.md
@@ -0,0 +1,4 @@ +This virtual suite runs tests with the +BoostRenderBlockingStyleLoadingTaskPriority feature enabled. + +Bug: crbug.com/1470003 \ No newline at end of file
diff --git a/third_party/blink/web_tests/virtual/boost-video-loading-task-priority/README.md b/third_party/blink/web_tests/virtual/boost-video-loading-task-priority/README.md new file mode 100644 index 0000000..dafae0f --- /dev/null +++ b/third_party/blink/web_tests/virtual/boost-video-loading-task-priority/README.md
@@ -0,0 +1,4 @@ +This virtual suite runs tests with the BoostVideoLoadingTaskPriority +feature enabled. + +Bug: crbug.com/1470003 \ No newline at end of file
diff --git a/third_party/blink/web_tests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/blink/web_tests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt index 4d0ffa0fa..b77f320 100644 --- a/third_party/blink/web_tests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt +++ b/third_party/blink/web_tests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -2043,6 +2043,7 @@ attribute ZERO getter canvas getter drawingBufferColorSpace + getter drawingBufferFormat getter drawingBufferHeight getter drawingBufferWidth getter unpackColorSpace @@ -2123,6 +2124,7 @@ method drawElements method drawElementsInstanced method drawRangeElements + method drawingBufferStorage method enable method enableVertexAttribArray method endQuery @@ -2483,8 +2485,10 @@ attribute RGB attribute RGB565 attribute RGB5_A1 + attribute RGB8 attribute RGBA attribute RGBA4 + attribute RGBA8 attribute SAMPLER_2D attribute SAMPLER_CUBE attribute SAMPLES @@ -2599,6 +2603,7 @@ attribute ZERO getter canvas getter drawingBufferColorSpace + getter drawingBufferFormat getter drawingBufferHeight getter drawingBufferWidth getter unpackColorSpace @@ -2649,6 +2654,7 @@ method disableVertexAttribArray method drawArrays method drawElements + method drawingBufferStorage method enable method enableVertexAttribArray method finish
diff --git a/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt b/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt index c8257465..875048e 100644 --- a/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt +++ b/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt
@@ -2622,6 +2622,7 @@ [Worker] attribute ZERO [Worker] getter canvas [Worker] getter drawingBufferColorSpace +[Worker] getter drawingBufferFormat [Worker] getter drawingBufferHeight [Worker] getter drawingBufferWidth [Worker] getter unpackColorSpace @@ -2702,6 +2703,7 @@ [Worker] method drawElements [Worker] method drawElementsInstanced [Worker] method drawRangeElements +[Worker] method drawingBufferStorage [Worker] method enable [Worker] method enableVertexAttribArray [Worker] method endQuery @@ -3062,8 +3064,10 @@ [Worker] attribute RGB [Worker] attribute RGB565 [Worker] attribute RGB5_A1 +[Worker] attribute RGB8 [Worker] attribute RGBA [Worker] attribute RGBA4 +[Worker] attribute RGBA8 [Worker] attribute SAMPLER_2D [Worker] attribute SAMPLER_CUBE [Worker] attribute SAMPLES @@ -3178,6 +3182,7 @@ [Worker] attribute ZERO [Worker] getter canvas [Worker] getter drawingBufferColorSpace +[Worker] getter drawingBufferFormat [Worker] getter drawingBufferHeight [Worker] getter drawingBufferWidth [Worker] getter unpackColorSpace @@ -3228,6 +3233,7 @@ [Worker] method disableVertexAttribArray [Worker] method drawArrays [Worker] method drawElements +[Worker] method drawingBufferStorage [Worker] method enable [Worker] method enableVertexAttribArray [Worker] method finish
diff --git a/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt index 276cd84f..3a0889b 100644 --- a/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt +++ b/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -9673,6 +9673,7 @@ attribute ZERO getter canvas getter drawingBufferColorSpace + getter drawingBufferFormat getter drawingBufferHeight getter drawingBufferWidth getter unpackColorSpace @@ -9753,6 +9754,7 @@ method drawElements method drawElementsInstanced method drawRangeElements + method drawingBufferStorage method enable method enableVertexAttribArray method endQuery @@ -10113,8 +10115,10 @@ attribute RGB attribute RGB565 attribute RGB5_A1 + attribute RGB8 attribute RGBA attribute RGBA4 + attribute RGBA8 attribute SAMPLER_2D attribute SAMPLER_CUBE attribute SAMPLES @@ -10229,6 +10233,7 @@ attribute ZERO getter canvas getter drawingBufferColorSpace + getter drawingBufferFormat getter drawingBufferHeight getter drawingBufferWidth getter unpackColorSpace @@ -10279,6 +10284,7 @@ method disableVertexAttribArray method drawArrays method drawElements + method drawingBufferStorage method enable method enableVertexAttribArray method finish
diff --git a/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt b/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt index 107d6ab..c8caa1f 100644 --- a/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt +++ b/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt
@@ -1937,6 +1937,7 @@ [Worker] attribute ZERO [Worker] getter canvas [Worker] getter drawingBufferColorSpace +[Worker] getter drawingBufferFormat [Worker] getter drawingBufferHeight [Worker] getter drawingBufferWidth [Worker] getter unpackColorSpace @@ -2017,6 +2018,7 @@ [Worker] method drawElements [Worker] method drawElementsInstanced [Worker] method drawRangeElements +[Worker] method drawingBufferStorage [Worker] method enable [Worker] method enableVertexAttribArray [Worker] method endQuery @@ -2377,8 +2379,10 @@ [Worker] attribute RGB [Worker] attribute RGB565 [Worker] attribute RGB5_A1 +[Worker] attribute RGB8 [Worker] attribute RGBA [Worker] attribute RGBA4 +[Worker] attribute RGBA8 [Worker] attribute SAMPLER_2D [Worker] attribute SAMPLER_CUBE [Worker] attribute SAMPLES @@ -2493,6 +2497,7 @@ [Worker] attribute ZERO [Worker] getter canvas [Worker] getter drawingBufferColorSpace +[Worker] getter drawingBufferFormat [Worker] getter drawingBufferHeight [Worker] getter drawingBufferWidth [Worker] getter unpackColorSpace @@ -2543,6 +2548,7 @@ [Worker] method disableVertexAttribArray [Worker] method drawArrays [Worker] method drawElements +[Worker] method drawingBufferStorage [Worker] method enable [Worker] method enableVertexAttribArray [Worker] method finish
diff --git a/third_party/chromite b/third_party/chromite index 462c04f..db1410a 160000 --- a/third_party/chromite +++ b/third_party/chromite
@@ -1 +1 @@ -Subproject commit 462c04f706e5185ca5e4e9bede03ec7daa2fc92f +Subproject commit db1410a8915c656c397f6d9111062c9f5a5947db
diff --git a/third_party/chromium-variations b/third_party/chromium-variations index 1e5fa7e..ff1e377 160000 --- a/third_party/chromium-variations +++ b/third_party/chromium-variations
@@ -1 +1 @@ -Subproject commit 1e5fa7e62fdeca99624cc64f84edc865a42cd90f +Subproject commit ff1e3775275922c5f8dd82af21637e99339997e1
diff --git a/third_party/depot_tools b/third_party/depot_tools index 6953ebe..cd076ba 160000 --- a/third_party/depot_tools +++ b/third_party/depot_tools
@@ -1 +1 @@ -Subproject commit 6953ebe3c1825e0f548e8c124a3b85f6c75dbc73 +Subproject commit cd076ba1b0be061d4446e47f68b3ec53122ce95c
diff --git a/third_party/devtools-frontend-internal b/third_party/devtools-frontend-internal index 7cdb4af..7bc9c8f 160000 --- a/third_party/devtools-frontend-internal +++ b/third_party/devtools-frontend-internal
@@ -1 +1 @@ -Subproject commit 7cdb4af2d310e71f3dfc36ccbf901f5944abd5c7 +Subproject commit 7bc9c8f33ac40a5b30c4a4f8486f25afde26058b
diff --git a/third_party/devtools-frontend/src b/third_party/devtools-frontend/src index 8e82459..d00d10d 160000 --- a/third_party/devtools-frontend/src +++ b/third_party/devtools-frontend/src
@@ -1 +1 @@ -Subproject commit 8e82459cfc5a48ed593407748bbef1e6c37ce943 +Subproject commit d00d10d6f5adcb3c705c4f81b889c59bcb904d28
diff --git a/third_party/nearby/README.chromium b/third_party/nearby/README.chromium index ef62627e..6d47afb 100644 --- a/third_party/nearby/README.chromium +++ b/third_party/nearby/README.chromium
@@ -1,7 +1,7 @@ Name: Nearby Connections Library Short Name: Nearby URL: https://github.com/google/nearby -Version: 16cb7f70b3a8b8b04440b7b96534e11df964ca60 +Version: cd4963b0f9c68775372d91dc422c01d703122345 License: Apache 2.0 License File: LICENSE Security Critical: yes
diff --git a/third_party/nearby/src b/third_party/nearby/src index 16cb7f7..cd4963b 160000 --- a/third_party/nearby/src +++ b/third_party/nearby/src
@@ -1 +1 @@ -Subproject commit 16cb7f70b3a8b8b04440b7b96534e11df964ca60 +Subproject commit cd4963b0f9c68775372d91dc422c01d703122345
diff --git a/third_party/skia b/third_party/skia index 83105a7..0e8023d 160000 --- a/third_party/skia +++ b/third_party/skia
@@ -1 +1 @@ -Subproject commit 83105a7fb6e2c2e3dda07a63f5139cbedc8c81cf +Subproject commit 0e8023dc0a1a5655703b39454c090b5a004415d6
diff --git a/tools/gritsettings/resource_ids.spec b/tools/gritsettings/resource_ids.spec index d5b9acc..f152619 100644 --- a/tools/gritsettings/resource_ids.spec +++ b/tools/gritsettings/resource_ids.spec
@@ -389,7 +389,7 @@ "includes": [3720], }, "<(SHARED_INTERMEDIATE_DIR)/chrome/browser/resources/side_panel/customize_chrome/resources.grd": { - "META": {"sizes": {"includes": [50],}}, + "META": {"sizes": {"includes": [55],}}, "includes": [3740], }, "<(SHARED_INTERMEDIATE_DIR)/chrome/browser/resources/side_panel/history_clusters/resources.grd": {
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 29ef758..d5121c6 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -20576,47 +20576,6 @@ <int value="5" label="Journeys"/> </enum> -<enum name="HistoryTopSitesRecoveryEnum"> - <summary>Error states noted in top_sites_database.cc recovery code.</summary> - <int value="0" label="RECOVERY_EVENT_RECOVERED">Successful recovery.</int> - <int value="1" label="RECOVERY_EVENT_DEPRECATED"> - Recovery found deprecated version and razed. - </int> - <int value="2" label="RECOVERY_EVENT_FAILED_SCOPER (obsolete Mar 2017)"> - sql::Recovery failed init. - </int> - <int value="3" label="RECOVERY_EVENT_FAILED_META_VERSION"> - Failed sql::Recovery::SetupMeta() or GetMetaVersionNumber(). - </int> - <int value="4" label="RECOVERY_EVENT_FAILED_META_WRONG_VERSION"> - Recovery meta table has an unexpected version. - </int> - <int value="5" label="RECOVERY_EVENT_FAILED_META_INIT (obsolete Mar 2017)"> - Failed sql::MetaTable::Init(). - </int> - <int value="6" label="RECOVERY_EVENT_FAILED_SCHEMA_INIT (obsolete Mar 2017)"> - Failed to init target schema. - </int> - <int value="7" - label="RECOVERY_EVENT_FAILED_AUTORECOVER_THUMBNAILS (obsolete Mar 2017)"> - Failed recovery on thumbnails table. - </int> - <int value="8" label="RECOVERY_EVENT_FAILED_COMMIT"> - Failure from sql::Recovery::Recovered(). - </int> - <int value="9" label="RECOVERY_EVENT_INVARIANT_RANK"> - Rows were deleted because |url_rank| and |last_forced| didn't agree. Does - not prevent recovery. - </int> - <int value="10" label="RECOVERY_EVENT_INVARIANT_REDIRECT"> - Rows were deleted because |redirects| did not contain |url|. Does not - prevent recovery. - </int> - <int value="11" label="RECOVERY_EVENT_INVARIANT_CONTIGUOUS"> - |url_rank| was renumbered due to missing rows. Does not prevent recovery. - </int> -</enum> - <enum name="HomepageLocationType"> <int value="0" label="POLICY_NTP"/> <int value="1" label="POLICY_OTHER"/> @@ -30641,6 +30600,7 @@ <int value="508272289" label="SharedHighlightingAmp:disabled"/> <int value="510066229" label="AutofillEnforceMinRequiredFieldsForQuery:enabled"/> + <int value="510759575" label="LeftHandSideActivityIndicators:disabled"/> <int value="510814146" label="OfflineBookmarks:enabled"/> <int value="510833540" label="UseOutOfProcessVideoDecoding:enabled"/> <int value="511179195" label="ShoppingAssist:disabled"/> @@ -33829,6 +33789,7 @@ <int value="2001520126" label="AccountManagementFlowsV2:enabled"/> <int value="2001562962" label="enable-manual-fallback-for-password-saving:enabled"/> + <int value="2002003766" label="LeftHandSideActivityIndicators:enabled"/> <int value="2002113900" label="AdaptiveButtonInTopToolbar:disabled"/> <int value="2002573873" label="ChromeHomeMenuItemsExpandSheet:enabled"/> <int value="2002724184" label="MouseAndTrackpadDropdownMenu:enabled"/> @@ -42654,6 +42615,19 @@ <int value="4" label="Policy Opt Out"/> </enum> +<enum name="RedactionToolCaller"> + <summary>The caller of the redaction tool.</summary> + <int value="1" label="System Logs Uploader"/> + <int value="2" label="System Logs Fetcher"/> + <int value="3" label="Support Tool"/> + <int value="4" label="Error Reporting"/> + <int value="5" label="Feedback Tool"/> + <int value="6" label="Browser System Logs"/> + <int value="7" label="Unit Tests"/> + <int value="8" label="Undetermined"/> + <int value="9" label="Unknown"/> +</enum> + <enum name="RelatedActiveContentsSyncAccessInfo"> <int value="0" label="kNoSyncAccess"/> <int value="1"
diff --git a/tools/metrics/histograms/metadata/android/enums.xml b/tools/metrics/histograms/metadata/android/enums.xml index ae3b4f59..f8e17f5 100644 --- a/tools/metrics/histograms/metadata/android/enums.xml +++ b/tools/metrics/histograms/metadata/android/enums.xml
@@ -1077,16 +1077,6 @@ <int value="4" label="Stylus"/> </enum> -<enum name="IntentUriNavigationResult"> - <int value="0" label="Intent with an unused fallback URL was launched"/> - <int value="1" label="Intent fallback URL was used"/> - <int value="2" label="Intent with an unused fallback URL was blocked"/> - <int value="3" label="Intent with a fallback URL prompted the user"/> - <int value="4" label="Intent without a fallback URL was launched"/> - <int value="5" label="Intent without a fallback URL was blocked"/> - <int value="6" label="Intent without a fallback URL prompted the user"/> -</enum> - <enum name="LightTheme"> <int value="0" label="undefined"/> <int value="1" label="no"/>
diff --git a/tools/metrics/histograms/metadata/android/histograms.xml b/tools/metrics/histograms/metadata/android/histograms.xml index e675658..1ed1ee3 100644 --- a/tools/metrics/histograms/metadata/android/histograms.xml +++ b/tools/metrics/histograms/metadata/android/histograms.xml
@@ -1756,16 +1756,6 @@ </summary> </histogram> -<histogram name="Android.Intent.IntentUriNavigationResult" - enum="IntentUriNavigationResult" expires_after="2023-12-17"> - <owner>mthiesse@chromium.org</owner> - <owner>yfriedman@chromium.org</owner> - <summary> - Recorded when a navigation to an Intent URI occurs. Records the results of - the navigation. - </summary> -</histogram> - <histogram name="Android.Intent.MainFrameIntentLaunch" enum="MainFrameIntentLaunch" expires_after="2024-06-30"> <owner>mthiesse@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/ash/histograms.xml b/tools/metrics/histograms/metadata/ash/histograms.xml index 01a3e29..66b293e 100644 --- a/tools/metrics/histograms/metadata/ash/histograms.xml +++ b/tools/metrics/histograms/metadata/ash/histograms.xml
@@ -1934,7 +1934,7 @@ </histogram> <histogram name="Ash.CaptureModeController.SwitchesFromInitialCaptureMode" - enum="Boolean" expires_after="2024-02-12"> + enum="Boolean" expires_after="2025-01-08"> <owner>afakhry@chromium.org</owner> <owner>gzadina@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/history/histograms.xml b/tools/metrics/histograms/metadata/history/histograms.xml index 027256de..7bc2fc8c 100644 --- a/tools/metrics/histograms/metadata/history/histograms.xml +++ b/tools/metrics/histograms/metadata/history/histograms.xml
@@ -1624,6 +1624,14 @@ profile remains open. If no domains are visited in a given day, a count of 0 will be reported for that day. + Warning about Android activity types (custom tabs, browser app, etc.): Do + not look at this data using an activity type filter; when looking at data + from Android, use "Android Chrome (All)". Why? This histogram + reflects all usage of the browser. Using a filter such as "Browser + App" is not appropriate because it doesn't make sense to ask "how + many web sites were visited in Chrome (in any mode) the last week but only + tell me if the answer if this current launch was in browser app mode." + Warning about delayed data: Chrome may upload logs on a given day without uploading this histogram. This can happen because Chrome uploads logs initially upon startup. This histogram is emitted shortly _after_ startup. @@ -1658,6 +1666,14 @@ profile remains open. If no domains are visited in a given day, a count of 0 will be reported for that day. + Warning about Android activity types (custom tabs, browser app, etc.): Do + not look at this data using an activity type filter; when looking at data + from Android, use "Android Chrome (All)". Why? This histogram + reflects all usage of the browser. Using a filter such as "Browser + App" is not appropriate because it doesn't make sense to ask "how + many web sites were visited in Chrome (in any mode) the last week but only + tell me if the answer if this current launch was in browser app mode." + Warning about delayed data: Chrome may upload logs on a given day without uploading this histogram. This can happen because Chrome uploads logs initially upon startup. This histogram is emitted shortly _after_ startup. @@ -1686,6 +1702,14 @@ open. If no domains are visited during a 28-day period, a count of 0 will be reported for that period. + Warning about Android activity types (custom tabs, browser app, etc.): Do + not look at this data using an activity type filter; when looking at data + from Android, use "Android Chrome (All)". Why? This histogram + reflects all usage of the browser. Using a filter such as "Browser + App" is not appropriate because it doesn't make sense to ask "how + many web sites were visited in Chrome (in any mode) the last week but only + tell me if the answer if this current launch was in browser app mode." + Warning about delayed data: Chrome may upload logs on a given day without uploading this histogram. This can happen because Chrome uploads logs initially upon startup. This histogram is emitted shortly _after_ startup. @@ -1720,6 +1744,14 @@ open. If no domains are visited during a 28-day period, a count of 0 will be reported for that period. + Warning about Android activity types (custom tabs, browser app, etc.): Do + not look at this data using an activity type filter; when looking at data + from Android, use "Android Chrome (All)". Why? This histogram + reflects all usage of the browser. Using a filter such as "Browser + App" is not appropriate because it doesn't make sense to ask "how + many web sites were visited in Chrome (in any mode) the last week but only + tell me if the answer if this current launch was in browser app mode." + Warning about delayed data: Chrome may upload logs on a given day without uploading this histogram. This can happen because Chrome uploads logs initially upon startup. This histogram is emitted shortly _after_ startup. @@ -1748,6 +1780,14 @@ open. If no domains are visited during a 7-day period, a count 0 will be reported for that period. + Warning about Android activity types (custom tabs, browser app, etc.): Do + not look at this data using an activity type filter; when looking at data + from Android, use "Android Chrome (All)". Why? This histogram + reflects all usage of the browser. Using a filter such as "Browser + App" is not appropriate because it doesn't make sense to ask "how + many web sites were visited in Chrome (in any mode) the last week but only + tell me if the answer if this current launch was in browser app mode." + Warning about delayed data: Chrome may upload logs on a given day without uploading this histogram. This can happen because Chrome uploads logs initially upon startup. This histogram is emitted shortly _after_ startup. @@ -1782,6 +1822,14 @@ open. If no domains are visited during a 7-day period, a count 0 will be reported for that period. + Warning about Android activity types (custom tabs, browser app, etc.): Do + not look at this data using an activity type filter; when looking at data + from Android, use "Android Chrome (All)". Why? This histogram + reflects all usage of the browser. Using a filter such as "Browser + App" is not appropriate because it doesn't make sense to ask "how + many web sites were visited in Chrome (in any mode) the last week but only + tell me if the answer if this current launch was in browser app mode." + Warning about delayed data: Chrome may upload logs on a given day without uploading this histogram. This can happen because Chrome uploads logs initially upon startup. This histogram is emitted shortly _after_ startup.
diff --git a/tools/metrics/histograms/metadata/readaloud/histograms.xml b/tools/metrics/histograms/metadata/readaloud/histograms.xml index 0ed00dd..16dc7e4 100644 --- a/tools/metrics/histograms/metadata/readaloud/histograms.xml +++ b/tools/metrics/histograms/metadata/readaloud/histograms.xml
@@ -124,6 +124,31 @@ </summary> </histogram> +<histogram name="ReadAloud.VoiceChanged.{VoiceID}" enum="Boolean" + expires_after="2024-06-02"> + <owner>andreaxg@google.com</owner> + <owner>basiaz@google.com</owner> + <owner>iwells@chromium.org</owner> + <summary> + Histogram for recording what voice a user changes to. Emitted when the + ReadAloud pref for voice is changed by the user. This only ever logs the + value "true" because we only care about the total count. + </summary> +</histogram> + +<histogram name="ReadAloud.VoicePreviewed.{VoiceID}" enum="Boolean" + expires_after="2024-06-02"> + <owner>andreaxg@google.com</owner> + <owner>basiaz@google.com</owner> + <owner>iwells@chromium.org</owner> + <summary> + Histogram for recording what voice a user previews. Emitted when a voice + preview playback is created successfully in ReadAloudController. This only + ever logs the value "true" because we only care about the total + count. + </summary> +</histogram> + </histograms> </histogram-configuration>
diff --git a/tools/metrics/histograms/metadata/sb_client/histograms.xml b/tools/metrics/histograms/metadata/sb_client/histograms.xml index 08622f6..fb1a3ac 100644 --- a/tools/metrics/histograms/metadata/sb_client/histograms.xml +++ b/tools/metrics/histograms/metadata/sb_client/histograms.xml
@@ -100,7 +100,7 @@ </histogram> <histogram name="SBClientDownload.DocumentCheckDownloadStats" - enum="SBClientDownloadCheckDownloadStats" expires_after="2024-02-20"> + enum="SBClientDownloadCheckDownloadStats" expires_after="2025-02-20"> <owner>drubery@chromium.org</owner> <owner>chrome-counter-abuse-alerts@google.com</owner> <summary> @@ -111,7 +111,7 @@ </histogram> <histogram name="SBClientDownload.DocumentContainsMacros" - enum="BooleanContainsMacros" expires_after="2024-02-20"> + enum="BooleanContainsMacros" expires_after="2025-02-20"> <owner>drubery@chromium.org</owner> <owner>chrome-counter-abuse-alerts@google.com</owner> <summary>
diff --git a/tools/win/DebugVisualizers/chrome.natvis b/tools/win/DebugVisualizers/chrome.natvis index 406d1691..16b33a8 100644 --- a/tools/win/DebugVisualizers/chrome.natvis +++ b/tools/win/DebugVisualizers/chrome.natvis
@@ -300,4 +300,7 @@ </ArrayItems> </Expand> </Type> + <Type Name="base::StrongAlias<*,*>"> + <DisplayString>{value_}</DisplayString> + </Type> </AutoVisualizer>
diff --git a/ui/base/x/x11_gl_egl_utility.cc b/ui/base/x/x11_gl_egl_utility.cc index 4ea7dfce..eb56cd68 100644 --- a/ui/base/x/x11_gl_egl_utility.cc +++ b/ui/base/x/x11_gl_egl_utility.cc
@@ -70,10 +70,4 @@ } } -bool IsTransparentBackgroundSupported() { - return x11::Connection::Get() - ->GetOrCreateVisualManager() - .ArgbVisualAvailable(); -} - } // namespace ui
diff --git a/ui/base/x/x11_gl_egl_utility.h b/ui/base/x/x11_gl_egl_utility.h index a57891eb..1a2d9fe 100644 --- a/ui/base/x/x11_gl_egl_utility.h +++ b/ui/base/x/x11_gl_egl_utility.h
@@ -19,9 +19,6 @@ void ChoosePlatformCustomAlphaAndBufferSize(EGLint* alpha_size, EGLint* buffer_size); -// Returns whether transparent background is suppored. -bool IsTransparentBackgroundSupported(); - } // namespace ui #endif // UI_BASE_X_X11_GL_EGL_UTILITY_H_
diff --git a/ui/base/x/x11_util.cc b/ui/base/x/x11_util.cc index 376822b..79073ed6b 100644 --- a/ui/base/x/x11_util.cc +++ b/ui/base/x/x11_util.cc
@@ -46,7 +46,6 @@ #include "ui/gfx/x/connection.h" #include "ui/gfx/x/screensaver.h" #include "ui/gfx/x/shm.h" -#include "ui/gfx/x/visual_manager.h" #include "ui/gfx/x/xproto.h" #if BUILDFLAG(IS_FREEBSD) @@ -655,19 +654,6 @@ return false; } -bool DoesVisualHaveAlphaForTest() { - uint8_t depth = 0; - bool visual_has_alpha = false; - x11::Connection::Get()->GetOrCreateVisualManager().ChooseVisualForWindow( - true, nullptr, &depth, nullptr, &visual_has_alpha); - - if (visual_has_alpha) { - DCHECK_EQ(32, depth); - } - - return visual_has_alpha; -} - gfx::ImageSkia GetNativeWindowIcon(intptr_t target_window_id) { std::vector<uint32_t> data; if (!x11::Connection::Get()->GetArrayProperty(
diff --git a/ui/base/x/x11_util.h b/ui/base/x/x11_util.h index ab53ab6..24665adf 100644 --- a/ui/base/x/x11_util.h +++ b/ui/base/x/x11_util.h
@@ -251,9 +251,6 @@ // Return true if VulkanSurface is supported. COMPONENT_EXPORT(UI_BASE_X) bool IsVulkanSurfaceSupported(); -// Returns whether ARGB visuals are supported. -COMPONENT_EXPORT(UI_BASE_X) bool DoesVisualHaveAlphaForTest(); - // Returns an icon for a native window referred by |target_window_id|. Can be // any window on screen. COMPONENT_EXPORT(UI_BASE_X)
diff --git a/ui/ozone/platform/wayland/gpu/wayland_gl_egl_utility.cc b/ui/ozone/platform/wayland/gpu/wayland_gl_egl_utility.cc index b3e92d8..3e84ec8 100644 --- a/ui/ozone/platform/wayland/gpu/wayland_gl_egl_utility.cc +++ b/ui/ozone/platform/wayland/gpu/wayland_gl_egl_utility.cc
@@ -68,18 +68,10 @@ void WaylandGLEGLUtility::ChooseEGLAlphaAndBufferSize(EGLint* alpha_size, EGLint* buffer_size) {} -bool WaylandGLEGLUtility::IsTransparentBackgroundSupported() const { - return true; -} - void WaylandGLEGLUtility::CollectGpuExtraInfo( bool enable_native_gpu_memory_buffers, gfx::GpuExtraInfo& gpu_extra_info) const {} -bool WaylandGLEGLUtility::X11DoesVisualHaveAlphaForTest() const { - return false; -} - bool WaylandGLEGLUtility::HasVisualManager() { return false; }
diff --git a/ui/ozone/platform/wayland/gpu/wayland_gl_egl_utility.h b/ui/ozone/platform/wayland/gpu/wayland_gl_egl_utility.h index b99a5750..7594986 100644 --- a/ui/ozone/platform/wayland/gpu/wayland_gl_egl_utility.h +++ b/ui/ozone/platform/wayland/gpu/wayland_gl_egl_utility.h
@@ -23,10 +23,8 @@ std::vector<EGLAttrib>* display_attributes) override; void ChooseEGLAlphaAndBufferSize(EGLint* alpha_size, EGLint* buffer_size) override; - bool IsTransparentBackgroundSupported() const override; void CollectGpuExtraInfo(bool enable_native_gpu_memory_buffers, gfx::GpuExtraInfo& gpu_extra_info) const override; - bool X11DoesVisualHaveAlphaForTest() const override; bool HasVisualManager() override; };
diff --git a/ui/ozone/platform/wayland/host/wayland_window.cc b/ui/ozone/platform/wayland/host/wayland_window.cc index a0eef2f..607b4c3b 100644 --- a/ui/ozone/platform/wayland/host/wayland_window.cc +++ b/ui/ozone/platform/wayland/host/wayland_window.cc
@@ -536,11 +536,6 @@ NOTIMPLEMENTED_LOG_ONCE(); } -bool WaylandWindow::IsTranslucentWindowOpacitySupported() const { - // Wayland compositors always support translucency. - return true; -} - void WaylandWindow::SetDecorationInsets(const gfx::Insets* insets_px) { // TODO(crbug.com/1395267): Add window geometry to WaylandWindow::State. if ((!frame_insets_px_ && !insets_px) ||
diff --git a/ui/ozone/platform/wayland/host/wayland_window.h b/ui/ozone/platform/wayland/host/wayland_window.h index d68d4d8..89027ed 100644 --- a/ui/ozone/platform/wayland/host/wayland_window.h +++ b/ui/ozone/platform/wayland/host/wayland_window.h
@@ -208,7 +208,6 @@ gfx::Rect GetRestoredBoundsInDIP() const override; bool ShouldWindowContentsBeTransparent() const override; void SetAspectRatio(const gfx::SizeF& aspect_ratio) override; - bool IsTranslucentWindowOpacitySupported() const override; void SetDecorationInsets(const gfx::Insets* insets_px) override; void SetWindowIcons(const gfx::ImageSkia& window_icon, const gfx::ImageSkia& app_icon) override;
diff --git a/ui/ozone/platform/x11/gl_egl_utility_x11.cc b/ui/ozone/platform/x11/gl_egl_utility_x11.cc index 7aded514..3d3d0ab0 100644 --- a/ui/ozone/platform/x11/gl_egl_utility_x11.cc +++ b/ui/ozone/platform/x11/gl_egl_utility_x11.cc
@@ -27,10 +27,6 @@ ChoosePlatformCustomAlphaAndBufferSize(alpha_size, buffer_size); } -bool GLEGLUtilityX11::IsTransparentBackgroundSupported() const { - return ui::IsTransparentBackgroundSupported(); -} - void GLEGLUtilityX11::CollectGpuExtraInfo( bool enable_native_gpu_memory_buffers, gfx::GpuExtraInfo& gpu_extra_info) const { @@ -46,10 +42,6 @@ } } -bool GLEGLUtilityX11::X11DoesVisualHaveAlphaForTest() const { - return ui::DoesVisualHaveAlphaForTest(); -} - bool GLEGLUtilityX11::HasVisualManager() { return true; }
diff --git a/ui/ozone/platform/x11/gl_egl_utility_x11.h b/ui/ozone/platform/x11/gl_egl_utility_x11.h index 2e822203..e6e7b1e 100644 --- a/ui/ozone/platform/x11/gl_egl_utility_x11.h +++ b/ui/ozone/platform/x11/gl_egl_utility_x11.h
@@ -23,10 +23,8 @@ std::vector<EGLAttrib>* display_attributes) override; void ChooseEGLAlphaAndBufferSize(EGLint* alpha_size, EGLint* buffer_size) override; - bool IsTransparentBackgroundSupported() const override; void CollectGpuExtraInfo(bool enable_native_gpu_memory_buffers, gfx::GpuExtraInfo& gpu_extra_info) const override; - bool X11DoesVisualHaveAlphaForTest() const override; bool HasVisualManager() override; absl::optional<base::ScopedEnvironmentVariableOverride> MaybeGetScopedDisplayUnsetForVulkan() override;
diff --git a/ui/ozone/platform/x11/x11_window.cc b/ui/ozone/platform/x11/x11_window.cc index f2221946..443c8177 100644 --- a/ui/ozone/platform/x11/x11_window.cc +++ b/ui/ozone/platform/x11/x11_window.cc
@@ -1064,17 +1064,6 @@ X11Window::UpdateMinAndMaxSize(); } -bool X11Window::IsTranslucentWindowOpacitySupported() const { - // If this function may be called before InitX11Window() (which - // initializes |visual_has_alpha_|), return whether it is possible - // to create windows with ARGB visuals. - if (xwindow_ == x11::Window::None) { - connection_->GetOrCreateVisualManager().ArgbVisualAvailable(); - } - - return visual_has_alpha_; -} - void X11Window::SetOpacity(float opacity) { // X server opacity is in terms of 32 bit unsigned int space, and counts from // the opposite direction.
diff --git a/ui/ozone/platform/x11/x11_window.h b/ui/ozone/platform/x11/x11_window.h index 1d9ba6e..fc999f7 100644 --- a/ui/ozone/platform/x11/x11_window.h +++ b/ui/ozone/platform/x11/x11_window.h
@@ -116,7 +116,6 @@ void SetWindowIcons(const gfx::ImageSkia& window_icon, const gfx::ImageSkia& app_icon) override; void SizeConstraintsChanged() override; - bool IsTranslucentWindowOpacitySupported() const override; void SetOpacity(float opacity) override; bool CanSetDecorationInsets() const override; void SetDecorationInsets(const gfx::Insets* insets_px) override;
diff --git a/ui/ozone/public/platform_gl_egl_utility.h b/ui/ozone/public/platform_gl_egl_utility.h index 47473203..66fa30b 100644 --- a/ui/ozone/public/platform_gl_egl_utility.h +++ b/ui/ozone/public/platform_gl_egl_utility.h
@@ -30,19 +30,11 @@ virtual void ChooseEGLAlphaAndBufferSize(EGLint* alpha_size, EGLint* buffer_size) = 0; - // Returns whether the platform supports setting transparent background for - // windows. - virtual bool IsTransparentBackgroundSupported() const = 0; - // Fills in the platform specific bits of the GPU extra info holder. // |enable_native_gpu_memory_buffers| should be taken from GpuPreferences. virtual void CollectGpuExtraInfo(bool enable_native_gpu_memory_buffers, gfx::GpuExtraInfo& gpu_extra_info) const = 0; - // X11 specific; returns whether the test configuration supports alpha for - // window visuals. - virtual bool X11DoesVisualHaveAlphaForTest() const = 0; - // X11 specific; returns whether the platform supports visuals. virtual bool HasVisualManager();
diff --git a/ui/platform_window/platform_window.cc b/ui/platform_window/platform_window.cc index 89bef01..f34351e 100644 --- a/ui/platform_window/platform_window.cc +++ b/ui/platform_window/platform_window.cc
@@ -43,10 +43,6 @@ return false; } -bool PlatformWindow::IsTranslucentWindowOpacitySupported() const { - return false; -} - void PlatformWindow::SetOpacity(float opacity) {} void PlatformWindow::SetVisibilityChangedAnimationsEnabled(bool enabled) {}
diff --git a/ui/platform_window/platform_window.h b/ui/platform_window/platform_window.h index 845da94..1cf6737 100644 --- a/ui/platform_window/platform_window.h +++ b/ui/platform_window/platform_window.h
@@ -156,9 +156,6 @@ // animations. virtual bool IsAnimatingClosed() const; - // Returns true if the window supports translucency. - virtual bool IsTranslucentWindowOpacitySupported() const; - // Sets opacity of the platform window. virtual void SetOpacity(float opacity);
diff --git a/ui/platform_window/win/win_window.cc b/ui/platform_window/win/win_window.cc index fad36c24..c264c751 100644 --- a/ui/platform_window/win/win_window.cc +++ b/ui/platform_window/win/win_window.cc
@@ -239,11 +239,6 @@ return false; } -bool WinWindow::IsTranslucentWindowOpacitySupported() const { - NOTIMPLEMENTED_LOG_ONCE(); - return false; -} - bool WinWindow::IsFullscreen() const { return GetPlatformWindowState() == PlatformWindowState::kFullScreen; }
diff --git a/ui/platform_window/win/win_window.h b/ui/platform_window/win/win_window.h index 5ecf188..ed60ad7d 100644 --- a/ui/platform_window/win/win_window.h +++ b/ui/platform_window/win/win_window.h
@@ -74,7 +74,6 @@ const gfx::ImageSkia& app_icon) override; void SizeConstraintsChanged() override; bool IsAnimatingClosed() const override; - bool IsTranslucentWindowOpacitySupported() const override; bool IsFullscreen() const;
diff --git a/ui/views/button_drag_utils.cc b/ui/views/button_drag_utils.cc index 306962e..1386d96 100644 --- a/ui/views/button_drag_utils.cc +++ b/ui/views/button_drag_utils.cc
@@ -90,7 +90,7 @@ color_provider->GetColor(ui::kColorTextfieldForeground)); SkColor bg_color = color_provider->GetColor(ui::kColorTextfieldBackground); - if (drag_widget->IsTranslucentWindowOpacitySupported()) { + if (views::Widget::IsWindowCompositingSupported()) { button->SetTextShadows(gfx::ShadowValues( 10, gfx::ShadowValue(gfx::Vector2d(0, 0), 2.0f, bg_color))); } else {
diff --git a/ui/views/controls/menu/menu_controller_cocoa_delegate_impl.mm b/ui/views/controls/menu/menu_controller_cocoa_delegate_impl.mm index 8199063..3be639f 100644 --- a/ui/views/controls/menu/menu_controller_cocoa_delegate_impl.mm +++ b/ui/views/controls/menu/menu_controller_cocoa_delegate_impl.mm
@@ -173,7 +173,7 @@ NSSize newTagSize = attachment.image.size; // The baseline offset of the badge image to the menu text baseline. - const int kBadgeBaselineOffset = -4; + const int kBadgeBaselineOffset = -3; attachment.bounds = NSMakeRect(0, kBadgeBaselineOffset, newTagSize.width, newTagSize.height);
diff --git a/ui/views/controls/textfield/textfield.cc b/ui/views/controls/textfield/textfield.cc index 57b6f649..81d64b0 100644 --- a/ui/views/controls/textfield/textfield.cc +++ b/ui/views/controls/textfield/textfield.cc
@@ -195,17 +195,6 @@ return (ch >= 0x20 && ch < 0x7F) || ch > 0x9F; } -bool CanUseTransparentBackgroundForDragImage() { -#if BUILDFLAG(IS_OZONE) - const auto* const egl_utility = - ui::OzonePlatform::GetInstance()->GetPlatformGLEGLUtility(); - return egl_utility ? egl_utility->IsTransparentBackgroundSupported() : false; -#else - // Other platforms allow this. - return true; -#endif -} - #if BUILDFLAG(IS_MAC) const float kAlmostTransparent = 1.0 / 255.0; const float kOpaque = 1.0; @@ -1245,7 +1234,7 @@ SkBitmap bitmap; float raster_scale = ScaleFactorForDragFromWidget(GetWidget()); - SkColor color = CanUseTransparentBackgroundForDragImage() + SkColor color = views::Widget::IsWindowCompositingSupported() ? SK_ColorTRANSPARENT : GetBackgroundColor(); label.Paint(PaintInfo::CreateRootPaintInfo(
diff --git a/ui/views/corewm/tooltip_lacros.cc b/ui/views/corewm/tooltip_lacros.cc index 380655a..58115595 100644 --- a/ui/views/corewm/tooltip_lacros.cc +++ b/ui/views/corewm/tooltip_lacros.cc
@@ -76,19 +76,13 @@ text_ = text; position_ = position; - // TODO(crbug.com/1492220) - Figure out why this is necessary and get the - // correctly computed offset. - if (parent_window_->GetType() == aura::client::WINDOW_TYPE_POPUP) { - position_.Offset(0, 36); - } - // Add the distance between `parent_window` and its toplevel window to // `position_` since Ash-side server will use this position as relative to // wayland toplevel window. // TODO(crbug.com/1385219): Use WaylandWindow instead of ToplevelWindow/Popup // when it's supported on ozone. aura::Window::ConvertPointToTarget( - parent_window_, parent_window_->GetToplevelWindow(), &position_); + parent_window_, parent_window_->GetRootWindow(), &position_); trigger_ = trigger; }
diff --git a/ui/views/examples/examples_main_proc.cc b/ui/views/examples/examples_main_proc.cc index 7e2eb57..51a2dc8 100644 --- a/ui/views/examples/examples_main_proc.cc +++ b/ui/views/examples/examples_main_proc.cc
@@ -156,13 +156,18 @@ { #if BUILDFLAG(IS_CHROMEOS_ASH) ExamplesViewsDelegateChromeOS views_delegate; -#else +#else // BUILDFLAG(IS_CHROMEOS_ASH) views::DesktopTestViewsDelegate views_delegate; +#if BUILDFLAG(IS_MAC) + views_delegate.set_context_factory(context_factories->GetContextFactory()); +#endif #if defined(USE_AURA) wm::WMState wm_state; #endif -#endif -#if BUILDFLAG(ENABLE_DESKTOP_AURA) +#endif // !BUILDFLAG(IS_CHROMEOS_ASH) +#if BUILDFLAG(IS_MAC) + display::ScopedNativeScreen desktop_screen; +#elif BUILDFLAG(ENABLE_DESKTOP_AURA) std::unique_ptr<display::Screen> desktop_screen = views::CreateDesktopScreen(); #endif
diff --git a/ui/views/layout/proposed_layout.cc b/ui/views/layout/proposed_layout.cc index 9d198dd..b8af035 100644 --- a/ui/views/layout/proposed_layout.cc +++ b/ui/views/layout/proposed_layout.cc
@@ -57,10 +57,6 @@ default; ProposedLayout& ProposedLayout::operator=(ProposedLayout&& other) = default; -bool ProposedLayout::operator==(const ProposedLayout& other) const { - return host_size == other.host_size && child_layouts == other.child_layouts; -} - std::string ProposedLayout::ToString() const { std::ostringstream oss; oss << "{" << host_size.ToString() << " {";
diff --git a/ui/views/layout/proposed_layout.h b/ui/views/layout/proposed_layout.h index 2649ed3e..b318f7d 100644 --- a/ui/views/layout/proposed_layout.h +++ b/ui/views/layout/proposed_layout.h
@@ -23,11 +23,10 @@ // Note that comparison ignores available size; as two layouts with the same // geometry are the same even if the available size is different. bool operator==(const ChildLayout& other) const; - bool operator!=(const ChildLayout& other) const { return !(*this == other); } std::string ToString() const; - raw_ptr<View, AcrossTasksDanglingUntriaged> child_view = nullptr; + raw_ptr<View> child_view = nullptr; bool visible = false; gfx::Rect bounds; SizeBounds available_size; @@ -44,10 +43,7 @@ ProposedLayout& operator=(const ProposedLayout& other); ProposedLayout& operator=(ProposedLayout&& other); - bool operator==(const ProposedLayout& other) const; - bool operator!=(const ProposedLayout& other) const { - return !(*this == other); - } + bool operator==(const ProposedLayout& other) const = default; std::string ToString() const;
diff --git a/ui/views/test/mock_native_widget.h b/ui/views/test/mock_native_widget.h index 9280c9b..f682604 100644 --- a/ui/views/test/mock_native_widget.h +++ b/ui/views/test/mock_native_widget.h
@@ -161,7 +161,6 @@ SetVisibilityAnimationTransition, (Widget::VisibilityTransition transition), (override)); - MOCK_METHOD(bool, IsTranslucentWindowOpacitySupported, (), (const override)); MOCK_METHOD(ui::GestureRecognizer*, GetGestureRecognizer, (), (override)); MOCK_METHOD(ui::GestureConsumer*, GetGestureConsumer, (), (override)); MOCK_METHOD(void, OnSizeConstraintsChanged, (), (override));
diff --git a/ui/views/test/views_test_base.cc b/ui/views/test/views_test_base.cc index bbe9cf8..aa715fd4 100644 --- a/ui/views/test/views_test_base.cc +++ b/ui/views/test/views_test_base.cc
@@ -30,25 +30,10 @@ #include "ui/views/widget/native_widget_mac.h" #endif -#if BUILDFLAG(IS_OZONE) -#include "ui/ozone/public/ozone_platform.h" -#include "ui/ozone/public/platform_gl_egl_utility.h" -#endif - namespace views { namespace { -bool DoesVisualHaveAlphaForTest() { -#if BUILDFLAG(IS_OZONE) - const auto* const egl_utility = - ui::OzonePlatform::GetInstance()->GetPlatformGLEGLUtility(); - return egl_utility ? egl_utility->X11DoesVisualHaveAlphaForTest() : false; -#else - return false; -#endif -} - } // namespace void ViewsTestBase::WidgetCloser::operator()(Widget* widget) const { @@ -67,8 +52,6 @@ } void ViewsTestBase::SetUp() { - has_compositing_manager_ = DoesVisualHaveAlphaForTest(); - testing::Test::SetUp(); setup_called_ = true; @@ -135,10 +118,6 @@ return widget; } -bool ViewsTestBase::HasCompositingManager() const { - return has_compositing_manager_; -} - void ViewsTestBase::SimulateNativeDestroy(Widget* widget) { test_helper_->SimulateNativeDestroy(widget); }
diff --git a/ui/views/test/views_test_base.h b/ui/views/test/views_test_base.h index 3301b58..c763624 100644 --- a/ui/views/test/views_test_base.h +++ b/ui/views/test/views_test_base.h
@@ -92,8 +92,6 @@ virtual std::unique_ptr<Widget> CreateTestWidget(Widget::InitParams params); - bool HasCompositingManager() const; - // Simulate an OS-level destruction of the native window held by non-desktop // |widget|. void SimulateNativeDestroy(Widget* widget); @@ -177,7 +175,6 @@ bool interactive_setup_called_ = false; bool setup_called_ = false; bool teardown_called_ = false; - bool has_compositing_manager_ = false; #if BUILDFLAG(IS_WIN) ui::ScopedOleInitializer ole_initializer_;
diff --git a/ui/views/views_delegate.cc b/ui/views/views_delegate.cc index 41da8d14..b89b4a2 100644 --- a/ui/views/views_delegate.cc +++ b/ui/views/views_delegate.cc
@@ -75,6 +75,13 @@ return true; } +#if BUILDFLAG(IS_CHROMEOS_LACROS) +bool ViewsDelegate::ShouldWindowHaveRoundedCorners( + const gfx::NativeWindow window) const { + return false; +} +#endif + #if BUILDFLAG(IS_WIN) HICON ViewsDelegate::GetDefaultWindowIcon() const { return nullptr;
diff --git a/ui/views/views_delegate.h b/ui/views/views_delegate.h index 9d4f2fe..8a94873 100644 --- a/ui/views/views_delegate.h +++ b/ui/views/views_delegate.h
@@ -129,6 +129,14 @@ // this returns true. virtual bool ShouldCloseMenuIfMouseCaptureLost() const; +#if BUILDFLAG(IS_CHROMEOS_LACROS) + // Returns true if the native `window` should have rounded corners. The + // decision can be based on multiple factors, including the window's current + // state. + virtual bool ShouldWindowHaveRoundedCorners( + const gfx::NativeWindow window) const; +#endif + #if BUILDFLAG(IS_WIN) // Retrieves the default window icon to use for windows if none is specified. virtual HICON GetDefaultWindowIcon() const;
diff --git a/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc b/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc index 851fe7d9..5babfd2 100644 --- a/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc +++ b/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc
@@ -1166,11 +1166,6 @@ wm::SetWindowVisibilityAnimationTransition(content_window_, wm_transition); } -bool DesktopNativeWidgetAura::IsTranslucentWindowOpacitySupported() const { - return desktop_window_tree_host_ && - desktop_window_tree_host_->IsTranslucentWindowOpacitySupported(); -} - ui::GestureRecognizer* DesktopNativeWidgetAura::GetGestureRecognizer() { return aura::Env::GetInstance()->gesture_recognizer(); }
diff --git a/ui/views/widget/desktop_aura/desktop_native_widget_aura.h b/ui/views/widget/desktop_aura/desktop_native_widget_aura.h index 3ed091c..2946123 100644 --- a/ui/views/widget/desktop_aura/desktop_native_widget_aura.h +++ b/ui/views/widget/desktop_aura/desktop_native_widget_aura.h
@@ -211,7 +211,6 @@ void SetVisibilityAnimationDuration(const base::TimeDelta& duration) override; void SetVisibilityAnimationTransition( Widget::VisibilityTransition transition) override; - bool IsTranslucentWindowOpacitySupported() const override; ui::GestureRecognizer* GetGestureRecognizer() override; ui::GestureConsumer* GetGestureConsumer() override; void OnSizeConstraintsChanged() override;
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host.h b/ui/views/widget/desktop_aura/desktop_window_tree_host.h index fb85354..ea82de3 100644 --- a/ui/views/widget/desktop_aura/desktop_window_tree_host.h +++ b/ui/views/widget/desktop_aura/desktop_window_tree_host.h
@@ -193,9 +193,6 @@ // animations. virtual bool IsAnimatingClosed() const = 0; - // Returns true if the Widget supports translucency. - virtual bool IsTranslucentWindowOpacitySupported() const = 0; - // Called when the window's size constraints change. virtual void SizeConstraintsChanged() = 0;
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_lacros.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_lacros.cc index 5028a156..0c9041e 100644 --- a/ui/views/widget/desktop_aura/desktop_window_tree_host_lacros.cc +++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_lacros.cc
@@ -6,15 +6,20 @@ #include <memory> #include <string> +#include <vector> +#include "base/logging.h" #include "chromeos/ui/base/window_properties.h" #include "ui/aura/client/aura_constants.h" #include "ui/aura/env.h" #include "ui/aura/window.h" #include "ui/aura/window_delegate.h" +#include "ui/compositor/layer.h" #include "ui/events/event.h" #include "ui/events/event_handler.h" #include "ui/events/event_target.h" +#include "ui/gfx/geometry/rounded_corners_f.h" +#include "ui/gfx/geometry/rrect_f.h" #include "ui/ozone/public/ozone_platform.h" #include "ui/platform_window/extensions/desk_extension.h" #include "ui/platform_window/extensions/pinned_mode_extension.h" @@ -28,6 +33,7 @@ #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h" #include "ui/views/widget/desktop_aura/window_event_filter_lacros.h" #include "ui/views/widget/widget.h" +#include "ui/views/window/non_client_view.h" namespace { @@ -141,6 +147,8 @@ GetContentWindow()->SetProperty( chromeos::kWindowStateTypeKey, ToChromeosWindowStateType(new_window_show_state)); + + UpdateWindowHints(); } void DesktopWindowTreeHostLacros::OnFullscreenTypeChanged( @@ -157,6 +165,13 @@ void DesktopWindowTreeHostLacros::OnOverviewModeChanged(bool in_overview) { GetContentWindow()->SetProperty(chromeos::kIsShowingInOverviewKey, in_overview); + + // Window corner radius depends on whether the window is in overview mode or + // not. Once the overview property has been updated, the browser window + // corners need to be updated. + // See `chromeos::GetFrameCornerRadius()` for more details. + // TODO(b/301501363): Rename to UpdateWindowHints. + UpdateWindowHints(); } void DesktopWindowTreeHostLacros::OnTooltipShownOnServer( @@ -174,6 +189,12 @@ } } +void DesktopWindowTreeHostLacros::OnBoundsChanged(const BoundsChange& change) { + DesktopWindowTreeHostPlatform::OnBoundsChanged(change); + + UpdateWindowHints(); +} + void DesktopWindowTreeHostLacros::AddAdditionalInitProperties( const Widget::InitParams& params, ui::PlatformWindowInitProperties* properties) { @@ -207,6 +228,12 @@ content_window_observation_.Reset(); } +void DesktopWindowTreeHostLacros::OnWidgetInitDone() { + DesktopWindowTreeHostPlatform::OnWidgetInitDone(); + + UpdateWindowHints(); +} + void DesktopWindowTreeHostLacros::CreateNonClientEventFilter() { DCHECK(!non_client_window_event_filter_); non_client_window_event_filter_ = std::make_unique<WindowEventFilterLacros>( @@ -217,6 +244,92 @@ non_client_window_event_filter_.reset(); } +void DesktopWindowTreeHostLacros::UpdateWindowHints() { + if (!GetWidget()->non_client_view()) { + return; + } + + const float scale = device_scale_factor(); + const gfx::Size widget_size_px = + platform_window()->GetBoundsInPixels().size(); + + auto* wayland_extension = ui::GetWaylandExtension(*platform_window()); + + const gfx::RoundedCornersF window_radii = + wayland_extension ? wayland_extension->GetWindowCornersRadii() + : gfx::RoundedCornersF(); + + std::vector<gfx::Rect> opaque_region; + + const bool should_have_rounded_window = + views::ViewsDelegate::GetInstance()->ShouldWindowHaveRoundedCorners( + GetWidget()->GetNativeWindow()); + + if (should_have_rounded_window) { + GetContentWindow()->layer()->SetRoundedCornerRadius(window_radii); + GetContentWindow()->layer()->SetIsFastRoundedCorner(true); + + // The opaque region is a list of rectangles that contain only fully + // opaque pixels of the window. We need to convert the clipping + // rounded-rect into this format. + const NonClientFrameView* frame_view = + GetWidget()->non_client_view()->frame_view(); + gfx::Rect local_bounds = frame_view->GetLocalBounds(); + gfx::RRectF rounded_corners_rect(gfx::RectF(local_bounds), window_radii); + gfx::RectF rect_f = rounded_corners_rect.rect(); + rect_f.Scale(scale); + + // It is acceptable to omit some pixels that are opaque, but the region + // must not include any translucent pixels. Therefore, we must + // conservatively scale to the enclosed rectangle. + gfx::Rect rect = gfx::ToEnclosedRect(rect_f); + + // Create the initial region from the clipping rectangle without rounded + // corners. + cc::Region region(rect); + + // Now subtract out the small rectangles that cover the corners. + struct { + gfx::RRectF::Corner corner; + bool left; + bool upper; + } kCorners[] = { + {gfx::RRectF::Corner::kUpperLeft, true, true}, + {gfx::RRectF::Corner::kUpperRight, false, true}, + {gfx::RRectF::Corner::kLowerLeft, true, false}, + {gfx::RRectF::Corner::kLowerRight, false, false}, + }; + for (const auto& corner : kCorners) { + auto corner_radii = rounded_corners_rect.GetCornerRadii(corner.corner); + auto rx = std::ceil(scale * corner_radii.x()); + auto ry = std::ceil(scale * corner_radii.y()); + auto corner_rect = + gfx::Rect(corner.left ? rect.x() : rect.right() - rx, + corner.upper ? rect.y() : rect.bottom() - ry, rx, ry); + region.Subtract(corner_rect); + } + + // Convert the region to a list of rectangles. + for (gfx::Rect i : region) { + opaque_region.push_back(i); + } + } else { + GetContentWindow()->layer()->SetRoundedCornerRadius({}); + GetContentWindow()->layer()->SetIsFastRoundedCorner(false); + opaque_region.push_back({{}, widget_size_px}); + } + // TODO(crbug.com/1306688): Instead of setting OpaqueRegion, set the rounded + // corners in dp. + platform_window()->SetOpaqueRegion(opaque_region); + + // If the window is rounded, we hint the platform to match the drop shadow's + // radii to the window's radii. Otherwise, we allow the platform to + // determine the drop shadow's radii. + if (should_have_rounded_window) { + wayland_extension->SetShadowCornersRadii(window_radii); + } +} + // static DesktopWindowTreeHostLacros* DesktopWindowTreeHostLacros::From( WindowTreeHost* wth) {
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_lacros.h b/ui/views/widget/desktop_aura/desktop_window_tree_host_lacros.h index be6d51d..cbb09034 100644 --- a/ui/views/widget/desktop_aura/desktop_window_tree_host_lacros.h +++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_lacros.h
@@ -70,6 +70,7 @@ void OnTooltipShownOnServer(const std::u16string& text, const gfx::Rect& bounds) override; void OnTooltipHiddenOnServer() override; + void OnBoundsChanged(const BoundsChange& change) override; // DesktopWindowTreeHostPlatform overrides: void AddAdditionalInitProperties( @@ -86,6 +87,9 @@ intptr_t old) override; void OnWindowDestroying(aura::Window* window) override; + // DesktopWindowTreeHost: + void OnWidgetInitDone() override; + private: FRIEND_TEST_ALL_PREFIXES(DesktopWindowTreeHostPlatformImplTestWithTouch, HitTest); @@ -93,6 +97,9 @@ void CreateNonClientEventFilter(); void DestroyNonClientEventFilter(); + // Sets hints for the WM/compositor that reflect the rounded corners. + void UpdateWindowHints(); + // A handler for events intended for non client area. // A posthandler for events intended for non client area. Handles events if no // other consumer handled them.
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc index 23e321b..90ebdc4 100644 --- a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc +++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc
@@ -796,11 +796,6 @@ return platform_window()->IsAnimatingClosed(); } -bool DesktopWindowTreeHostPlatform::IsTranslucentWindowOpacitySupported() - const { - return platform_window()->IsTranslucentWindowOpacitySupported(); -} - void DesktopWindowTreeHostPlatform::SizeConstraintsChanged() { platform_window()->SizeConstraintsChanged(); }
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h index 6c68371..2facd48 100644 --- a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h +++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h
@@ -133,7 +133,6 @@ void InitModalType(ui::ModalType modal_type) override; void FlashFrame(bool flash_frame) override; bool IsAnimatingClosed() const override; - bool IsTranslucentWindowOpacitySupported() const override; void SizeConstraintsChanged() override; bool ShouldUpdateWindowTransparency() const override; bool ShouldUseDesktopNativeCursorManager() const override;
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc index 5e613d18..d877d23 100644 --- a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc +++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc
@@ -535,7 +535,7 @@ } bool DesktopWindowTreeHostWin::ShouldUseNativeFrame() const { - return IsTranslucentWindowOpacitySupported(); + return true; } bool DesktopWindowTreeHostWin::ShouldWindowContentsBeTransparent() const { @@ -601,10 +601,6 @@ return pending_close_; } -bool DesktopWindowTreeHostWin::IsTranslucentWindowOpacitySupported() const { - return true; -} - void DesktopWindowTreeHostWin::SizeConstraintsChanged() { message_handler_->SizeConstraintsChanged(); }
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h index 013f571..e963c86 100644 --- a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h +++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h
@@ -154,7 +154,6 @@ void InitModalType(ui::ModalType modal_type) override; void FlashFrame(bool flash_frame) override; bool IsAnimatingClosed() const override; - bool IsTranslucentWindowOpacitySupported() const override; void SizeConstraintsChanged() override; bool ShouldUpdateWindowTransparency() const override; bool ShouldUseDesktopNativeCursorManager() const override;
diff --git a/ui/views/widget/native_widget_aura.cc b/ui/views/widget/native_widget_aura.cc index 19f417b..d328226 100644 --- a/ui/views/widget/native_widget_aura.cc +++ b/ui/views/widget/native_widget_aura.cc
@@ -977,10 +977,6 @@ wm::SetWindowVisibilityAnimationTransition(window_, wm_transition); } -bool NativeWidgetAura::IsTranslucentWindowOpacitySupported() const { - return true; -} - ui::GestureRecognizer* NativeWidgetAura::GetGestureRecognizer() { return aura::Env::GetInstance()->gesture_recognizer(); }
diff --git a/ui/views/widget/native_widget_aura.h b/ui/views/widget/native_widget_aura.h index 73ddbe3..5deaa7cb 100644 --- a/ui/views/widget/native_widget_aura.h +++ b/ui/views/widget/native_widget_aura.h
@@ -164,7 +164,6 @@ void SetVisibilityAnimationDuration(const base::TimeDelta& duration) override; void SetVisibilityAnimationTransition( Widget::VisibilityTransition transition) override; - bool IsTranslucentWindowOpacitySupported() const override; ui::GestureRecognizer* GetGestureRecognizer() override; ui::GestureConsumer* GetGestureConsumer() override; void OnSizeConstraintsChanged() override;
diff --git a/ui/views/widget/native_widget_mac.h b/ui/views/widget/native_widget_mac.h index f82654a..dd20417 100644 --- a/ui/views/widget/native_widget_mac.h +++ b/ui/views/widget/native_widget_mac.h
@@ -202,7 +202,6 @@ void SetVisibilityAnimationDuration(const base::TimeDelta& duration) override; void SetVisibilityAnimationTransition( Widget::VisibilityTransition transition) override; - bool IsTranslucentWindowOpacitySupported() const override; ui::GestureRecognizer* GetGestureRecognizer() override; ui::GestureConsumer* GetGestureConsumer() override; void OnSizeConstraintsChanged() override;
diff --git a/ui/views/widget/native_widget_mac.mm b/ui/views/widget/native_widget_mac.mm index 1ae9331..3a6617a 100644 --- a/ui/views/widget/native_widget_mac.mm +++ b/ui/views/widget/native_widget_mac.mm
@@ -896,10 +896,6 @@ GetNSWindowMojo()->SetTransitionsToAnimate(transitions); } -bool NativeWidgetMac::IsTranslucentWindowOpacitySupported() const { - return false; -} - ui::GestureRecognizer* NativeWidgetMac::GetGestureRecognizer() { static base::NoDestructor<ui::GestureRecognizerImplMac> recognizer; return recognizer.get();
diff --git a/ui/views/widget/native_widget_private.h b/ui/views/widget/native_widget_private.h index 23af442..3ac7a45a 100644 --- a/ui/views/widget/native_widget_private.h +++ b/ui/views/widget/native_widget_private.h
@@ -242,7 +242,6 @@ const base::TimeDelta& duration) = 0; virtual void SetVisibilityAnimationTransition( Widget::VisibilityTransition transition) = 0; - virtual bool IsTranslucentWindowOpacitySupported() const = 0; virtual ui::GestureRecognizer* GetGestureRecognizer() = 0; virtual ui::GestureConsumer* GetGestureConsumer() = 0; virtual void OnSizeConstraintsChanged() = 0;
diff --git a/ui/views/widget/widget.cc b/ui/views/widget/widget.cc index 866bb701..5093dee2 100644 --- a/ui/views/widget/widget.cc +++ b/ui/views/widget/widget.cc
@@ -58,6 +58,10 @@ #include "ui/linux/linux_ui.h" #endif +#if BUILDFLAG(IS_OZONE) +#include "ui/ozone/public/ozone_platform.h" +#endif + namespace views { namespace { @@ -358,6 +362,17 @@ return type == InitParams::TYPE_WINDOW || type == InitParams::TYPE_BUBBLE; } +// static +bool Widget::IsWindowCompositingSupported() { +#if BUILDFLAG(IS_WIN) + return true; +#elif BUILDFLAG(IS_OZONE) + return ui::OzonePlatform::GetInstance()->IsWindowCompositingSupported(); +#else + return false; +#endif +} + void Widget::Init(InitParams params) { TRACE_EVENT0("views", "Widget::Init"); @@ -1322,11 +1337,6 @@ root_view_->OnMouseMoved(mouse_event); } -bool Widget::IsTranslucentWindowOpacitySupported() const { - return native_widget_ ? native_widget_->IsTranslucentWindowOpacitySupported() - : false; -} - ui::GestureRecognizer* Widget::GetGestureRecognizer() { return native_widget_ ? native_widget_->GetGestureRecognizer() : nullptr; }
diff --git a/ui/views/widget/widget.h b/ui/views/widget/widget.h index 65959ee..1939476 100644 --- a/ui/views/widget/widget.h +++ b/ui/views/widget/widget.h
@@ -279,8 +279,7 @@ // If kOpaque, we can perform optimizations based on the widget being fully // opaque. Default is based on ViewsDelegate::GetOpacityForInitParams(). // Defaults to kOpaque for non-window widgets. Translucent windows may not - // always be supported. Use IsTranslucentWindowOpacitySupported() to - // determine whether they are. + // always be supported. WindowOpacity opacity = WindowOpacity::kInferred; bool accept_events = true; @@ -558,6 +557,8 @@ // Returns true if the specified type requires a NonClientView. static bool RequiresNonClientView(InitParams::Type type); + static bool IsWindowCompositingSupported(); + // Initializes the widget, and in turn, the native widget. |params| should be // moved to Init() by the caller. void Init(InitParams params); @@ -1059,9 +1060,6 @@ // mouse location to refresh hovering status in the widget. void SynthesizeMouseMoveEvent(); - // Whether the widget supports translucency. - bool IsTranslucentWindowOpacitySupported() const; - // Returns the gesture recognizer which can handle touch/gesture events on // this. ui::GestureRecognizer* GetGestureRecognizer();
diff --git a/ui/views/widget/widget_unittest.cc b/ui/views/widget/widget_unittest.cc index f0a4dd4..7a8b781 100644 --- a/ui/views/widget/widget_unittest.cc +++ b/ui/views/widget/widget_unittest.cc
@@ -94,11 +94,6 @@ #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h" #endif -#if BUILDFLAG(IS_OZONE) -#include "ui/ozone/public/ozone_platform.h" -#include "ui/ozone/public/platform_gl_egl_utility.h" -#endif - namespace views::test { namespace { @@ -1687,11 +1682,6 @@ widget()->IsStackedAbove(other_widget->GetNativeView()); } -TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, - IsTranslucentWindowOpacitySupported) { - widget()->IsTranslucentWindowOpacitySupported(); -} - TEST_P(WidgetWithDestroyedNativeViewOrNativeWidgetTest, IsVisible) { widget()->IsVisible(); } @@ -5931,28 +5921,6 @@ namespace { -bool CanHaveCompositingManager() { -#if BUILDFLAG(IS_OZONE) - auto* const egl_utility = - ui::OzonePlatform::GetInstance()->GetPlatformGLEGLUtility(); - return (egl_utility != nullptr) && egl_utility->HasVisualManager(); -#else - return false; -#endif -} - -bool ExpectWidgetTransparency(Widget::InitParams::WindowOpacity opacity) { - switch (opacity) { - case Widget::InitParams::WindowOpacity::kOpaque: - return false; - case Widget::InitParams::WindowOpacity::kTranslucent: - return true; - case Widget::InitParams::WindowOpacity::kInferred: - ADD_FAILURE() << "WidgetOpacity must be explicitly set"; - return false; - } -} - class CompositingWidgetTest : public DesktopWidgetTest { public: CompositingWidgetTest() @@ -6011,13 +5979,6 @@ EXPECT_EQ(IsNativeWindowTransparent(widget->GetNativeWindow()), should_be_transparent); - - if (CanHaveCompositingManager()) { - if (HasCompositingManager() && ExpectWidgetTransparency(opacity)) - EXPECT_TRUE(widget->IsTranslucentWindowOpacitySupported()); - else - EXPECT_FALSE(widget->IsTranslucentWindowOpacitySupported()); - } } }
diff --git a/ui/webui/resources/cr_components/theme_color_picker/theme_hue_slider_dialog.html b/ui/webui/resources/cr_components/theme_color_picker/theme_hue_slider_dialog.html index a6934e4..ad5d4e8 100644 --- a/ui/webui/resources/cr_components/theme_color_picker/theme_hue_slider_dialog.html +++ b/ui/webui/resources/cr_components/theme_color_picker/theme_hue_slider_dialog.html
@@ -103,6 +103,7 @@ <dialog id="dialog"> <div id="header"> <h2 id="title">[[i18n('hueSliderTitle')]]</h2> + <slot name="headerSuffix"></slot> <cr-icon-button id="close" class="icon-clear" aria-label$="[[i18n('close')]]" title$="[[i18n('close')]]"
diff --git a/v8 b/v8 index 017bc6b..13036d7 160000 --- a/v8 +++ b/v8
@@ -1 +1 @@ -Subproject commit 017bc6b893e733863245628de6f216922150bed3 +Subproject commit 13036d7a479a2da10ead4bdc99804cd2e93bb201