diff --git a/DEPS b/DEPS index f724d3a..8211738f 100644 --- a/DEPS +++ b/DEPS
@@ -144,6 +144,13 @@ # tools/clang/OWNERS before depending on it. 'checkout_clang_libs': 'use_rust', + # Fetch prebuilt and prepackaged Bazel binary/executable. Bazel is currently + # only needed by `chromium/src/tools/rust/build_crubit.py` and therefore + # shouldn't be used outside of Chromium Rust Experiments project. + # Furthermore note that Bazel is only needed when building Crubit during Rust + # toolchain build (and is *not* needed during regular Chromium builds). + 'checkout_bazel': False, + # Fetch Crubit support libraries in order to build ..._rs_api.rs and # ..._rs_api_impl.cc that are generated by prebuilt (see # tools/rust/build_crubit.py) Crubit tools during Chromium build (see @@ -190,10 +197,11 @@ # qemu on linux-arm64 machines. 'checkout_fuchsia_for_arm64_host': False, - # Revision of Crubit (trunk on 2022-07-13). This should typically be the + # Revision of Crubit (trunk on 2022-07-14). This should typically be the # same as the revision specified in CRUBIT_REVISION in - # tools/rust/update_rust.py. - 'crubit_revision': '07b3390a62412543c80226db44eecc317bbfcee0', + # tools/rust/update_rust.py. More details and roll instructions can be + # found in tools/rust/README.md. + 'crubit_revision': 'd9b0ad4c09b46328dcc7a5ec28ce86cca56e0389', # Run 'vpython_common' hook if this is set. # TODO(crbug.com/1329052): remove this when we remove .vpython. @@ -289,11 +297,11 @@ # 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': '2d95df3369910d3993d945b143368a94340275cd', + 'skia_revision': '4230d45a2f1d20f42be581ae73cae098519c2f90', # 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': 'e5aae8c52076579da9f20796073898dcb8717c4c', + 'v8_revision': '87528380c21affd775e85975c141fce8dd0b86bb', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ANGLE # and whatever else without interference from each other. @@ -336,7 +344,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling NaCl # and whatever else without interference from each other. - 'nacl_revision': '341a8e762364bc6a92362828ef26f4a067843e09', + 'nacl_revision': '04e5b5755d3d7f63fb3c212df8fc3ed6b484f7f7', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling freetype # and whatever else without interference from each other. @@ -404,7 +412,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'dawn_revision': '73a5a716b531c296354d43711a1884df5682a627', + 'dawn_revision': 'e4df87fd017cd1d3eacbfbed57e521f6f7733936', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -432,7 +440,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': 'bbf6de9d12bcbe2e709ea06b2ec06b4598295fe5', + 'nearby_revision': 'eaac8d045d44a2592c927f0440328b1b96538b59', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling securemessage # and whatever else without interference from each other. @@ -1148,7 +1156,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' + '@' + 'fd92310398dc2d3d97087d863e95afff553dada9', + 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '1734cae2fd73cfd6cac2d4ade63eb703a380bde4', 'condition': 'checkout_chromeos', }, @@ -1176,7 +1184,7 @@ }, 'src/third_party/depot_tools': - Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '90191b14c2be0a5344c2379681ce5c0460434e23', + Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '56101e1c90fe8c2185f74d7ee60f964082f7295b', 'src/third_party/devtools-frontend/src': Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'), @@ -1743,7 +1751,7 @@ Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '44e4c8770158c505b03ee7feafa4859d083b0912', 'src/third_party/webgpu-cts/src': - Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '228c2824fcb0c949e572e31bea76bcf66380fe21', + Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + 'd3094065b871f1fb6822e8d01741ca417916568b', 'src/third_party/webrtc': Var('webrtc_git') + '/src.git' + '@' + '049dde6c8ef0eaaa00896787783f6725c9a2fe78', @@ -1776,7 +1784,7 @@ 'packages': [ { 'package': 'skia/tools/goldctl/linux-amd64', - 'version': 'Ri4sbgofBQTekhs0H-MmBCEBFmTBIzjMFWjrISXy44QC', + 'version': 'BquSeorcTU84O2_A8IoWetGrcfLWxLfZCo9sve1Wt2IC', }, ], 'dep_type': 'cipd', @@ -1786,7 +1794,7 @@ 'packages': [ { 'package': 'skia/tools/goldctl/windows-amd64', - 'version': '2hLrGJKgXQCcX5OqtWO__r1MDSY-ix-DaFzXPUcuOJQC', + 'version': 'AOoQr1u4-cOIEYJDAgVxGWoTiPaRcjrSsjjAaB-u_ggC', }, ], 'dep_type': 'cipd', @@ -1797,7 +1805,7 @@ 'packages': [ { 'package': 'skia/tools/goldctl/mac-amd64', - 'version': '2FFjh0Xtg__05cZwoN_kBY9gONiqBgS4k96j4PiERwQC', + 'version': '-t3YY_sZ-jtMAYZ2PlhjudFnEUgk4m-HjlIwSip4tOAC', }, ], 'dep_type': 'cipd', @@ -1808,7 +1816,7 @@ 'packages': [ { 'package': 'skia/tools/goldctl/mac-arm64', - 'version': 'CDhGE0xDG5UpFXKhktNh4Hn1ahNh3qpRQ1KDKvRjuWgC', + 'version': 'x_xKUnqrgizoTO8mxX4RkyhpQ-nUp_x_go9YH-tc--QC', }, ], 'dep_type': 'cipd', @@ -1819,7 +1827,7 @@ Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'), 'src-internal': { - 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@f09db7d74a87f5a5c56e06f6fc443b7db70fcd0c', + 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@5f7fa810d621a842dacfcaebc48d981f0b012170', 'condition': 'checkout_src_internal', }, @@ -3616,6 +3624,15 @@ ], 'dep_type': 'cipd', }, + + 'src/tools/bazel': { + 'packages': [{ + 'package': 'infra/3pp/tools/bazel_bootstrap/${{platform}}', + 'version': 'version:2@5.2.0.1', + }], + 'dep_type': 'cipd', + 'condition': 'checkout_bazel', + }, }
diff --git a/android_webview/lib/aw_main_delegate.cc b/android_webview/lib/aw_main_delegate.cc index e5ce4b2..b55223f 100644 --- a/android_webview/lib/aw_main_delegate.cc +++ b/android_webview/lib/aw_main_delegate.cc
@@ -86,7 +86,7 @@ AwMainDelegate::~AwMainDelegate() = default; -bool AwMainDelegate::BasicStartupComplete(int* exit_code) { +absl::optional<int> AwMainDelegate::BasicStartupComplete() { TRACE_EVENT0("startup", "AwMainDelegate::BasicStartupComplete"); base::CommandLine* cl = base::CommandLine::ForCurrentProcess(); @@ -354,7 +354,7 @@ // partially-initialized, which the TLS object is supposed to protect again. heap_profiling::InitTLSSlot(); - return false; + return absl::nullopt; } void AwMainDelegate::PreSandboxStartup() { @@ -431,7 +431,8 @@ variations::VariationsIdsProvider::Mode::kDontSendSignedInVariations); } -void AwMainDelegate::PostEarlyInitialization(InvokedIn invoked_in) { +absl::optional<int> AwMainDelegate::PostEarlyInitialization( + InvokedIn invoked_in) { const bool is_browser_process = absl::holds_alternative<InvokedInBrowserProcess>(invoked_in); if (is_browser_process) { @@ -456,6 +457,7 @@ gwp_asan::EnableForPartitionAlloc(is_canary_dev || is_browser_process, process_type.c_str()); #endif + return absl::nullopt; } content::ContentClient* AwMainDelegate::CreateContentClient() {
diff --git a/android_webview/lib/aw_main_delegate.h b/android_webview/lib/aw_main_delegate.h index 1d9a0b2..b0d6c1d 100644 --- a/android_webview/lib/aw_main_delegate.h +++ b/android_webview/lib/aw_main_delegate.h
@@ -37,7 +37,7 @@ private: // content::ContentMainDelegate implementation: - bool BasicStartupComplete(int* exit_code) override; + absl::optional<int> BasicStartupComplete() override; void PreSandboxStartup() override; absl::variant<int, content::MainFunctionParams> RunProcess( const std::string& process_type, @@ -45,7 +45,7 @@ void ProcessExiting(const std::string& process_type) override; bool ShouldCreateFeatureList(InvokedIn invoked_in) override; variations::VariationsIdsProvider* CreateVariationsIdsProvider() override; - void PostEarlyInitialization(InvokedIn invoked_in) override; + absl::optional<int> PostEarlyInitialization(InvokedIn invoked_in) override; content::ContentClient* CreateContentClient() override; content::ContentBrowserClient* CreateContentBrowserClient() override; content::ContentGpuClient* CreateContentGpuClient() override;
diff --git a/ash/BUILD.gn b/ash/BUILD.gn index bd4c376..4717d5a 100644 --- a/ash/BUILD.gn +++ b/ash/BUILD.gn
@@ -971,6 +971,8 @@ "style/style_util.h", "style/system_shadow.cc", "style/system_shadow.h", + "style/system_shadow_on_nine_patch_layer.cc", + "style/system_shadow_on_nine_patch_layer.h", "style/system_toast_style.cc", "style/system_toast_style.h", "system/accessibility/accessibility_feature_disable_dialog.cc", @@ -1098,6 +1100,10 @@ "system/cast/unified_cast_detailed_view_controller.h", "system/channel_indicator/channel_indicator.cc", "system/channel_indicator/channel_indicator.h", + "system/channel_indicator/channel_indicator_quick_settings_view.cc", + "system/channel_indicator/channel_indicator_quick_settings_view.h", + "system/channel_indicator/channel_indicator_utils.cc", + "system/channel_indicator/channel_indicator_utils.h", "system/dark_mode/dark_mode_feature_pod_controller.cc", "system/dark_mode/dark_mode_feature_pod_controller.h", "system/diagnostics/async_log.cc", @@ -1525,6 +1531,8 @@ "system/power/tray_power.h", "system/power/video_activity_notifier.cc", "system/power/video_activity_notifier.h", + "system/privacy/privacy_indicators_controller.cc", + "system/privacy/privacy_indicators_controller.h", "system/privacy_screen/privacy_screen_feature_pod_controller.cc", "system/privacy_screen/privacy_screen_feature_pod_controller.h", "system/privacy_screen/privacy_screen_toast_controller.cc", @@ -1867,6 +1875,8 @@ "wm/desks/templates/saved_desk_animations.h", "wm/desks/templates/saved_desk_dialog_controller.cc", "wm/desks/templates/saved_desk_dialog_controller.h", + "wm/desks/templates/saved_desk_feedback_button.cc", + "wm/desks/templates/saved_desk_feedback_button.h", "wm/desks/templates/saved_desk_grid_view.cc", "wm/desks/templates/saved_desk_grid_view.h", "wm/desks/templates/saved_desk_icon_container.cc", @@ -2555,6 +2565,7 @@ "display/persistent_window_controller_unittest.cc", "display/privacy_screen_controller_unittest.cc", "display/projecting_observer_unittest.cc", + "display/refresh_rate_throttle_controller_unittest.cc", "display/resolution_notification_controller_unittest.cc", "display/root_window_transformers_unittest.cc", "display/screen_ash_unittest.cc", @@ -2727,7 +2738,9 @@ "system/bluetooth/tray_bluetooth_helper_legacy_unittest.cc", "system/bluetooth/unified_bluetooth_detailed_view_controller_unittest.cc", "system/caps_lock_notification_controller_unittest.cc", + "system/channel_indicator/channel_indicator_quick_settings_view_unittest.cc", "system/channel_indicator/channel_indicator_unittest.cc", + "system/channel_indicator/channel_indicator_utils_unittest.cc", "system/dark_mode/dark_mode_feature_pod_controller_unittest.cc", "system/diagnostics/async_log_unittest.cc", "system/diagnostics/diagnostics_log_controller_unittest.cc",
diff --git a/ash/app_list/views/app_list_folder_view.cc b/ash/app_list/views/app_list_folder_view.cc index c91d05e7..88a56424 100644 --- a/ash/app_list/views/app_list_folder_view.cc +++ b/ash/app_list/views/app_list_folder_view.cc
@@ -129,7 +129,7 @@ background_view_(background_view), shadow_(folder_view->shadow()) { background_view_observer_.Observe(background_view_); - shadow_->shadow_layer()->SetVisible(true); + shadow_->GetLayer()->SetVisible(true); } BackgroundAnimation(const BackgroundAnimation&) = delete; @@ -137,7 +137,7 @@ ~BackgroundAnimation() override { if (!show_) - shadow_->shadow_layer()->SetVisible(false); + shadow_->GetLayer()->SetVisible(false); } private: @@ -705,9 +705,10 @@ CreatePagedAppsGrid(contents_view); // Create a shadow under `background_view_`. - shadow_ = std::make_unique<SystemShadow>(SystemShadow::Type::kElevation8); - background_view_->AddLayerBeneathView(shadow_->layer()); - shadow_->shadow_layer()->SetVisible(false); + shadow_ = SystemShadow::CreateShadowOnNinePatchLayer( + SystemShadow::Type::kElevation8); + background_view_->AddLayerBeneathView(shadow_->GetLayer()); + shadow_->GetLayer()->SetVisible(false); AppListModelProvider::Get()->AddObserver(this); }
diff --git a/ash/app_list/views/search_result_page_view.cc b/ash/app_list/views/search_result_page_view.cc index c7aaca8b..47deac9 100644 --- a/ash/app_list/views/search_result_page_view.cc +++ b/ash/app_list/views/search_result_page_view.cc
@@ -24,7 +24,6 @@ #include "ash/public/cpp/app_list/app_list_config.h" #include "ash/public/cpp/app_list/app_list_features.h" #include "ash/public/cpp/style/color_provider.h" -#include "ash/public/cpp/view_shadow.h" #include "ash/search_box/search_box_constants.h" #include "ash/strings/grit/ash_strings.h" #include "ash/style/system_shadow.h" @@ -200,12 +199,9 @@ contents_view_->SetLayoutManager(std::make_unique<views::BoxLayout>( views::BoxLayout::Orientation::kVertical, gfx::Insets(), 0)); - view_shadow_ = std::make_unique<ViewShadow>( - this, - SystemShadow::GetElevationFromType(kSearchBoxSearchResultShadowType)); - view_shadow_->shadow()->SetShadowStyle(gfx::ShadowStyle::kChromeOSSystemUI); - view_shadow_->SetRoundedCornerRadius( - kSearchBoxBorderCornerRadiusSearchResult); + shadow_ = SystemShadow::CreateShadowOnNinePatchLayerForView( + this, kSearchBoxSearchResultShadowType); + shadow_->SetRoundedCornerRadius(kSearchBoxBorderCornerRadiusSearchResult); // Hides this view behind the search box by using the same color and // background border corner radius. All child views' background should be @@ -603,7 +599,7 @@ gfx::Rect clip_rect = from_rect; clip_rect -= to_rect.OffsetFromOrigin(); layer()->SetClipRect(clip_rect); - view_shadow_.reset(); + shadow_.reset(); base::TimeDelta duration; if (from_rect.height() < to_rect.height()) { @@ -632,11 +628,9 @@ } void SearchResultPageView::OnAnimationBetweenBoundsEnded() { - view_shadow_ = std::make_unique<ViewShadow>( - this, - SystemShadow::GetElevationFromType(kSearchBoxSearchResultShadowType)); - view_shadow_->shadow()->SetShadowStyle(gfx::ShadowStyle::kChromeOSSystemUI); - view_shadow_->SetRoundedCornerRadius( + shadow_ = SystemShadow::CreateShadowOnNinePatchLayerForView( + this, kSearchBoxSearchResultShadowType); + shadow_->SetRoundedCornerRadius( GetCornerRadiusForSearchResultsState(current_search_results_state_)); // To keep the animation visible for closing transitions from expanded search @@ -841,8 +835,8 @@ Layout(); animator.Run(default_offset, layer()); - if (view_shadow_) - animator.Run(default_offset, view_shadow_->shadow()->shadow_layer()); + if (shadow_) + animator.Run(default_offset, shadow_->GetNinePatchLayer()); SearchResultPageAnchoredDialog* search_page_dialog = dialog_controller_->dialog(); if (search_page_dialog) { @@ -926,7 +920,7 @@ // This changes the shadow's corner immediately while this corner bounds // gradually. This would be fine because this would be unnoticeable to // users. - view_shadow_->SetRoundedCornerRadius(to_radius); + shadow_->SetRoundedCornerRadius(to_radius); } // Animate the shadow's bounds through transform. @@ -936,11 +930,11 @@ transform.Scale( static_cast<float>(from_rect.width()) / to_rect.width(), static_cast<float>(from_rect.height()) / to_rect.height()); - view_shadow_->shadow()->layer()->SetTransform(transform); + shadow_->GetLayer()->SetTransform(transform); - auto settings = contents_view->CreateTransitionAnimationSettings( - view_shadow_->shadow()->layer()); - view_shadow_->shadow()->layer()->SetTransform(gfx::Transform()); + auto settings = + contents_view->CreateTransitionAnimationSettings(shadow_->GetLayer()); + shadow_->GetLayer()->SetTransform(gfx::Transform()); } } }
diff --git a/ash/app_list/views/search_result_page_view.h b/ash/app_list/views/search_result_page_view.h index 82045bd5..16abd7df 100644 --- a/ash/app_list/views/search_result_page_view.h +++ b/ash/app_list/views/search_result_page_view.h
@@ -31,7 +31,7 @@ class SearchResultListView; class SearchResultTileItemListView; class SearchResultPageAnchoredDialog; -class ViewShadow; +class SystemShadow; // The search results page for the app list. class ASH_EXPORT SearchResultPageView @@ -244,7 +244,7 @@ SearchResultsState current_search_results_state_ = SearchResultsState::kClosed; - std::unique_ptr<ViewShadow> view_shadow_; + std::unique_ptr<SystemShadow> shadow_; // The controller that manages dialogs modal to the search results page. std::unique_ptr<SearchResultPageDialogController> dialog_controller_;
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd index 084a342..458c153 100644 --- a/ash/ash_strings.grd +++ b/ash/ash_strings.grd
@@ -2097,13 +2097,25 @@ ''' - ''' </message> <!-- Status tray channel indicator strings --> - <message name="IDS_ASH_STATUS_TRAY_CHANNEL_BETA" desc="The string used to indicate that this device is on the beta release track"> + <message name="IDS_ASH_STATUS_TRAY_REPORT_FEEDBACK" desc="The string used for the tooltip and speakable name of the 'report feedback' button"> + Report feedback + </message> + <message name="IDS_ASH_STATUS_TRAY_CHANNEL_BETA" desc="The string used to show the name of beta release track, by itself"> + Beta + </message> + <message name="IDS_ASH_STATUS_TRAY_CHANNEL_DEV" desc="The string used to show the name of dev release track, by itself"> + Dev + </message> + <message name="IDS_ASH_STATUS_TRAY_CHANNEL_CANARY" desc="The string used to show the name of canary release track, by itself"> + Canary + </message> + <message name="IDS_ASH_STATUS_TRAY_CHANNEL_BETA_CHANNEL" desc="The string used to indicate that this device is on the beta release track"> Beta Channel </message> - <message name="IDS_ASH_STATUS_TRAY_CHANNEL_DEV" desc="The string used to indicate that this device is on the development release track"> + <message name="IDS_ASH_STATUS_TRAY_CHANNEL_DEV_CHANNEL" desc="The string used to indicate that this device is on the development release track"> Dev Channel </message> - <message name="IDS_ASH_STATUS_TRAY_CHANNEL_CANARY" desc="The string used to indicate that this device is on the canary release track"> + <message name="IDS_ASH_STATUS_TRAY_CHANNEL_CANARY_CHANNEL" desc="The string used to indicate that this device is on the canary release track"> Canary Channel </message> <!-- Status Tray Network strings --> @@ -3856,6 +3868,17 @@ An application is using your microphone </message> + <!-- For privacy indicators notification --> + <message name="IDS_PRIVACY_NOTIFICATION_TITLE_CAMERA_AND_MIC" desc="Title for a notification shown when an app is using the camera and the microphone."> + Camera and microphone in use + </message> + <message name="IDS_PRIVACY_NOTIFICATION_TITLE_CAMERA" desc="Title for a notification shown when an app is using the camera."> + Camera in use + </message> + <message name="IDS_PRIVACY_NOTIFICATION_TITLE_MIC" desc="Title for a notification shown when an app is using the microphone."> + Microphone in use + </message> + <!-- Strings for microphone mute switch notification --> <message name="IDS_MICROPHONE_MUTED_NOTIFICATION_TITLE" desc="Title for a notification shown to the users when an app tries to use the microphone while the microphone is muted.i Similar to IDS_MICROPHONE_MUTED_NOTIFICATION_TITLE_WITH_APP_NAME, except this message contains a generic app name string. Used when the name of the app that's using the microphone cannot be determined."> An app wants to use the microphone
diff --git a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_CHANNEL_BETA.png.sha1 b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_CHANNEL_BETA.png.sha1 index 900cb87..e9fb273 100644 --- a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_CHANNEL_BETA.png.sha1 +++ b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_CHANNEL_BETA.png.sha1
@@ -1 +1 @@ -a23e8925d97be40954790401e84089e09af5a456 \ No newline at end of file +9089cfd7cee8fb5053295c5639a4a9e99055d090 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_CHANNEL_BETA_CHANNEL.png.sha1 b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_CHANNEL_BETA_CHANNEL.png.sha1 new file mode 100644 index 0000000..e9fb273 --- /dev/null +++ b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_CHANNEL_BETA_CHANNEL.png.sha1
@@ -0,0 +1 @@ +9089cfd7cee8fb5053295c5639a4a9e99055d090 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_CHANNEL_CANARY.png.sha1 b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_CHANNEL_CANARY.png.sha1 index 29eb38a..353ac92 100644 --- a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_CHANNEL_CANARY.png.sha1 +++ b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_CHANNEL_CANARY.png.sha1
@@ -1 +1 @@ -11b35d936ec8e0b18154281d9cf2392ad822bf62 \ No newline at end of file +8041c4627127d19acb3ba3a34b59a8bd4ebd10ce \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_CHANNEL_CANARY_CHANNEL.png.sha1 b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_CHANNEL_CANARY_CHANNEL.png.sha1 new file mode 100644 index 0000000..353ac92 --- /dev/null +++ b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_CHANNEL_CANARY_CHANNEL.png.sha1
@@ -0,0 +1 @@ +8041c4627127d19acb3ba3a34b59a8bd4ebd10ce \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_CHANNEL_DEV.png.sha1 b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_CHANNEL_DEV.png.sha1 index a4516f6..48644be0d 100644 --- a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_CHANNEL_DEV.png.sha1 +++ b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_CHANNEL_DEV.png.sha1
@@ -1 +1 @@ -b7a6ff57d02323da11175ecca7c8473ceed32487 \ No newline at end of file +68a5f4e9505763877bfdd169cdcee7a27ccb7913 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_CHANNEL_DEV_CHANNEL.png.sha1 b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_CHANNEL_DEV_CHANNEL.png.sha1 new file mode 100644 index 0000000..48644be0d --- /dev/null +++ b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_CHANNEL_DEV_CHANNEL.png.sha1
@@ -0,0 +1 @@ +68a5f4e9505763877bfdd169cdcee7a27ccb7913 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_REPORT_FEEDBACK.png.sha1 b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_REPORT_FEEDBACK.png.sha1 new file mode 100644 index 0000000..5d1e81e --- /dev/null +++ b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_REPORT_FEEDBACK.png.sha1
@@ -0,0 +1 @@ +54c61a6a20b846a2270c4bee736c419afb70697c \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_PRIVACY_NOTIFICATION_TITLE_CAMERA.png.sha1 b/ash/ash_strings_grd/IDS_PRIVACY_NOTIFICATION_TITLE_CAMERA.png.sha1 new file mode 100644 index 0000000..ae7e3c64 --- /dev/null +++ b/ash/ash_strings_grd/IDS_PRIVACY_NOTIFICATION_TITLE_CAMERA.png.sha1
@@ -0,0 +1 @@ +77edccf6a440d3b8cadbc2ec9646f65aa09a60c1 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_PRIVACY_NOTIFICATION_TITLE_CAMERA_AND_MIC.png.sha1 b/ash/ash_strings_grd/IDS_PRIVACY_NOTIFICATION_TITLE_CAMERA_AND_MIC.png.sha1 new file mode 100644 index 0000000..e08a31d0 --- /dev/null +++ b/ash/ash_strings_grd/IDS_PRIVACY_NOTIFICATION_TITLE_CAMERA_AND_MIC.png.sha1
@@ -0,0 +1 @@ +3dc59ae30e045f280ba2ce319cee0fd90fd2eedf \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_PRIVACY_NOTIFICATION_TITLE_MIC.png.sha1 b/ash/ash_strings_grd/IDS_PRIVACY_NOTIFICATION_TITLE_MIC.png.sha1 new file mode 100644 index 0000000..2d29746e --- /dev/null +++ b/ash/ash_strings_grd/IDS_PRIVACY_NOTIFICATION_TITLE_MIC.png.sha1
@@ -0,0 +1 @@ +b6e5979c26ba5d0f5f8bb7168c00018b890a80f1 \ No newline at end of file
diff --git a/ash/bubble/bubble_constants.h b/ash/bubble/bubble_constants.h index fef67e21..d81c1d68 100644 --- a/ash/bubble/bubble_constants.h +++ b/ash/bubble/bubble_constants.h
@@ -5,6 +5,8 @@ #ifndef ASH_BUBBLE_BUBBLE_CONSTANTS_H_ #define ASH_BUBBLE_BUBBLE_CONSTANTS_H_ +#include "ash/style/system_shadow.h" + namespace ash { // The corner radius of a bubble, like the system tray bubble or the @@ -16,7 +18,8 @@ constexpr int kBubbleMenuPadding = 8; // The elevation used for system tray bubble. -constexpr int kBubbleShadowElevation = 12; +constexpr SystemShadow::Type kBubbleShadowType = + SystemShadow::Type::kElevation12; } // namespace ash
diff --git a/ash/capture_mode/capture_mode_bar_view.cc b/ash/capture_mode/capture_mode_bar_view.cc index e74800b..98f1b959 100644 --- a/ash/capture_mode/capture_mode_bar_view.cc +++ b/ash/capture_mode/capture_mode_bar_view.cc
@@ -73,9 +73,9 @@ base::BindRepeating(&CaptureModeBarView::OnCloseButtonPressed, base::Unretained(this)), kCaptureModeCloseIcon))), - shadow_(this, - SystemShadow::GetElevationFromType( - SystemShadow::Type::kElevation12)) { + shadow_(SystemShadow::CreateShadowOnNinePatchLayerForView( + this, + SystemShadow::Type::kElevation12)) { SetPaintToLayer(); auto* color_provider = AshColorProvider::Get(); SkColor background_color = color_provider->GetBaseLayerColor( @@ -119,8 +119,7 @@ kBorderRadius, views::HighlightBorder::Type::kHighlightBorder2, /*use_light_colors=*/false)); } - shadow_.shadow()->SetShadowStyle(gfx::ShadowStyle::kChromeOSSystemUI); - shadow_.SetRoundedCornerRadius(kBorderRadius); + shadow_->SetRoundedCornerRadius(kBorderRadius); } CaptureModeBarView::~CaptureModeBarView() = default;
diff --git a/ash/capture_mode/capture_mode_bar_view.h b/ash/capture_mode/capture_mode_bar_view.h index 042c332..5ef066e 100644 --- a/ash/capture_mode/capture_mode_bar_view.h +++ b/ash/capture_mode/capture_mode_bar_view.h
@@ -7,7 +7,6 @@ #include "ash/ash_export.h" #include "ash/capture_mode/capture_mode_types.h" -#include "ash/public/cpp/view_shadow.h" #include "ui/base/metadata/metadata_header_macros.h" #include "ui/views/view.h" @@ -21,6 +20,7 @@ class CaptureModeSourceView; class CaptureModeToggleButton; class CaptureModeTypeView; +class SystemShadow; // A view that acts as the content view of the capture mode bar widget. // It has a set of buttons to toggle between image and video capture, and @@ -86,7 +86,7 @@ views::Separator* separator_2_; CaptureModeToggleButton* settings_button_; CaptureModeButton* close_button_; - ViewShadow shadow_; + std::unique_ptr<SystemShadow> shadow_; }; } // namespace ash
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc index 1e0d94b..5a277df3 100644 --- a/ash/constants/ash_features.cc +++ b/ash/constants/ash_features.cc
@@ -344,6 +344,10 @@ const base::Feature kConsumerAutoUpdateToggleAllowed{ "ConsumerAutoUpdateToggleAllowed", base::FEATURE_DISABLED_BY_DEFAULT}; +// Enable or disable the changes of WMP features for CrosNext project. +const base::Feature kCrosNextWMP{"CrosNextWMP", + base::FEATURE_DISABLED_BY_DEFAULT}; + // If enabled, replaces the `DeskMiniView` legacy desk close button and behavior // with a button to close desk and windows and a button to combine desks (the // legacy behavior). @@ -1809,6 +1813,10 @@ return base::FeatureList::IsEnabled(kConsumerAutoUpdateToggleAllowed); } +bool IsCrosNextWMPEnabled() { + return base::FeatureList::IsEnabled(kCrosNextWMP); +} + bool IsCryptohomeRecoveryFlowEnabled() { return base::FeatureList::IsEnabled(kCryptohomeRecoveryFlow); }
diff --git a/ash/constants/ash_features.h b/ash/constants/ash_features.h index 80c8575..ac72ac95 100644 --- a/ash/constants/ash_features.h +++ b/ash/constants/ash_features.h
@@ -153,6 +153,8 @@ COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kCrosLanguageSettingsUpdateJapanese; COMPONENT_EXPORT(ASH_CONSTANTS) +extern const base::Feature kCrosNextWMP; +COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kCrostiniBullseyeUpgrade; COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kDesksTemplates; @@ -689,6 +691,7 @@ bool IsClipboardHistoryNudgeSessionResetEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsClipboardHistoryReorderEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsConsumerAutoUpdateToggleAllowed(); +COMPONENT_EXPORT(ASH_CONSTANTS) bool IsCrosNextWMPEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsDesksCloseAllEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsCryptohomeRecoveryFlowEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsCryptohomeRecoveryFlowUIEnabled();
diff --git a/ash/constants/notifier_catalogs.h b/ash/constants/notifier_catalogs.h index 5951dfa..9afa184 100644 --- a/ash/constants/notifier_catalogs.h +++ b/ash/constants/notifier_catalogs.h
@@ -158,7 +158,8 @@ kLowPowerAdapter = 144, kTPMAutoUpdatePlanned = 145, kTPMAutoUpdateOnReboot = 146, - kMaxValue = kTPMAutoUpdateOnReboot + kPrivacyIndicators = 147, + kMaxValue = kPrivacyIndicators }; // A living catalog that registers toasts.
diff --git a/ash/display/refresh_rate_throttle_controller_unittest.cc b/ash/display/refresh_rate_throttle_controller_unittest.cc new file mode 100644 index 0000000..46f43c4 --- /dev/null +++ b/ash/display/refresh_rate_throttle_controller_unittest.cc
@@ -0,0 +1,280 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/display/refresh_rate_throttle_controller.h" + +#include <memory> +#include <vector> + +#include "ash/shell.h" +#include "ash/system/power/power_status.h" +#include "ash/test/ash_test_base.h" +#include "chromeos/dbus/power_manager/power_supply_properties.pb.h" +#include "ui/display/fake/fake_display_snapshot.h" +#include "ui/display/manager/display_configurator.h" +#include "ui/display/manager/display_manager.h" +#include "ui/display/manager/test/action_logger.h" +#include "ui/display/manager/test/action_logger_util.h" +#include "ui/display/manager/test/test_native_display_delegate.h" +#include "ui/display/types/display_mode.h" +#include "ui/display/types/display_snapshot.h" +#include "ui/display/types/native_display_delegate.h" + +namespace ash { +namespace { + +using display::DisplayMode; +using display::DisplaySnapshot; +using display::FakeDisplaySnapshot; +using display::NativeDisplayDelegate; +using display::test::ActionLogger; +using display::test::TestNativeDisplayDelegate; +using power_manager::PowerSupplyProperties; + +std::unique_ptr<DisplayMode> MakeDisplayMode(int width, + int height, + bool is_interlaced, + float refresh_rate) { + return std::make_unique<DisplayMode>(gfx::Size(width, height), is_interlaced, + refresh_rate); +} + +std::unique_ptr<DisplaySnapshot> BuildDualRefreshPanelSnapshot( + int64_t id, + display::DisplayConnectionType type) { + return FakeDisplaySnapshot::Builder() + .SetId(id) + .SetType(type) + .SetNativeMode(MakeDisplayMode(1920, 1200, false, 120.f)) + .AddMode(MakeDisplayMode(1920, 1200, false, 60.f)) + .SetCurrentMode(MakeDisplayMode(1920, 1200, false, 120.f)) + .Build(); +} + +PowerSupplyProperties BuildFakePowerSupplyProperties( + PowerSupplyProperties::ExternalPower charger_state, + double battery_percent) { + PowerSupplyProperties fake_power; + fake_power.set_external_power(charger_state); + fake_power.set_battery_percent(battery_percent); + return fake_power; +} + +class RefreshRateThrottleControllerTest : public AshTestBase { + public: + RefreshRateThrottleControllerTest() = default; + RefreshRateThrottleControllerTest(const RefreshRateThrottleControllerTest&) = + delete; + RefreshRateThrottleControllerTest& operator=( + const RefreshRateThrottleControllerTest&) = delete; + ~RefreshRateThrottleControllerTest() override = default; + + void SetUp() override { + AshTestBase::SetUp(); + + logger_ = std::make_unique<ActionLogger>(); + native_display_delegate_ = new TestNativeDisplayDelegate(logger_.get()); + display_manager()->configurator()->SetDelegateForTesting( + std::unique_ptr<NativeDisplayDelegate>(native_display_delegate_)); + controller_ = std::make_unique<RefreshRateThrottleController>( + Shell::Get()->display_configurator(), PowerStatus::Get()); + } + + void TearDown() override { + controller_.reset(); + AshTestBase::TearDown(); + } + + protected: + void SetUpDisplays( + const std::vector<std::unique_ptr<DisplaySnapshot>>& snapshots) { + std::vector<DisplaySnapshot*> outputs; + for (const std::unique_ptr<DisplaySnapshot>& snapshot : snapshots) + outputs.push_back(snapshot.get()); + + display::DisplayConfigurator::TestApi test_api( + display_manager()->configurator()); + native_display_delegate_->set_outputs(outputs); + display_manager()->configurator()->OnConfigurationChanged(); + display_manager()->configurator()->ForceInitialConfigure(); + ASSERT_TRUE(test_api.TriggerConfigureTimeout()); + } + + const DisplaySnapshot* GetDisplaySnapshot(int64_t display_id) { + for (const DisplaySnapshot* snapshot : + display_manager()->configurator()->cached_displays()) { + if (snapshot->display_id() == display_id) + return snapshot; + } + return nullptr; + } + + std::unique_ptr<ActionLogger> logger_; + std::unique_ptr<RefreshRateThrottleController> controller_; + // Owned by DisplayConfigurator. + TestNativeDisplayDelegate* native_display_delegate_; +}; + +TEST_F(RefreshRateThrottleControllerTest, ShouldNotThrottleOnAC) { + constexpr int64_t kDisplayId = 12345; + std::vector<std::unique_ptr<DisplaySnapshot>> snapshots; + snapshots.push_back(BuildDualRefreshPanelSnapshot( + kDisplayId, display::DISPLAY_CONNECTION_TYPE_INTERNAL)); + SetUpDisplays(snapshots); + + // Expect the initial state to be 120 Hz. + { + const DisplaySnapshot* snapshot = GetDisplaySnapshot(kDisplayId); + ASSERT_NE(snapshot, nullptr); + ASSERT_NE(snapshot->current_mode(), nullptr); + EXPECT_EQ(snapshot->current_mode()->refresh_rate(), 120.f); + } + + // Set power state to indicate the device is on AC. + PowerStatus::Get()->SetProtoForTesting( + BuildFakePowerSupplyProperties(PowerSupplyProperties::AC, 100.0)); + controller_->OnPowerStatusChanged(); + + // Expect the new state to be unchanged. + { + const DisplaySnapshot* snapshot = GetDisplaySnapshot(kDisplayId); + ASSERT_NE(snapshot, nullptr); + ASSERT_NE(snapshot->current_mode(), nullptr); + EXPECT_EQ(snapshot->current_mode()->refresh_rate(), 120.f); + } +} + +TEST_F(RefreshRateThrottleControllerTest, ShouldThrottleOnBattery) { + constexpr int64_t kDisplayId = 12345; + std::vector<std::unique_ptr<DisplaySnapshot>> snapshots; + snapshots.push_back(BuildDualRefreshPanelSnapshot( + kDisplayId, display::DISPLAY_CONNECTION_TYPE_INTERNAL)); + SetUpDisplays(snapshots); + + // Expect the initial state to be 120 Hz. + { + const DisplaySnapshot* snapshot = GetDisplaySnapshot(kDisplayId); + ASSERT_NE(snapshot, nullptr); + ASSERT_NE(snapshot->current_mode(), nullptr); + EXPECT_EQ(snapshot->current_mode()->refresh_rate(), 120.f); + } + + // Set power state to indicate the device is on battery. + PowerStatus::Get()->SetProtoForTesting(BuildFakePowerSupplyProperties( + PowerSupplyProperties::DISCONNECTED, 100.0)); + controller_->OnPowerStatusChanged(); + + // Expect the new state to be 60 Hz. + { + const DisplaySnapshot* snapshot = GetDisplaySnapshot(kDisplayId); + ASSERT_NE(snapshot, nullptr); + ASSERT_NE(snapshot->current_mode(), nullptr); + EXPECT_EQ(snapshot->current_mode()->refresh_rate(), 60.f); + } +} + +TEST_F(RefreshRateThrottleControllerTest, ShouldNotAffectExternalDisplay) { + constexpr int64_t kDisplayId = 12345; + std::vector<std::unique_ptr<DisplaySnapshot>> snapshots; + snapshots.push_back(BuildDualRefreshPanelSnapshot( + kDisplayId, display::DISPLAY_CONNECTION_TYPE_HDMI)); + SetUpDisplays(snapshots); + + // Expect the initial state to be 120 Hz. + { + const DisplaySnapshot* snapshot = GetDisplaySnapshot(kDisplayId); + ASSERT_NE(snapshot, nullptr); + ASSERT_NE(snapshot->current_mode(), nullptr); + EXPECT_EQ(snapshot->current_mode()->refresh_rate(), 120.f); + } + + // Set power state to indicate the device is on battery. + PowerStatus::Get()->SetProtoForTesting(BuildFakePowerSupplyProperties( + PowerSupplyProperties::DISCONNECTED, 100.0)); + controller_->OnPowerStatusChanged(); + + // Expect the state to be unchanged. + { + const DisplaySnapshot* snapshot = GetDisplaySnapshot(kDisplayId); + ASSERT_NE(snapshot, nullptr); + ASSERT_NE(snapshot->current_mode(), nullptr); + EXPECT_EQ(snapshot->current_mode()->refresh_rate(), 120.f); + } +} + +TEST_F(RefreshRateThrottleControllerTest, ShouldThrottleOnUSBCharger) { + constexpr int64_t kDisplayId = 12345; + std::vector<std::unique_ptr<DisplaySnapshot>> snapshots; + snapshots.push_back(BuildDualRefreshPanelSnapshot( + kDisplayId, display::DISPLAY_CONNECTION_TYPE_INTERNAL)); + SetUpDisplays(snapshots); + + // Expect the initial state to be 120 Hz. + { + const DisplaySnapshot* snapshot = GetDisplaySnapshot(kDisplayId); + ASSERT_NE(snapshot, nullptr); + ASSERT_NE(snapshot->current_mode(), nullptr); + EXPECT_EQ(snapshot->current_mode()->refresh_rate(), 120.f); + } + + // Set power state to indicate the device is on a low powered charger. + PowerStatus::Get()->SetProtoForTesting( + BuildFakePowerSupplyProperties(PowerSupplyProperties::USB, 100.0)); + controller_->OnPowerStatusChanged(); + + // Expect the new state to be 60 Hz. + { + const DisplaySnapshot* snapshot = GetDisplaySnapshot(kDisplayId); + ASSERT_NE(snapshot, nullptr); + ASSERT_NE(snapshot->current_mode(), nullptr); + EXPECT_EQ(snapshot->current_mode()->refresh_rate(), 60.f); + } +} + +TEST_F(RefreshRateThrottleControllerTest, ShouldThrottleOnLowBattery) { + constexpr int64_t kDisplayId = 12345; + std::vector<std::unique_ptr<DisplaySnapshot>> snapshots; + snapshots.push_back(BuildDualRefreshPanelSnapshot( + kDisplayId, display::DISPLAY_CONNECTION_TYPE_INTERNAL)); + SetUpDisplays(snapshots); + + // Expect the initial state to be 120 Hz. + { + const DisplaySnapshot* snapshot = GetDisplaySnapshot(kDisplayId); + ASSERT_NE(snapshot, nullptr); + ASSERT_NE(snapshot->current_mode(), nullptr); + EXPECT_EQ(snapshot->current_mode()->refresh_rate(), 120.f); + } + + // Set power state to indicate the device is on a high-powered charger, + // but the battery is critically low. + PowerStatus::Get()->SetProtoForTesting( + BuildFakePowerSupplyProperties(PowerSupplyProperties::AC, 4.0)); + controller_->OnPowerStatusChanged(); + + // Expect the new state to be 60 Hz. + { + const DisplaySnapshot* snapshot = GetDisplaySnapshot(kDisplayId); + ASSERT_NE(snapshot, nullptr); + ASSERT_NE(snapshot->current_mode(), nullptr); + EXPECT_EQ(snapshot->current_mode()->refresh_rate(), 60.f); + } + + // Set the power state to indicate the device has charged above + // critical level. + PowerStatus::Get()->SetProtoForTesting( + BuildFakePowerSupplyProperties(PowerSupplyProperties::AC, 6.0)); + controller_->OnPowerStatusChanged(); + + // Expect the new state to be 120 Hz. + { + const DisplaySnapshot* snapshot = GetDisplaySnapshot(kDisplayId); + ASSERT_NE(snapshot, nullptr); + ASSERT_NE(snapshot->current_mode(), nullptr); + EXPECT_EQ(snapshot->current_mode()->refresh_rate(), 120.f); + } +} + +} // namespace +} // namespace ash \ No newline at end of file
diff --git a/ash/public/cpp/system_tray_client.h b/ash/public/cpp/system_tray_client.h index d14a4bd..646b681 100644 --- a/ash/public/cpp/system_tray_client.h +++ b/ash/public/cpp/system_tray_client.h
@@ -159,6 +159,14 @@ bool& opened_pwa, GURL& finalized_event_url) = 0; + // Shown when the device is on a non-stable release track and the user clicks + // the channel/version button from quick settings. + virtual void ShowChannelInfoAdditionalDetails() = 0; + + // Shown when the device is on a non-stable release track and the user clicks + // the "send feedback" button. + virtual void ShowChannelInfoGiveFeedback() = 0; + protected: SystemTrayClient() {} };
diff --git a/ash/public/cpp/test/test_system_tray_client.cc b/ash/public/cpp/test/test_system_tray_client.cc index a7c1532..49284e6 100644 --- a/ash/public/cpp/test/test_system_tray_client.cc +++ b/ash/public/cpp/test/test_system_tray_client.cc
@@ -120,4 +120,8 @@ bool& opened_pwa, GURL& final_event_url) {} +void TestSystemTrayClient::ShowChannelInfoAdditionalDetails() {} + +void TestSystemTrayClient::ShowChannelInfoGiveFeedback() {} + } // namespace ash
diff --git a/ash/public/cpp/test/test_system_tray_client.h b/ash/public/cpp/test/test_system_tray_client.h index 4db1910..4eb3398 100644 --- a/ash/public/cpp/test/test_system_tray_client.h +++ b/ash/public/cpp/test/test_system_tray_client.h
@@ -66,6 +66,8 @@ const base::Time& date, bool& opened_pwa, GURL& final_event_url) override; + void ShowChannelInfoAdditionalDetails() override; + void ShowChannelInfoGiveFeedback() override; int show_bluetooth_settings_count() const { return show_bluetooth_settings_count_;
diff --git a/ash/resources/vector_icons/BUILD.gn b/ash/resources/vector_icons/BUILD.gn index 4b72818..2cb1779f 100644 --- a/ash/resources/vector_icons/BUILD.gn +++ b/ash/resources/vector_icons/BUILD.gn
@@ -250,6 +250,7 @@ "reorder_nudge_dark_tablet.icon", "reorder_nudge_light_clamshell.icon", "reorder_nudge_light_tablet.icon", + "request_feedback.icon", "resume.icon", "save_desk_as_template.icon", "save_desk_for_later.icon",
diff --git a/ash/resources/vector_icons/request_feedback.icon b/ash/resources/vector_icons/request_feedback.icon new file mode 100644 index 0000000..f4714a5 --- /dev/null +++ b/ash/resources/vector_icons/request_feedback.icon
@@ -0,0 +1,35 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +CANVAS_DIMENSIONS, 20, +MOVE_TO, 9, 5, +H_LINE_TO, 11, +V_LINE_TO, 9, +H_LINE_TO, 9, +V_LINE_TO, 5, +CLOSE, +NEW_PATH, +MOVE_TO, 9, 10, +H_LINE_TO, 11, +V_LINE_TO, 12, +H_LINE_TO, 9, +V_LINE_TO, 10, +CLOSE, +NEW_PATH, +MOVE_TO, 3.67f, 2, +H_LINE_TO, 16, +CUBIC_TO, 16.92f, 2, 18, 2.58f, 18, 3.5f, +V_LINE_TO, 13.5f, +CUBIC_TO, 18, 14.42f, 16.92f, 15, 16, 15, +H_LINE_TO, 5, +LINE_TO, 2, 17.5f, +LINE_TO, 2.01f, 3.67f, +CUBIC_TO, 2.01f, 2.75f, 2.75f, 2, 3.67f, 2, +CLOSE, +MOVE_TO, 4, 13, +H_LINE_TO, 16, +V_LINE_TO, 4, +H_LINE_TO, 4, +V_LINE_TO, 13, +CLOSE
diff --git a/ash/shell_delegate.h b/ash/shell_delegate.h index 5b29bceb..e072f1a 100644 --- a/ash/shell_delegate.h +++ b/ash/shell_delegate.h
@@ -144,6 +144,9 @@ // Retrieves the release track on which the device resides. virtual version_info::Channel GetChannel() = 0; + + // Retrieves the official Chrome version string e.g. 105.0.5178.0. + virtual std::string GetVersionString() = 0; }; } // namespace ash
diff --git a/ash/style/ash_color_provider_unittest.cc b/ash/style/ash_color_provider_unittest.cc index 2e3252c..18052b9 100644 --- a/ash/style/ash_color_provider_unittest.cc +++ b/ash/style/ash_color_provider_unittest.cc
@@ -216,6 +216,279 @@ {ColorMode::kLight, ColorProvider::ControlsLayerType::kBorderColor3, SkColorSetARGB(0x0F, 0x0, 0x0, 0x0)}})); +class AshColorProviderContentTest + : public AshColorProviderBase<ColorProvider::ContentLayerType> {}; + +TEST_P(AshColorProviderContentTest, Colors) { + const auto& test_case = GetParam(); + bool dark = test_case.color_mode == ColorMode::kDark; + DarkLightModeController::Get()->SetDarkModeEnabledForTest(dark); + SkColor actual_color = color_provider_->GetContentLayerColor(test_case.type); + EXPECT_EQ(test_case.expected_color, actual_color) + << "Colors do not match. Expected " << test_case + << " Actual: " << ColorToString(actual_color); +} + +INSTANTIATE_TEST_SUITE_P( + AshColorProviderTests, + AshColorProviderContentTest, + testing::ValuesIn<ColorsTestCase<ColorProvider::ContentLayerType>>( + {// Light colors + {ColorMode::kLight, ColorProvider::ContentLayerType::kScrollBarColor, + SkColorSetRGB(0x5F, 0x63, 0x68)}, + {ColorMode::kLight, ColorProvider::ContentLayerType::kSeparatorColor, + SkColorSetARGB(0x24, 0x0, 0x0, 0x0)}, + + {ColorMode::kLight, ColorProvider::ContentLayerType::kTextColorPrimary, + SkColorSetRGB(0x20, 0x21, 0x24)}, + {ColorMode::kLight, + ColorProvider::ContentLayerType::kTextColorSecondary, + SkColorSetRGB(0x5F, 0x63, 0x68)}, + {ColorMode::kLight, ColorProvider::ContentLayerType::kTextColorAlert, + SkColorSetRGB(0xD9, 0x30, 0x25)}, + {ColorMode::kLight, ColorProvider::ContentLayerType::kTextColorWarning, + SkColorSetRGB(0xE3, 0x74, 0x0)}, + {ColorMode::kLight, + ColorProvider::ContentLayerType::kTextColorPositive, + SkColorSetRGB(0x1E, 0x8E, 0x3E)}, + {ColorMode::kLight, ColorProvider::ContentLayerType::kTextColorURL, + SkColorSetRGB(0x1A, 0x73, 0xE8)}, + + {ColorMode::kLight, ColorProvider::ContentLayerType::kIconColorPrimary, + SkColorSetRGB(0x20, 0x21, 0x24)}, + {ColorMode::kLight, + ColorProvider::ContentLayerType::kIconColorSecondary, + SkColorSetRGB(0x9A, 0xA0, 0xA6)}, + {ColorMode::kLight, ColorProvider::ContentLayerType::kIconColorAlert, + SkColorSetRGB(0xD9, 0x30, 0x25)}, + {ColorMode::kLight, ColorProvider::ContentLayerType::kIconColorWarning, + SkColorSetRGB(0xE3, 0x74, 0x0)}, + {ColorMode::kLight, + ColorProvider::ContentLayerType::kIconColorPositive, + SkColorSetRGB(0x1E, 0x8E, 0x3E)}, + {ColorMode::kLight, + ColorProvider::ContentLayerType::kIconColorProminent, + SkColorSetRGB(0x1A, 0x73, 0xE8)}, + + {ColorMode::kLight, + ColorProvider::ContentLayerType::kIconColorSecondaryBackground, + SkColorSetRGB(0x3C, 0x40, 0x43)}, + + {ColorMode::kLight, ColorProvider::ContentLayerType::kButtonLabelColor, + SkColorSetRGB(0x20, 0x21, 0x24)}, + {ColorMode::kLight, + ColorProvider::ContentLayerType::kButtonLabelColorPrimary, + SkColorSetRGB(0xE8, 0xEA, 0xED)}, + + {ColorMode::kLight, + ColorProvider::ContentLayerType::kButtonLabelColorBlue, + SkColorSetRGB(0x1A, 0x73, 0xE8)}, + + {ColorMode::kLight, ColorProvider::ContentLayerType::kButtonIconColor, + SkColorSetRGB(0x20, 0x21, 0x24)}, + {ColorMode::kLight, + ColorProvider::ContentLayerType::kButtonIconColorPrimary, + SkColorSetRGB(0xE8, 0xEA, 0xED)}, + + {ColorMode::kLight, + ColorProvider::ContentLayerType::kAppStateIndicatorColor, + SkColorSetRGB(0x20, 0x21, 0x24)}, + {ColorMode::kLight, + ColorProvider::ContentLayerType::kAppStateIndicatorColorInactive, + SkColorSetARGB(0x61, 0x20, 0x21, 0x24)}, + + {ColorMode::kLight, ColorProvider::ContentLayerType::kShelfHandleColor, + SkColorSetARGB(0x24, 0x0, 0x0, 0x0)}, + + {ColorMode::kLight, + ColorProvider::ContentLayerType::kSliderColorActive, + SkColorSetRGB(0x1A, 0x73, 0xE8)}, + {ColorMode::kLight, + ColorProvider::ContentLayerType::kSliderColorInactive, + SkColorSetRGB(0x5F, 0x63, 0x68)}, + + {ColorMode::kLight, ColorProvider::ContentLayerType::kRadioColorActive, + SkColorSetRGB(0x1A, 0x73, 0xE8)}, + {ColorMode::kLight, + ColorProvider::ContentLayerType::kRadioColorInactive, + SkColorSetRGB(0x5F, 0x63, 0x68)}, + + {ColorMode::kLight, + ColorProvider::ContentLayerType::kSwitchKnobColorActive, + SkColorSetRGB(0x1A, 0x73, 0xE8)}, + {ColorMode::kLight, + ColorProvider::ContentLayerType::kSwitchKnobColorInactive, + SkColorSetRGB(0xFF, 0xFF, 0xFF)}, + {ColorMode::kLight, + ColorProvider::ContentLayerType::kSwitchTrackColorActive, + SkColorSetARGB(0x4D, 0x1A, 0x73, 0xE8)}, + {ColorMode::kLight, + ColorProvider::ContentLayerType::kSwitchTrackColorInactive, + SkColorSetARGB(0x4D, 0x5F, 0x63, 0x68)}, + + {ColorMode::kLight, ColorProvider::ContentLayerType::kCurrentDeskColor, + SkColorSetRGB(0x0, 0x0, 0x0)}, + + {ColorMode::kLight, + ColorProvider::ContentLayerType::kBatteryBadgeColor, + SkColorSetRGB(0xE8, 0xEA, 0xED)}, + + {ColorMode::kLight, + ColorProvider::ContentLayerType::kSwitchAccessInnerStrokeColor, + SkColorSetRGB(0x8A, 0xB4, 0xF8)}, + {ColorMode::kLight, + ColorProvider::ContentLayerType::kSwitchAccessOuterStrokeColor, + SkColorSetRGB(0x17, 0x4E, 0xA6)}, + + {ColorMode::kLight, + ColorProvider::ContentLayerType::kProgressBarColorForeground, + SkColorSetRGB(0x1A, 0x73, 0xE8)}, + {ColorMode::kLight, + ColorProvider::ContentLayerType::kProgressBarColorBackground, + SkColorSetARGB(0x4C, 0x1A, 0x73, 0xE8)}, + + {ColorMode::kLight, + ColorProvider::ContentLayerType::kHighlightColorHover, + SkColorSetARGB(0x14, 0x0, 0x0, 0x0)}, + + {ColorMode::kLight, + ColorProvider::ContentLayerType::kBatterySystemInfoBackgroundColor, + SkColorSetRGB(0x1E, 0x8E, 0x3E)}, + + {ColorMode::kLight, + ColorProvider::ContentLayerType::kBatterySystemInfoIconColor, + SkColorSetRGB(0xE8, 0xEA, 0xED)}, + + {ColorMode::kLight, + ColorProvider::ContentLayerType::kCaptureRegionColor, + SkColorSetARGB(0x4C, 0x1A, 0x73, 0xE8)}, + + // Dark colors + {ColorMode::kDark, ColorProvider::ContentLayerType::kScrollBarColor, + SkColorSetRGB(0xE8, 0xEA, 0xED)}, + {ColorMode::kDark, ColorProvider::ContentLayerType::kSeparatorColor, + SkColorSetARGB(0x24, 0xFF, 0xFF, 0xFF)}, + + {ColorMode::kDark, ColorProvider::ContentLayerType::kTextColorPrimary, + SkColorSetRGB(0xE8, 0xEA, 0xED)}, + {ColorMode::kDark, + ColorProvider::ContentLayerType::kTextColorSecondary, + SkColorSetRGB(0xBD, 0xC1, 0xC6)}, + {ColorMode::kDark, ColorProvider::ContentLayerType::kTextColorAlert, + SkColorSetRGB(0xF2, 0x8B, 0x82)}, + {ColorMode::kDark, ColorProvider::ContentLayerType::kTextColorWarning, + SkColorSetRGB(0xFD, 0xD6, 0x63)}, + {ColorMode::kDark, ColorProvider::ContentLayerType::kTextColorPositive, + SkColorSetRGB(0x81, 0xC9, 0x95)}, + {ColorMode::kDark, ColorProvider::ContentLayerType::kTextColorURL, + SkColorSetRGB(0x8A, 0xB4, 0xF8)}, + + {ColorMode::kDark, ColorProvider::ContentLayerType::kIconColorPrimary, + SkColorSetRGB(0xE8, 0xEA, 0xED)}, + {ColorMode::kDark, + ColorProvider::ContentLayerType::kIconColorSecondary, + SkColorSetRGB(0x9A, 0xA0, 0xA6)}, + {ColorMode::kDark, ColorProvider::ContentLayerType::kIconColorAlert, + SkColorSetRGB(0xF2, 0x8B, 0x82)}, + {ColorMode::kDark, ColorProvider::ContentLayerType::kIconColorWarning, + SkColorSetRGB(0xFD, 0xD6, 0x63)}, + {ColorMode::kDark, ColorProvider::ContentLayerType::kIconColorPositive, + SkColorSetRGB(0x81, 0xC9, 0x95)}, + {ColorMode::kDark, + ColorProvider::ContentLayerType::kIconColorProminent, + SkColorSetRGB(0x8A, 0xB4, 0xF8)}, + + {ColorMode::kDark, + ColorProvider::ContentLayerType::kIconColorSecondaryBackground, + SkColorSetRGB(0xF1, 0xF3, 0xF4)}, + + {ColorMode::kDark, ColorProvider::ContentLayerType::kButtonLabelColor, + SkColorSetRGB(0xE8, 0xEA, 0xED)}, + {ColorMode::kDark, + ColorProvider::ContentLayerType::kButtonLabelColorPrimary, + SkColorSetRGB(0x20, 0x21, 0x24)}, + + {ColorMode::kDark, + ColorProvider::ContentLayerType::kButtonLabelColorBlue, + SkColorSetRGB(0x8A, 0xB4, 0xF8)}, + + {ColorMode::kDark, ColorProvider::ContentLayerType::kButtonIconColor, + SkColorSetRGB(0xE8, 0xEA, 0xED)}, + {ColorMode::kDark, + ColorProvider::ContentLayerType::kButtonIconColorPrimary, + SkColorSetRGB(0x20, 0x21, 0x24)}, + + {ColorMode::kDark, + ColorProvider::ContentLayerType::kAppStateIndicatorColor, + SkColorSetRGB(0xE8, 0xEA, 0xED)}, + {ColorMode::kDark, + ColorProvider::ContentLayerType::kAppStateIndicatorColorInactive, + SkColorSetARGB(0x61, 0xE8, 0xEA, 0xED)}, + + {ColorMode::kDark, ColorProvider::ContentLayerType::kShelfHandleColor, + SkColorSetARGB(0x24, 0xFF, 0xFF, 0xFF)}, + + {ColorMode::kDark, ColorProvider::ContentLayerType::kSliderColorActive, + SkColorSetRGB(0x8A, 0xB4, 0xF8)}, + {ColorMode::kDark, + ColorProvider::ContentLayerType::kSliderColorInactive, + SkColorSetRGB(0xE8, 0xEA, 0xED)}, + + {ColorMode::kDark, ColorProvider::ContentLayerType::kRadioColorActive, + SkColorSetRGB(0x8A, 0xB4, 0xF8)}, + {ColorMode::kDark, + ColorProvider::ContentLayerType::kRadioColorInactive, + SkColorSetRGB(0xE8, 0xEA, 0xED)}, + + {ColorMode::kDark, + ColorProvider::ContentLayerType::kSwitchKnobColorActive, + SkColorSetRGB(0x8A, 0xB4, 0xF8)}, + {ColorMode::kDark, + ColorProvider::ContentLayerType::kSwitchKnobColorInactive, + SkColorSetRGB(0xBD, 0xC1, 0xC6)}, + {ColorMode::kDark, + ColorProvider::ContentLayerType::kSwitchTrackColorActive, + SkColorSetARGB(0x4D, 0x8A, 0xB4, 0xF8)}, + {ColorMode::kDark, + ColorProvider::ContentLayerType::kSwitchTrackColorInactive, + SkColorSetARGB(0x4D, 0xE8, 0xEA, 0xED)}, + + {ColorMode::kDark, ColorProvider::ContentLayerType::kCurrentDeskColor, + SkColorSetRGB(0xFF, 0xFF, 0xFF)}, + + {ColorMode::kDark, ColorProvider::ContentLayerType::kBatteryBadgeColor, + SkColorSetRGB(0x20, 0x21, 0x24)}, + + {ColorMode::kDark, + ColorProvider::ContentLayerType::kSwitchAccessInnerStrokeColor, + SkColorSetRGB(0x8A, 0xB4, 0xF8)}, + {ColorMode::kDark, + ColorProvider::ContentLayerType::kSwitchAccessOuterStrokeColor, + SkColorSetRGB(0x17, 0x4E, 0xA6)}, + + {ColorMode::kDark, + ColorProvider::ContentLayerType::kProgressBarColorForeground, + SkColorSetRGB(0x8A, 0xB4, 0xF8)}, + {ColorMode::kDark, + ColorProvider::ContentLayerType::kProgressBarColorBackground, + SkColorSetARGB(0x4C, 0x8A, 0xB4, 0xF8)}, + + {ColorMode::kDark, + ColorProvider::ContentLayerType::kHighlightColorHover, + SkColorSetARGB(0xD, 0xFF, 0xFF, 0xFF)}, + + {ColorMode::kDark, + ColorProvider::ContentLayerType::kBatterySystemInfoBackgroundColor, + SkColorSetRGB(0x81, 0xC9, 0x95)}, + + {ColorMode::kDark, + ColorProvider::ContentLayerType::kBatterySystemInfoIconColor, + SkColorSetRGB(0x20, 0x21, 0x24)}, + + {ColorMode::kDark, + ColorProvider::ContentLayerType::kCaptureRegionColor, + SkColorSetARGB(0x4C, 0x8A, 0xB4, 0xF8)}})); + } // namespace } // namespace ash
diff --git a/ash/style/system_shadow.cc b/ash/style/system_shadow.cc index 3458701d..5b5292f4 100644 --- a/ash/style/system_shadow.cc +++ b/ash/style/system_shadow.cc
@@ -1,48 +1,44 @@ -// Copyright 2021 The Chromium Authors. All rights reserved. +// Copyright 2022 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "ash/style/system_shadow.h" -#include "base/logging.h" -#include "base/notreached.h" -#include "ui/aura/window.h" -#include "ui/compositor/layer.h" -#include "ui/views/widget/widget.h" + +#include "ash/style/system_shadow_on_nine_patch_layer.h" +#include "base/memory/ptr_util.h" namespace ash { -// static -std::unique_ptr<SystemShadow> SystemShadow::CreateShadowForWidget( - views::Widget* widget, - Type shadow_type) { - DCHECK(widget); - return CreateShadowForWindow(widget->GetNativeWindow(), shadow_type); -} - -// static -std::unique_ptr<SystemShadow> SystemShadow::CreateShadowForWindow( - aura::Window* window, - Type shadow_type) { - DCHECK(window); - auto shadow = std::make_unique<SystemShadow>(shadow_type); - auto* shadow_layer = shadow->layer(); - auto* window_layer = window->layer(); - - // Add shadow layer to window layer and stack at the bottom. - window_layer->Add(shadow_layer); - window_layer->StackAtBottom(shadow_layer); - return shadow; -} - -SystemShadow::SystemShadow(Type type) : type_(type) { - // Note: Init function should be called before SetShadowStyle. - Init(GetElevationFromType(type_)); - // System shadow always use `kChromeOSSystemUI` as shadow style. - SetShadowStyle(gfx::ShadowStyle::kChromeOSSystemUI); -} - SystemShadow::~SystemShadow() = default; +// static +std::unique_ptr<SystemShadow> SystemShadow::CreateShadowOnNinePatchLayer( + Type shadow_type) { + int elevation = GetElevationFromType(shadow_type); + return base::WrapUnique(new SystemShadowOnNinePatchLayerImpl(elevation)); +} + +// static +std::unique_ptr<SystemShadow> SystemShadow::CreateShadowOnNinePatchLayerForView( + views::View* view, + Type shadow_type) { + DCHECK(view); + int elevation = GetElevationFromType(shadow_type); + return base::WrapUnique( + new SystemViewShadowOnNinePatchLayer(view, elevation)); +} + +// static +std::unique_ptr<SystemShadow> +SystemShadow::CreateShadowOnNinePatchLayerForWindow(aura::Window* window, + Type shadow_type) { + DCHECK(window); + int elevation = GetElevationFromType(shadow_type); + return base::WrapUnique( + new SystemWindowShadowOnNinePatchLayer(window, elevation)); +} + +// static int SystemShadow::GetElevationFromType(Type type) { switch (type) { case Type::kElevation4: @@ -58,12 +54,4 @@ } } -void SystemShadow::SetType(Type type) { - if (type_ == type) - return; - - type_ = type; - SetElevation(GetElevationFromType(type_)); -} - } // namespace ash
diff --git a/ash/style/system_shadow.h b/ash/style/system_shadow.h index 7eb76da4..6d62f7ab7 100644 --- a/ash/style/system_shadow.h +++ b/ash/style/system_shadow.h
@@ -6,20 +6,25 @@ #define ASH_STYLE_SYSTEM_SHADOW_H_ #include "ash/ash_export.h" -#include "ui/compositor_extra/shadow.h" - -namespace views { -class Widget; -} // namespace views +#include "ui/gfx/geometry/rect.h" namespace aura { class Window; } // namespace aura +namespace ui { +class Layer; +} // namespace ui + +namespace views { +class View; +} // namespace views + namespace ash { -// Shadow for Chrome OS System UI component. -class ASH_EXPORT SystemShadow : public ui::Shadow { +// SystemShadow is an interface to generate shadow with system shadow style for +// different types of UI surfaces. +class ASH_EXPORT SystemShadow { public: // Shadow types of system UI components. The shadows with different elevations // have different appearance. @@ -31,28 +36,65 @@ kElevation24, }; - explicit SystemShadow(Type type); - SystemShadow(const SystemShadow&) = delete; - SystemShadow& operator=(const SystemShadow&) = delete; - ~SystemShadow() override; + virtual ~SystemShadow(); - static std::unique_ptr<SystemShadow> CreateShadowForWidget( - views::Widget* widget, + // Create a system shadow based on `ui::Shadow` which paints shadow on a nine + // patch layer. This shadow can be used for any UI surfaces. Usually, when + // creating the shadow for a window, attach the shadow's layer at the bottom + // of the window's layer; when creating the shadow for a view, attach the + // shadow's layer at the bottom of the view's parent layer. The layer's + // content bounds should be manually updated. + static std::unique_ptr<SystemShadow> CreateShadowOnNinePatchLayer( Type shadow_type); - static std::unique_ptr<SystemShadow> CreateShadowForWindow( + + // Create a system shadow based on `ash::ViewShadow`. This shadow is used for + // views. The shadow's layer is added to the `layers_beneath_` of the view and + // its content bounds are adjusted with the bounds of view's layer. The shadow + // does not need to manually update the content bounds but cannot be used when + // the shadow's content bounds do not equal to the view bounds. For example, + // `AppListFolderView` has a clip rect whose bounds should be the content + // bounds of the shadow. In this case, please use + // `CreateShadowOnNinePatchLayer` instead. + static std::unique_ptr<SystemShadow> CreateShadowOnNinePatchLayerForView( + views::View* view, + Type shadow_type); + + // Create a system shadow based on `ui::Shadow`. The shadow's layer is added + // to the bottom of the window's layer and its contents bounds are adjusted + // with the window bounds. The shadow does not need to manually update the + // content bounds but cannot be used when the shadow's contents bounds do not + // equal to the window bounds. For example, the content bounds of + // `OverviewItem` for wide and tall windows do not equal to the item bounds. + // In this case, please use `CreateShadowOnNinePatchLayer` instead. + static std::unique_ptr<SystemShadow> CreateShadowOnNinePatchLayerForWindow( aura::Window* window, Type shadow_type); + // Get shadow elevation according to the given type. static int GetElevationFromType(Type type); // Change shadow type and update shadow elevation and appearance. Note that to // avoid inconsistency of shadow type and elevation. Always change system - // shadow elevation with `SetType` instead of `SetElevation`. - void SetType(Type type); - Type type() const { return type_; } + // shadow elevation with `SetType`. + virtual void SetType(Type type) = 0; - private: - Type type_ = Type::kElevation4; + virtual void SetContentBounds(const gfx::Rect& bounds) = 0; + + virtual void SetRoundedCornerRadius(int corner_radius) = 0; + + virtual const gfx::Rect& GetContentBounds() = 0; + + // Return the layer of the shadow. This function can be used by any types of + // shadow. The layer is commonly used for setting layer hierarchy, visibility, + // and transformation. + virtual ui::Layer* GetLayer() = 0; + + // Return the nine patch layer of the shadow. This function is only used by + // ui::Shadow based implementations. The nine patch layer is a child layer of + // the shadow's layer painted with the shadow image. Normally, set the + // hierarchy, visibility and transformation on the shadow's layer instead of + // the nine patch layer. + virtual ui::Layer* GetNinePatchLayer() = 0; }; } // namespace ash
diff --git a/ash/style/system_shadow_on_nine_patch_layer.cc b/ash/style/system_shadow_on_nine_patch_layer.cc new file mode 100644 index 0000000..6ecec65a --- /dev/null +++ b/ash/style/system_shadow_on_nine_patch_layer.cc
@@ -0,0 +1,111 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/style/system_shadow_on_nine_patch_layer.h" + +#include "ui/compositor/layer.h" + +namespace ash { + +// ----------------------------------------------------------------------------- +// SystemShadowOnNinePatchLayer: +SystemShadowOnNinePatchLayer::~SystemShadowOnNinePatchLayer() = default; + +void SystemShadowOnNinePatchLayer::SetType(SystemShadow::Type type) { + shadow()->SetElevation(SystemShadow::GetElevationFromType(type)); +} + +void SystemShadowOnNinePatchLayer::SetContentBounds(const gfx::Rect& bounds) { + shadow()->SetContentBounds(bounds); +} + +void SystemShadowOnNinePatchLayer::SetRoundedCornerRadius(int corner_radius) { + shadow()->SetRoundedCornerRadius(corner_radius); +} + +const gfx::Rect& SystemShadowOnNinePatchLayer::GetContentBounds() { + return shadow()->content_bounds(); +} + +ui::Layer* SystemShadowOnNinePatchLayer::GetLayer() { + return shadow()->layer(); +} + +ui::Layer* SystemShadowOnNinePatchLayer::GetNinePatchLayer() { + return shadow()->shadow_layer(); +} + +// ----------------------------------------------------------------------------- +// SystemShadowOnNinePatchLayerImpl: +SystemShadowOnNinePatchLayerImpl::SystemShadowOnNinePatchLayerImpl( + int elevation) { + shadow_.Init(elevation); + shadow_.SetShadowStyle(gfx::ShadowStyle::kChromeOSSystemUI); +} + +SystemShadowOnNinePatchLayerImpl::~SystemShadowOnNinePatchLayerImpl() = default; + +ui::Shadow* SystemShadowOnNinePatchLayerImpl::shadow() { + return &shadow_; +} + +// ----------------------------------------------------------------------------- +// SystemViewShadowOnNinePatchLayer: +SystemViewShadowOnNinePatchLayer::SystemViewShadowOnNinePatchLayer( + views::View* view, + int elevation) + : view_shadow_(view, elevation) { + view_shadow_.shadow()->SetShadowStyle(gfx::ShadowStyle::kChromeOSSystemUI); +} + +SystemViewShadowOnNinePatchLayer::~SystemViewShadowOnNinePatchLayer() = default; + +void SystemViewShadowOnNinePatchLayer::SetRoundedCornerRadius( + int corner_radius) { + view_shadow_.SetRoundedCornerRadius(corner_radius); +} + +void SystemViewShadowOnNinePatchLayer::SetContentBounds( + const gfx::Rect& content_bounds) {} + +ui::Shadow* SystemViewShadowOnNinePatchLayer::shadow() { + return view_shadow_.shadow(); +} + +// ----------------------------------------------------------------------------- +// SystemWindowShadowOnNinePatchLayer: +SystemWindowShadowOnNinePatchLayer::SystemWindowShadowOnNinePatchLayer( + aura::Window* window, + int elevation) + : SystemShadowOnNinePatchLayerImpl(elevation) { + auto* window_layer = window->layer(); + auto* shadow_layer = GetLayer(); + window_layer->Add(shadow_layer); + window_layer->StackAtBottom(shadow_layer); + SystemShadowOnNinePatchLayerImpl::SetContentBounds(window_layer->bounds()); + + window_observation_.Observe(window); +} + +SystemWindowShadowOnNinePatchLayer::~SystemWindowShadowOnNinePatchLayer() = + default; + +void SystemWindowShadowOnNinePatchLayer::OnWindowBoundsChanged( + aura::Window* window, + const gfx::Rect& old_bounds, + const gfx::Rect& new_bounds, + ui::PropertyChangeReason reason) { + SystemShadowOnNinePatchLayerImpl::SetContentBounds( + gfx::Rect(new_bounds.size())); +} + +void SystemWindowShadowOnNinePatchLayer::OnWindowDestroyed( + aura::Window* window) { + window_observation_.Reset(); +} + +void SystemWindowShadowOnNinePatchLayer::SetContentBounds( + const gfx::Rect& content_bounds) {} + +} // namespace ash
diff --git a/ash/style/system_shadow_on_nine_patch_layer.h b/ash/style/system_shadow_on_nine_patch_layer.h new file mode 100644 index 0000000..1c43a91 --- /dev/null +++ b/ash/style/system_shadow_on_nine_patch_layer.h
@@ -0,0 +1,114 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_STYLE_SYSTEM_SHADOW_ON_NINE_PATCH_LAYER_H_ +#define ASH_STYLE_SYSTEM_SHADOW_ON_NINE_PATCH_LAYER_H_ + +#include "ash/public/cpp/view_shadow.h" +#include "ash/style/system_shadow.h" +#include "base/scoped_observation.h" +#include "ui/aura/window.h" +#include "ui/aura/window_observer.h" +#include "ui/compositor_extra/shadow.h" + +namespace ui { +class Layer; +} // namespace ui + +namespace ash { + +// SystemShadowOnNinePatchLayer is an interface for the shadows based on +// ui::Shadow which paints shadow on a nine patch layer. The shadow attributes +// are set and get from ui::Shadow's functions. The child classes need to expose +// their ui::Shadow pointer in `shadow()`. +class SystemShadowOnNinePatchLayer : public SystemShadow { + public: + ~SystemShadowOnNinePatchLayer() override; + + // SystemShadow: + void SetType(SystemShadow::Type type) override; + void SetContentBounds(const gfx::Rect& bounds) override; + void SetRoundedCornerRadius(int corner_radius) override; + const gfx::Rect& GetContentBounds() override; + ui::Layer* GetLayer() override; + ui::Layer* GetNinePatchLayer() override; + + protected: + virtual ui::Shadow* shadow() = 0; +}; + +// An implementation of `SystemShadowOnNinePatchLayer`. It is directly based on +// the ui::Shadow. +class SystemShadowOnNinePatchLayerImpl : public SystemShadowOnNinePatchLayer { + public: + explicit SystemShadowOnNinePatchLayerImpl(int elevation); + SystemShadowOnNinePatchLayerImpl(const SystemShadowOnNinePatchLayerImpl&) = + delete; + SystemShadowOnNinePatchLayerImpl& operator=( + const SystemShadowOnNinePatchLayerImpl&) = delete; + ~SystemShadowOnNinePatchLayerImpl() override; + + private: + // SystemShadowOnNinePatchLayer: + ui::Shadow* shadow() override; + + ui::Shadow shadow_; +}; + +// An implementation of `SystemShadowOnNinePatchLayer`. It is based on +// ViewShadow. The ViewShadow is added in the layers beneath the view and +// adjusts its content bounds with the view's bounds. Do not manually set the +// content bounds. +class SystemViewShadowOnNinePatchLayer : public SystemShadowOnNinePatchLayer { + public: + SystemViewShadowOnNinePatchLayer(views::View* view, int elevation); + SystemViewShadowOnNinePatchLayer(const SystemViewShadowOnNinePatchLayer&) = + delete; + SystemViewShadowOnNinePatchLayer& operator=( + const SystemViewShadowOnNinePatchLayer&) = delete; + ~SystemViewShadowOnNinePatchLayer() override; + + // SystemShadow: + void SetRoundedCornerRadius(int corner_radius) override; + + private: + // SystemShadowOnNinePatchLayer: + void SetContentBounds(const gfx::Rect& content_bounds) override; + ui::Shadow* shadow() override; + + ViewShadow view_shadow_; +}; + +// An extension of SystemShadowOnNinePatchLayerImpl. The shadow is added at the +// bottom of a window's layer and adjusts its content bounds with the window's +// bounds. Do not manually set the content bounds. +class SystemWindowShadowOnNinePatchLayer + : public SystemShadowOnNinePatchLayerImpl, + public aura::WindowObserver { + public: + SystemWindowShadowOnNinePatchLayer(aura::Window* window, int elevation); + SystemWindowShadowOnNinePatchLayer( + const SystemWindowShadowOnNinePatchLayer&) = delete; + SystemWindowShadowOnNinePatchLayer& operator=( + const SystemWindowShadowOnNinePatchLayer&) = delete; + ~SystemWindowShadowOnNinePatchLayer() override; + + // aura::WindowObserver: + void OnWindowBoundsChanged(aura::Window* window, + const gfx::Rect& old_bounds, + const gfx::Rect& new_bounds, + ui::PropertyChangeReason reason) override; + void OnWindowDestroyed(aura::Window* window) override; + + private: + // SystemShadowOnNinePatchLayerImpl: + void SetContentBounds(const gfx::Rect& content_bounds) override; + + base::ScopedObservation<aura::Window, aura::WindowObserver> + window_observation_{this}; +}; + +} // namespace ash + +#endif // ASH_STYLE_SYSTEM_SHADOW_ON_NINE_PATCH_LAYER_H_
diff --git a/ash/system/channel_indicator/channel_indicator.cc b/ash/system/channel_indicator/channel_indicator.cc index e2a0fd02..a9fe873 100644 --- a/ash/system/channel_indicator/channel_indicator.cc +++ b/ash/system/channel_indicator/channel_indicator.cc
@@ -4,26 +4,16 @@ #include "ash/system/channel_indicator/channel_indicator.h" -#include <string> -#include <utility> - -#include "ash/public/cpp/shelf_config.h" -#include "ash/public/cpp/style/dark_light_mode_controller.h" -#include "ash/public/cpp/system_tray_client.h" #include "ash/resources/vector_icons/vector_icons.h" -#include "ash/strings/grit/ash_strings.h" -#include "ash/system/model/system_tray_model.h" +#include "ash/shelf/shelf.h" +#include "ash/system/channel_indicator/channel_indicator_utils.h" #include "ash/system/tray/tray_constants.h" -#include "ash/system/tray/tray_item_view.h" -#include "components/session_manager/session_manager_types.h" -#include "components/version_info/channel.h" #include "ui/accessibility/ax_node_data.h" #include "ui/base/l10n/l10n_util.h" #include "ui/gfx/paint_vector_icon.h" #include "ui/views/background.h" #include "ui/views/border.h" #include "ui/views/controls/image_view.h" -#include "ui/views/view.h" namespace ash { @@ -31,64 +21,6 @@ constexpr int kIndicatorBgCornerRadius = 50; -bool IsDisplayableChannel(version_info::Channel channel) { - switch (channel) { - case version_info::Channel::BETA: - case version_info::Channel::DEV: - case version_info::Channel::CANARY: - return true; - default: - return false; - } -} - -SkColor GetFgColor(version_info::Channel channel) { - bool is_dark_mode_enabled = - DarkLightModeController::Get()->IsDarkModeEnabled(); - switch (channel) { - case version_info::Channel::BETA: - return is_dark_mode_enabled ? gfx::kGoogleBlue200 : gfx::kGoogleBlue900; - case version_info::Channel::DEV: - return is_dark_mode_enabled ? gfx::kGoogleGreen200 : gfx::kGoogleGreen900; - case version_info::Channel::CANARY: - return is_dark_mode_enabled ? gfx::kGoogleYellow200 : gfx::kGoogleGrey900; - default: - return 0; - } -} - -SkColor GetBgColor(version_info::Channel channel) { - bool is_dark_mode_enabled = - DarkLightModeController::Get()->IsDarkModeEnabled(); - switch (channel) { - case version_info::Channel::BETA: - return is_dark_mode_enabled ? SkColorSetA(gfx::kGoogleBlue300, 0x55) - : gfx::kGoogleBlue200; - case version_info::Channel::DEV: - return is_dark_mode_enabled ? SkColorSetA(gfx::kGoogleGreen300, 0x55) - : gfx::kGoogleGreen200; - case version_info::Channel::CANARY: - return is_dark_mode_enabled ? SkColorSetA(gfx::kGoogleYellow300, 0x55) - : gfx::kGoogleYellow200; - default: - return 0; - } -} - -int GetStringResource(version_info::Channel channel) { - DCHECK(IsDisplayableChannel(channel)); - switch (channel) { - case version_info::Channel::BETA: - return IDS_ASH_STATUS_TRAY_CHANNEL_BETA; - case version_info::Channel::DEV: - return IDS_ASH_STATUS_TRAY_CHANNEL_DEV; - case version_info::Channel::CANARY: - return IDS_ASH_STATUS_TRAY_CHANNEL_CANARY; - default: - return -1; - } -} - } // namespace ChannelIndicatorView::ChannelIndicatorView(Shelf* shelf, @@ -133,7 +65,7 @@ } void ChannelIndicatorView::Update(version_info::Channel channel) { - if (!IsDisplayableChannel(channel)) + if (!channel_indicator_utils::IsDisplayableChannel(channel)) return; SetVisible(true); @@ -143,28 +75,28 @@ } void ChannelIndicatorView::SetImage(version_info::Channel channel) { - DCHECK(IsDisplayableChannel(channel)); + DCHECK(channel_indicator_utils::IsDisplayableChannel(channel)); SetBorder(views::CreateEmptyBorder( gfx::Insets::VH(kUnifiedTrayChannelIndicatorDimension / 2, 0))); image_view()->SetBackground(views::CreateRoundedRectBackground( - GetBgColor(channel), kIndicatorBgCornerRadius)); + channel_indicator_utils::GetBgColor(channel), kIndicatorBgCornerRadius)); switch (channel) { case version_info::Channel::BETA: image_view()->SetImage(gfx::CreateVectorIcon( kChannelBetaIcon, kUnifiedTrayChannelIndicatorDimension, - GetFgColor(channel))); + channel_indicator_utils::GetFgColor(channel))); break; case version_info::Channel::DEV: image_view()->SetImage(gfx::CreateVectorIcon( kChannelDevIcon, kUnifiedTrayChannelIndicatorDimension, - GetFgColor(channel))); + channel_indicator_utils::GetFgColor(channel))); break; case version_info::Channel::CANARY: image_view()->SetImage(gfx::CreateVectorIcon( kChannelCanaryIcon, kUnifiedTrayChannelIndicatorDimension, - GetFgColor(channel))); + channel_indicator_utils::GetFgColor(channel))); break; default: break; @@ -172,14 +104,16 @@ } void ChannelIndicatorView::SetAccessibleName(version_info::Channel channel) { - DCHECK(IsDisplayableChannel(channel)); - accessible_name_ = l10n_util::GetStringUTF16(GetStringResource(channel)); + DCHECK(channel_indicator_utils::IsDisplayableChannel(channel)); + accessible_name_ = l10n_util::GetStringUTF16( + channel_indicator_utils::GetChannelNameStringResourceID(channel, true)); image_view()->SetAccessibleName(accessible_name_); } void ChannelIndicatorView::SetTooltip(version_info::Channel channel) { - DCHECK(IsDisplayableChannel(channel)); - tooltip_ = l10n_util::GetStringUTF16(GetStringResource(channel)); + DCHECK(channel_indicator_utils::IsDisplayableChannel(channel)); + tooltip_ = l10n_util::GetStringUTF16( + channel_indicator_utils::GetChannelNameStringResourceID(channel, true)); } } // namespace ash
diff --git a/ash/system/channel_indicator/channel_indicator.h b/ash/system/channel_indicator/channel_indicator.h index ce410e4f..d05075f 100644 --- a/ash/system/channel_indicator/channel_indicator.h +++ b/ash/system/channel_indicator/channel_indicator.h
@@ -39,9 +39,14 @@ void SetAccessibleName(version_info::Channel channel); void SetTooltip(version_info::Channel channel); + // The localized string used to announce this view in accessibility mode. std::u16string accessible_name_; + + // The localized string displayed when this view is hovered-over. std::u16string tooltip_; - version_info::Channel channel_; + + // The release track on which this devices resides. + const version_info::Channel channel_; }; } // namespace ash
diff --git a/ash/system/channel_indicator/channel_indicator_quick_settings_view.cc b/ash/system/channel_indicator/channel_indicator_quick_settings_view.cc new file mode 100644 index 0000000..aaee021 --- /dev/null +++ b/ash/system/channel_indicator/channel_indicator_quick_settings_view.cc
@@ -0,0 +1,173 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/system/channel_indicator/channel_indicator_quick_settings_view.h" + +#include "ash/public/cpp/system_tray_client.h" +#include "ash/resources/vector_icons/vector_icons.h" +#include "ash/shell.h" +#include "ash/strings/grit/ash_strings.h" +#include "ash/style/icon_button.h" +#include "ash/system/channel_indicator/channel_indicator_utils.h" +#include "ash/system/model/system_tray_model.h" +#include "ash/system/tray/tray_constants.h" +#include "ui/gfx/canvas.h" +#include "ui/gfx/geometry/insets.h" +#include "ui/gfx/geometry/skia_conversions.h" +#include "ui/views/border.h" +#include "ui/views/controls/button/label_button.h" +#include "ui/views/controls/highlight_path_generator.h" +#include "ui/views/layout/box_layout.h" +#include "ui/views/view.h" + +namespace ash { + +namespace { + +constexpr int kVersionButtonHeight = 32; +constexpr int kVersionButtonBorderRadius = 4; +constexpr int kVersionButtonImageLabelSpacing = 8; + +constexpr int kVersionButtonMarginVertical = 6; +constexpr int kVersionButtonMarginHorizontal = 16; + +constexpr int kVersionButtonLargeCornerRadius = 16; +constexpr int kVersionButtonSmallCornerRadius = 4; +constexpr SkScalar kVersionButtonCorners[] = { + kVersionButtonLargeCornerRadius, kVersionButtonLargeCornerRadius, + kVersionButtonSmallCornerRadius, kVersionButtonSmallCornerRadius, + kVersionButtonSmallCornerRadius, kVersionButtonSmallCornerRadius, + kVersionButtonLargeCornerRadius, kVersionButtonLargeCornerRadius}; + +constexpr int kFeedbackButtonMarginVertical = 6; +constexpr int kFeedbackButtonMarginHorizontal = 16; + +constexpr int kFeedbackButtonLargeCornerRadius = 16; +constexpr int kFeedbackButtonSmallCornerRadius = 4; +constexpr SkScalar kFeedbackButtonCorners[] = { + kFeedbackButtonSmallCornerRadius, kFeedbackButtonSmallCornerRadius, + kFeedbackButtonLargeCornerRadius, kFeedbackButtonLargeCornerRadius, + kFeedbackButtonLargeCornerRadius, kFeedbackButtonLargeCornerRadius, + kFeedbackButtonSmallCornerRadius, kFeedbackButtonSmallCornerRadius}; + +constexpr int kButtonSpacing = 2; + +} // namespace + +// VersionButton provides a styled button, for devices on a +// non-stable release track, that has a label for the channel and ChromeOS +// version. +class ASH_EXPORT VersionButton : public views::LabelButton { + public: + explicit VersionButton(version_info::Channel channel) + : LabelButton( + base::BindRepeating([] { + Shell::Get() + ->system_tray_model() + ->client() + ->ShowChannelInfoAdditionalDetails(); + }), + channel_indicator_utils::GetFullReleaseTrackString(channel)), + channel_(channel) { + SetBorder(views::CreateEmptyBorder(gfx::Insets::VH( + kVersionButtonMarginVertical, kVersionButtonMarginHorizontal))); + SetImageLabelSpacing(kVersionButtonImageLabelSpacing); + SetMinSize(gfx::Size(0, kVersionButtonHeight)); + SetFocusBehavior(FocusBehavior::ALWAYS); + SetInstallFocusRingOnFocus(true); + views::FocusRing::Get(this)->SetColorId(ui::kColorAshFocusRing); + views::InstallRoundRectHighlightPathGenerator(this, gfx::Insets(), + kVersionButtonBorderRadius); + } + VersionButton(const VersionButton&) = delete; + VersionButton& operator=(const VersionButton&) = delete; + ~VersionButton() override = default; + + // views::LabelButton: + void PaintButtonContents(gfx::Canvas* canvas) override { + cc::PaintFlags flags; + flags.setColor(channel_indicator_utils::GetBgColor(channel_)); + flags.setStyle(cc::PaintFlags::kFill_Style); + canvas->DrawPath( + SkPath().addRoundRect(gfx::RectToSkRect(GetLocalBounds()), + kVersionButtonCorners, SkPathDirection::kCW), + flags); + } + + void OnThemeChanged() override { + views::LabelButton::OnThemeChanged(); + SetBackgroundAndFont(); + } + + private: + void SetBackgroundAndFont() { + label()->SetFontList( + gfx::FontList().DeriveWithWeight(gfx::Font::Weight::MEDIUM)); + SetEnabledTextColors(channel_indicator_utils::GetFgColor(channel_)); + } + + const version_info::Channel channel_; +}; + +// FeedbackButton provides a styled button, for devices on a +// non-stable release track, that allows the user to submit feedback. +class ASH_EXPORT FeedbackButton : public IconButton { + public: + explicit FeedbackButton(version_info::Channel channel) + : IconButton(base::BindRepeating([] { + Shell::Get() + ->system_tray_model() + ->client() + ->ShowChannelInfoGiveFeedback(); + }), + IconButton::Type::kSmall, + &kRequestFeedbackIcon, + IDS_ASH_STATUS_TRAY_REPORT_FEEDBACK), + channel_(channel) { + SetBorder(views::CreateEmptyBorder(gfx::Insets::VH( + kFeedbackButtonMarginVertical, kFeedbackButtonMarginHorizontal))); + SetIconColor(channel_indicator_utils::GetFgColor(channel_)); + } + FeedbackButton(const FeedbackButton&) = delete; + FeedbackButton& operator=(const FeedbackButton&) = delete; + ~FeedbackButton() override = default; + + // views::LabelButton: + void PaintButtonContents(gfx::Canvas* canvas) override { + cc::PaintFlags flags; + flags.setColor(channel_indicator_utils::GetBgColor(channel_)); + flags.setStyle(cc::PaintFlags::kFill_Style); + canvas->DrawPath( + SkPath().addRoundRect(gfx::RectToSkRect(GetLocalBounds()), + kFeedbackButtonCorners, SkPathDirection::kCW), + flags); + IconButton::PaintButtonContents(canvas); + } + + private: + const version_info::Channel channel_; +}; + +ChannelIndicatorQuickSettingsView::ChannelIndicatorQuickSettingsView( + version_info::Channel channel) { + auto* layout = SetLayoutManager(std::make_unique<views::BoxLayout>( + views::BoxLayout::Orientation::kHorizontal, kUnifiedSystemInfoViewPadding, + kUnifiedSystemInfoSpacing)); + layout->set_cross_axis_alignment( + views::BoxLayout::CrossAxisAlignment::kCenter); + layout->set_between_child_spacing(kButtonSpacing); + + version_button_ = AddChildView(std::make_unique<VersionButton>(channel)); + feedback_button_ = AddChildView(std::make_unique<FeedbackButton>(channel)); +} + +bool ChannelIndicatorQuickSettingsView::IsVersionButtonVisibleForTesting() { + return version_button_->GetVisible(); +} + +bool ChannelIndicatorQuickSettingsView::IsFeedbackButtonVisibleForTesting() { + return feedback_button_->GetVisible(); +} + +} // namespace ash
diff --git a/ash/system/channel_indicator/channel_indicator_quick_settings_view.h b/ash/system/channel_indicator/channel_indicator_quick_settings_view.h new file mode 100644 index 0000000..57475d06 --- /dev/null +++ b/ash/system/channel_indicator/channel_indicator_quick_settings_view.h
@@ -0,0 +1,40 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_SYSTEM_CHANNEL_INDICATOR_CHANNEL_INDICATOR_QUICK_SETTINGS_VIEW_H_ +#define ASH_SYSTEM_CHANNEL_INDICATOR_CHANNEL_INDICATOR_QUICK_SETTINGS_VIEW_H_ + +#include "ash/ash_export.h" +#include "components/version_info/channel.h" +#include "ui/views/view.h" + +namespace ash { + +class VersionButton; +class FeedbackButton; + +// ChannelIndicatorQuickSettingsView contains all of the views included in the +// channel indicator UI that resides in UnifiedSystemInfoView. +class ASH_EXPORT ChannelIndicatorQuickSettingsView : public views::View { + public: + explicit ChannelIndicatorQuickSettingsView(version_info::Channel channel); + ChannelIndicatorQuickSettingsView(const ChannelIndicatorQuickSettingsView&) = + delete; + ChannelIndicatorQuickSettingsView& operator=( + const ChannelIndicatorQuickSettingsView&) = delete; + ~ChannelIndicatorQuickSettingsView() override = default; + + // Introspection methods for unit tests. + bool IsVersionButtonVisibleForTesting(); + bool IsFeedbackButtonVisibleForTesting(); + + private: + // Refs maintained for unit test introspection methods. + VersionButton* version_button_ = nullptr; + FeedbackButton* feedback_button_ = nullptr; +}; + +} // namespace ash + +#endif // ASH_SYSTEM_CHANNEL_INDICATOR_CHANNEL_INDICATOR_QUICK_SETTINGS_VIEW_H_
diff --git a/ash/system/channel_indicator/channel_indicator_quick_settings_view_unittest.cc b/ash/system/channel_indicator/channel_indicator_quick_settings_view_unittest.cc new file mode 100644 index 0000000..d0598683 --- /dev/null +++ b/ash/system/channel_indicator/channel_indicator_quick_settings_view_unittest.cc
@@ -0,0 +1,59 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/system/channel_indicator/channel_indicator_quick_settings_view.h" + +#include "ash/constants/ash_features.h" +#include "ash/test/ash_test_base.h" +#include "components/version_info/channel.h" + +namespace ash { + +class ChannelIndicatorQuickSettingsViewTest + : public AshTestBase, + public testing::WithParamInterface<bool> { + public: + ChannelIndicatorQuickSettingsViewTest() = default; + ChannelIndicatorQuickSettingsViewTest( + const ChannelIndicatorQuickSettingsViewTest&) = delete; + ChannelIndicatorQuickSettingsViewTest& operator=( + const ChannelIndicatorQuickSettingsViewTest&) = delete; + ~ChannelIndicatorQuickSettingsViewTest() override = default; + + // AshTestBase: + void SetUp() override { + AshTestBase::SetUp(); + + // Instantiate members. + view_ = std::make_unique<ChannelIndicatorQuickSettingsView>( + static_cast<version_info::Channel>(GetParam())); + } + + // Ignored for now, will come into play with the fix for crbug.com/1344855. + bool IsFeedbackShown() { return GetParam(); } + + ChannelIndicatorQuickSettingsView* view() { return view_.get(); } + + private: + std::unique_ptr<ChannelIndicatorQuickSettingsView> view_; +}; + +// Run the `Visible` test below for each value of version_info::Channel. +INSTANTIATE_TEST_SUITE_P(ChannelValues, + ChannelIndicatorQuickSettingsViewTest, + ::testing::Bool()); + +TEST_P(ChannelIndicatorQuickSettingsViewTest, Visible) { + // View exists. + EXPECT_TRUE(view()); + + // Version button is always visible. + EXPECT_TRUE(view()->IsVersionButtonVisibleForTesting()); + + // Feedback button is always visible, for now. This will change with the fix + // for crbug.com/1344855. + EXPECT_TRUE(view()->IsFeedbackButtonVisibleForTesting()); +} + +} // namespace ash
diff --git a/ash/system/channel_indicator/channel_indicator_unittest.cc b/ash/system/channel_indicator/channel_indicator_unittest.cc index 12c5bc4..17a13c2 100644 --- a/ash/system/channel_indicator/channel_indicator_unittest.cc +++ b/ash/system/channel_indicator/channel_indicator_unittest.cc
@@ -21,6 +21,12 @@ : public AshTestBase, public testing::WithParamInterface<version_info::Channel> { public: + ChannelIndicatorViewTest() = default; + ChannelIndicatorViewTest(const ChannelIndicatorViewTest&) = delete; + ChannelIndicatorViewTest& operator=(const ChannelIndicatorViewTest&) = delete; + ~ChannelIndicatorViewTest() override = default; + + // AshTestBase: void SetUp() override { // Need this feature enabled in order for the `ChannelIndicatorView` to be // instantiated.
diff --git a/ash/system/channel_indicator/channel_indicator_utils.cc b/ash/system/channel_indicator/channel_indicator_utils.cc new file mode 100644 index 0000000..a42e2e1 --- /dev/null +++ b/ash/system/channel_indicator/channel_indicator_utils.cc
@@ -0,0 +1,100 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/system/channel_indicator/channel_indicator_utils.h" + +#include <string> + +#include "ash/public/cpp/style/dark_light_mode_controller.h" +#include "ash/shell.h" +#include "ash/shell_delegate.h" +#include "ash/strings/grit/ash_strings.h" +#include "base/strings/strcat.h" +#include "base/strings/utf_string_conversions.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/gfx/color_palette.h" + +namespace ash::channel_indicator_utils { + +bool IsDisplayableChannel(version_info::Channel channel) { + switch (channel) { + case version_info::Channel::BETA: + case version_info::Channel::DEV: + case version_info::Channel::CANARY: + return true; + case version_info::Channel::STABLE: + case version_info::Channel::UNKNOWN: + return false; + } +} + +int GetChannelNameStringResourceID(version_info::Channel channel, + bool append_channel) { + switch (channel) { + case version_info::Channel::BETA: + return append_channel ? IDS_ASH_STATUS_TRAY_CHANNEL_BETA_CHANNEL + : IDS_ASH_STATUS_TRAY_CHANNEL_BETA; + case version_info::Channel::DEV: + return append_channel ? IDS_ASH_STATUS_TRAY_CHANNEL_DEV_CHANNEL + : IDS_ASH_STATUS_TRAY_CHANNEL_DEV; + case version_info::Channel::CANARY: + return append_channel ? IDS_ASH_STATUS_TRAY_CHANNEL_CANARY_CHANNEL + : IDS_ASH_STATUS_TRAY_CHANNEL_CANARY; + // Handle STABLE/UNKNOWN here to satisfy the compiler without using + // "default," but the DCHECK() above will bark if that value is ever + // actually passed in. + case version_info::Channel::STABLE: + case version_info::Channel::UNKNOWN: + return -1; + } +} + +SkColor GetFgColor(version_info::Channel channel) { + bool is_dark_mode_enabled = + DarkLightModeController::Get()->IsDarkModeEnabled(); + switch (channel) { + case version_info::Channel::BETA: + return is_dark_mode_enabled ? gfx::kGoogleBlue200 : gfx::kGoogleBlue900; + case version_info::Channel::DEV: + return is_dark_mode_enabled ? gfx::kGoogleGreen200 : gfx::kGoogleGreen900; + case version_info::Channel::CANARY: + return is_dark_mode_enabled ? gfx::kGoogleYellow200 : gfx::kGoogleGrey900; + case version_info::Channel::STABLE: + case version_info::Channel::UNKNOWN: + return SkColorSetRGB(0x00, 0x00, 0x00); + } +} + +SkColor GetBgColor(version_info::Channel channel) { + bool is_dark_mode_enabled = + DarkLightModeController::Get()->IsDarkModeEnabled(); + switch (channel) { + case version_info::Channel::BETA: + return is_dark_mode_enabled ? SkColorSetA(gfx::kGoogleBlue300, 0x55) + : gfx::kGoogleBlue200; + case version_info::Channel::DEV: + return is_dark_mode_enabled ? SkColorSetA(gfx::kGoogleGreen300, 0x55) + : gfx::kGoogleGreen200; + case version_info::Channel::CANARY: + return is_dark_mode_enabled ? SkColorSetA(gfx::kGoogleYellow300, 0x55) + : gfx::kGoogleYellow200; + case version_info::Channel::STABLE: + case version_info::Channel::UNKNOWN: + return SkColorSetRGB(0x00, 0x00, 0x00); + } +} + +std::u16string GetFullReleaseTrackString(version_info::Channel channel) { + if (!IsDisplayableChannel(channel)) + return std::u16string(); + + return base::StrCat( + {l10n_util::GetStringUTF16( + channel_indicator_utils::GetChannelNameStringResourceID(channel, + false)), + u" ", + base::UTF8ToUTF16(Shell::Get()->shell_delegate()->GetVersionString())}); +} + +} // namespace ash::channel_indicator_utils
diff --git a/ash/system/channel_indicator/channel_indicator_utils.h b/ash/system/channel_indicator/channel_indicator_utils.h new file mode 100644 index 0000000..28eb15e --- /dev/null +++ b/ash/system/channel_indicator/channel_indicator_utils.h
@@ -0,0 +1,44 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_SYSTEM_CHANNEL_INDICATOR_CHANNEL_INDICATOR_UTILS_H_ +#define ASH_SYSTEM_CHANNEL_INDICATOR_CHANNEL_INDICATOR_UTILS_H_ + +#include <string> + +#include "ash/ash_export.h" +#include "components/version_info/channel.h" +#include "third_party/skia/include/core/SkColor.h" + +namespace ash::channel_indicator_utils { + +// Returns 'true' if `channel` is a release track name we want to show the user. +ASH_EXPORT bool IsDisplayableChannel(version_info::Channel channel); + +// Returns a string resource ID for the release track `channel`. If +// `append_channel` is 'true' then the resource ID returned is for a string that +// has "channel" at the end e.g. "Beta Channel" instead of just "Beta". If +// `channel` is `STABLE` or `UNKNOWN` this function will return -1. +ASH_EXPORT int GetChannelNameStringResourceID(version_info::Channel channel, + bool append_channel); + +// Returns the foreground UI color for release track `channel`. If `channel` is +// one of the displayable values then the expected `SkColor` is returned, a +// value of SkColorSetRGB(0x00, 0x00, 0x00) otherwise. +ASH_EXPORT SkColor GetFgColor(version_info::Channel channel); + +// Returns the background UI color for release track `channel`. If `channel` is +// one of the displayable values then the expected `SkColor` is returned, a +// value of SkColorSetRGB(0x00, 0x00, 0x00) otherwise. +ASH_EXPORT SkColor GetBgColor(version_info::Channel channel); + +// Returns the text for the version button text, for release track `channel` +// e.g. "Beta 105.0.5167.0". If `channel` is not one of the displayable values, +// the function will return an empty std::u16string. +ASH_EXPORT std::u16string GetFullReleaseTrackString( + version_info::Channel channel); + +} // namespace ash::channel_indicator_utils + +#endif // ASH_SYSTEM_CHANNEL_INDICATOR_CHANNEL_INDICATOR_UTILS_H_ \ No newline at end of file
diff --git a/ash/system/channel_indicator/channel_indicator_utils_unittest.cc b/ash/system/channel_indicator/channel_indicator_utils_unittest.cc new file mode 100644 index 0000000..d849d6c4 --- /dev/null +++ b/ash/system/channel_indicator/channel_indicator_utils_unittest.cc
@@ -0,0 +1,114 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/system/channel_indicator/channel_indicator_utils.h" + +#include <string> + +#include "ash/public/cpp/style/dark_light_mode_controller.h" +#include "ash/strings/grit/ash_strings.h" +#include "ash/test/ash_test_base.h" +#include "ash/test_shell_delegate.h" +#include "components/version_info/channel.h" +#include "ui/gfx/color_palette.h" + +namespace ash { +namespace { + +// OS version that's set, and final button string that's expected. +const char* kTestOsVersion = "123.45.6789.10"; +const char16_t* kTestButtonStr = u"Beta 123.45.6789.10"; + +} // namespace + +class ChannelIndicatorUtilsTest : public AshTestBase { + public: + ChannelIndicatorUtilsTest() = default; + ChannelIndicatorUtilsTest(const ChannelIndicatorUtilsTest&) = delete; + ChannelIndicatorUtilsTest& operator=(const ChannelIndicatorUtilsTest&) = + delete; + ~ChannelIndicatorUtilsTest() override = default; + + // AshTestBase: + void SetUp() override { + // Instantiate a `TestShellDelegate` with the version set to something + // tests can verify. + std::unique_ptr<TestShellDelegate> shell_delegate = + std::make_unique<TestShellDelegate>(); + shell_delegate->set_version_string(kTestOsVersion); + AshTestBase::SetUp(std::move(shell_delegate)); + } +}; + +TEST_F(ChannelIndicatorUtilsTest, IsDisplayableChannel) { + EXPECT_FALSE(channel_indicator_utils::IsDisplayableChannel( + version_info::Channel::UNKNOWN)); + EXPECT_TRUE(channel_indicator_utils::IsDisplayableChannel( + version_info::Channel::CANARY)); + EXPECT_TRUE(channel_indicator_utils::IsDisplayableChannel( + version_info::Channel::DEV)); + EXPECT_TRUE(channel_indicator_utils::IsDisplayableChannel( + version_info::Channel::BETA)); + EXPECT_FALSE(channel_indicator_utils::IsDisplayableChannel( + version_info::Channel::STABLE)); +} + +TEST_F(ChannelIndicatorUtilsTest, GetChannelNameStringResourceID) { + // Non-displayable channel should yield a resource_id of -1. + EXPECT_EQ(channel_indicator_utils::GetChannelNameStringResourceID( + version_info::Channel::STABLE, false), + -1); + + // Same thing if `append_channel` is `true`. + EXPECT_EQ(channel_indicator_utils::GetChannelNameStringResourceID( + version_info::Channel::STABLE, true), + -1); + + // Displayable channel should yield a valid resource_id. + EXPECT_EQ(channel_indicator_utils::GetChannelNameStringResourceID( + version_info::Channel::BETA, false), + IDS_ASH_STATUS_TRAY_CHANNEL_BETA); + + // An equally-valid resource_id if `append_channel` is `true`. + EXPECT_EQ(channel_indicator_utils::GetChannelNameStringResourceID( + version_info::Channel::BETA, true), + IDS_ASH_STATUS_TRAY_CHANNEL_BETA_CHANNEL); +} + +TEST_F(ChannelIndicatorUtilsTest, GetColors) { + // Non-displayable channel should yield fg/bg colors of 0. + EXPECT_EQ(channel_indicator_utils::GetFgColor(version_info::Channel::STABLE), + SkColorSetRGB(0x00, 0x00, 0x00)); + EXPECT_EQ(channel_indicator_utils::GetBgColor(version_info::Channel::STABLE), + SkColorSetRGB(0x00, 0x00, 0x00)); + + // Displayable channel should yield valid, nonzero fg/bg colors. Check with + // dark mode not enabled first. + DarkLightModeController::Get()->SetDarkModeEnabledForTest(false); + EXPECT_EQ(channel_indicator_utils::GetFgColor(version_info::Channel::BETA), + gfx::kGoogleBlue900); + EXPECT_EQ(channel_indicator_utils::GetBgColor(version_info::Channel::BETA), + gfx::kGoogleBlue200); + + // Check with dark mode enabled. + DarkLightModeController::Get()->SetDarkModeEnabledForTest(true); + EXPECT_EQ(channel_indicator_utils::GetFgColor(version_info::Channel::BETA), + gfx::kGoogleBlue200); + EXPECT_EQ(channel_indicator_utils::GetBgColor(version_info::Channel::BETA), + SkColorSetA(gfx::kGoogleBlue300, 0x55)); +} + +TEST_F(ChannelIndicatorUtilsTest, GetFullReleaseTrackString) { + // Channel is not displayable, no string. + EXPECT_TRUE(channel_indicator_utils::GetFullReleaseTrackString( + version_info::Channel::STABLE) + .empty()); + + // Channel is displayable, string that's expected. + EXPECT_EQ(channel_indicator_utils::GetFullReleaseTrackString( + version_info::Channel::BETA), + kTestButtonStr); +} + +} // namespace ash
diff --git a/ash/system/message_center/unified_message_center_bubble.cc b/ash/system/message_center/unified_message_center_bubble.cc index 31beebb3..8228ee4f8 100644 --- a/ash/system/message_center/unified_message_center_bubble.cc +++ b/ash/system/message_center/unified_message_center_bubble.cc
@@ -115,8 +115,8 @@ } // Create a shadow for bubble widget. - shadow_ = SystemShadow::CreateShadowForWidget( - bubble_widget_, SystemShadow::Type::kElevation12); + shadow_ = SystemShadow::CreateShadowOnNinePatchLayerForWindow( + bubble_widget_->GetNativeWindow(), SystemShadow::Type::kElevation12); shadow_->SetRoundedCornerRadius(kBubbleCornerRadius); bubble_view_->InitializeAndShowBubble(); @@ -199,14 +199,10 @@ // When the last notification is removed, the content bounds of message center // may become too small such which makes the shadow's bounds smaller than its - // blur region. To avoid this, we do not update shadow's content bounds and - // hide the shadow when the message center has no notifications. - if (message_center_view_->message_list_view()->GetTotalNotificationCount()) { - shadow_->layer()->SetVisible(true); - shadow_->SetContentBounds(bubble_view_->GetContentsBounds()); - } else { - shadow_->layer()->SetVisible(false); - } + // blur region. To avoid this, we hide the shadow when the message center has + // no notifications. + shadow_->GetLayer()->SetVisible( + message_center_view_->message_list_view()->GetTotalNotificationCount()); } void UnifiedMessageCenterBubble::FocusEntered(bool reverse) {
diff --git a/ash/system/power/power_button_menu_view.cc b/ash/system/power/power_button_menu_view.cc index f98ea40..9a00822 100644 --- a/ash/system/power/power_button_menu_view.cc +++ b/ash/system/power/power_button_menu_view.cc
@@ -12,7 +12,6 @@ #include "ash/login/login_screen_controller.h" #include "ash/public/cpp/new_window_delegate.h" #include "ash/public/cpp/style/scoped_light_mode_as_default.h" -#include "ash/public/cpp/view_shadow.h" #include "ash/resources/vector_icons/vector_icons.h" #include "ash/session/session_controller_impl.h" #include "ash/shell.h" @@ -101,11 +100,9 @@ l10n_util::GetStringUTF16(IDS_ASH_POWER_BUTTON_MENU_ACCESSIBLE)); RecreateItems(); - // Create a view shadow. - shadow_ = std::make_unique<ViewShadow>( - this, - SystemShadow::GetElevationFromType(SystemShadow::Type::kElevation12)); - shadow_->shadow()->SetShadowStyle(gfx::ShadowStyle::kChromeOSSystemUI); + // Create a system shadow for current view. + shadow_ = SystemShadow::CreateShadowOnNinePatchLayerForView( + this, SystemShadow::Type::kElevation12); shadow_->SetRoundedCornerRadius(kMenuCornerRadius); } @@ -130,7 +127,7 @@ } SetLayerAnimation(layer(), this, show, transform); - SetLayerAnimation(shadow_->shadow()->layer(), nullptr, show, transform); + SetLayerAnimation(shadow_->GetLayer(), nullptr, show, transform); } PowerButtonMenuView::TransformDisplacement
diff --git a/ash/system/power/power_button_menu_view.h b/ash/system/power/power_button_menu_view.h index 830f509..cc98af9 100644 --- a/ash/system/power/power_button_menu_view.h +++ b/ash/system/power/power_button_menu_view.h
@@ -14,7 +14,7 @@ namespace ash { enum class PowerButtonMenuActionType; class PowerButtonMenuItemView; -class ViewShadow; +class SystemShadow; // PowerButtonMenuView displays the menu items of the power button menu. It // includes power off and sign out items currently. @@ -97,7 +97,7 @@ // The physical display side of power button in landscape primary. PowerButtonController::PowerButtonPosition power_button_position_; - std::unique_ptr<ViewShadow> shadow_; + std::unique_ptr<SystemShadow> shadow_; }; } // namespace ash
diff --git a/ash/system/privacy/privacy_indicators_controller.cc b/ash/system/privacy/privacy_indicators_controller.cc new file mode 100644 index 0000000..7812ad454 --- /dev/null +++ b/ash/system/privacy/privacy_indicators_controller.cc
@@ -0,0 +1,71 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/system/privacy/privacy_indicators_controller.h" + +#include <string> + +#include "ash/public/cpp/notification_utils.h" +#include "ash/resources/vector_icons/vector_icons.h" +#include "ash/strings/grit/ash_strings.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/message_center/message_center.h" +#include "ui/message_center/public/cpp/notification.h" +#include "ui/message_center/public/cpp/notification_types.h" + +namespace ash { + +namespace { +const char kPrivacyIndicatorsNotificationIdPrefix[] = "privacy-indicators"; +const char kPrivacyIndicatorsNotifierId[] = "ash.privacy-indicators"; +} // namespace + +void ModifyPrivacyIndicatorsNotification(const std::string& app_id, + bool camera_is_used, + bool microphone_is_used) { + auto* message_center = message_center::MessageCenter::Get(); + std::string id = kPrivacyIndicatorsNotificationIdPrefix + app_id; + bool notification_exist = message_center->FindVisibleNotificationById(id); + + if (!camera_is_used && !microphone_is_used) { + if (notification_exist) + message_center->RemoveNotification(id, /*by_user=*/false); + return; + } + + std::u16string title; + if (camera_is_used && microphone_is_used) { + title = l10n_util::GetStringUTF16( + IDS_PRIVACY_NOTIFICATION_TITLE_CAMERA_AND_MIC); + } else if (camera_is_used) { + title = l10n_util::GetStringUTF16(IDS_PRIVACY_NOTIFICATION_TITLE_CAMERA); + } else { + title = l10n_util::GetStringUTF16(IDS_PRIVACY_NOTIFICATION_TITLE_MIC); + } + + message_center::RichNotificationData optional_fields; + optional_fields.pinned = true; + // Make the notification low priority so that it is silently added (no popup). + optional_fields.priority = message_center::LOW_PRIORITY; + + auto notification = CreateSystemNotification( + message_center::NotificationType::NOTIFICATION_TYPE_SIMPLE, id, title, + std::u16string(), + /*display_source=*/std::u16string(), + /*origin_url=*/GURL(), + message_center::NotifierId(message_center::NotifierType::SYSTEM_COMPONENT, + kPrivacyIndicatorsNotifierId, + NotificationCatalogName::kPrivacyIndicators), + optional_fields, + /*delegate=*/nullptr, kImeMenuMicrophoneIcon, + message_center::SystemNotificationWarningLevel::NORMAL); + + if (notification_exist) { + message_center->UpdateNotification(id, std::move(notification)); + return; + } + message_center->AddNotification(std::move(notification)); +} + +} // namespace ash \ No newline at end of file
diff --git a/ash/system/privacy/privacy_indicators_controller.h b/ash/system/privacy/privacy_indicators_controller.h new file mode 100644 index 0000000..c3e606f5 --- /dev/null +++ b/ash/system/privacy/privacy_indicators_controller.h
@@ -0,0 +1,22 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_SYSTEM_PRIVACY_PRIVACY_INDICATORS_CONTROLLER_H_ +#define ASH_SYSTEM_PRIVACY_PRIVACY_INDICATORS_CONTROLLER_H_ + +#include <string> + +#include "ash/ash_export.h" + +namespace ash { + +// Add, update, or remove the privacy notification associated with the given +// `app_id`. +void ASH_EXPORT ModifyPrivacyIndicatorsNotification(const std::string& app_id, + bool camera_is_used, + bool microphone_is_used); + +} // namespace ash + +#endif // ASH_SYSTEM_PRIVACY_PRIVACY_INDICATORS_CONTROLLER_H_
diff --git a/ash/system/tray/tray_bubble_view.cc b/ash/system/tray/tray_bubble_view.cc index b5eabf9b..7aad2d71 100644 --- a/ash/system/tray/tray_bubble_view.cc +++ b/ash/system/tray/tray_bubble_view.cc
@@ -14,9 +14,9 @@ #include "ash/constants/ash_features.h" #include "ash/public/cpp/accelerators.h" #include "ash/public/cpp/style/color_provider.h" -#include "ash/public/cpp/view_shadow.h" #include "ash/shell.h" #include "ash/style/ash_color_id.h" +#include "ash/style/system_shadow.h" #include "ash/system/tray/tray_constants.h" #include "ash/system/unified/unified_system_tray_view.h" #include "third_party/skia/include/core/SkCanvas.h" @@ -308,8 +308,8 @@ } if (params_.has_shadow) { - shadow_ = std::make_unique<ViewShadow>(this, params_.shadow_elevation); - shadow_->shadow()->SetShadowStyle(gfx::ShadowStyle::kChromeOSSystemUI); + shadow_ = SystemShadow::CreateShadowOnNinePatchLayerForView( + this, params_.shadow_type); shadow_->SetRoundedCornerRadius(params_.corner_radius); }
diff --git a/ash/system/tray/tray_bubble_view.h b/ash/system/tray/tray_bubble_view.h index c6b4a33..5d315774 100644 --- a/ash/system/tray/tray_bubble_view.h +++ b/ash/system/tray/tray_bubble_view.h
@@ -32,7 +32,7 @@ namespace ash { -class ViewShadow; +class SystemShadow; // Specialized bubble view for bubbles associated with a tray icon (e.g. the // Ash status area). Mostly this handles custom anchor location and arrow and @@ -121,7 +121,7 @@ absl::optional<gfx::Insets> insets; absl::optional<gfx::Insets> margin; bool has_shadow = true; - int shadow_elevation = kBubbleShadowElevation; + SystemShadow::Type shadow_type = kBubbleShadowType; // Use half opaque widget instead of fully opaque. bool translucent = false; // Whether the view is fully transparent (only serves as a container). @@ -259,7 +259,7 @@ // keyboard. std::unique_ptr<EventHandler> reroute_event_handler_; - std::unique_ptr<ViewShadow> shadow_; + std::unique_ptr<SystemShadow> shadow_; absl::optional<StatusAreaWidget::ScopedTrayBubbleCounter> tray_bubble_counter_;
diff --git a/ash/system/unified/unified_system_info_view.cc b/ash/system/unified/unified_system_info_view.cc index 6bce420..301a052 100644 --- a/ash/system/unified/unified_system_info_view.cc +++ b/ash/system/unified/unified_system_info_view.cc
@@ -10,8 +10,11 @@ #include "ash/resources/vector_icons/vector_icons.h" #include "ash/session/session_controller_impl.h" #include "ash/shell.h" +#include "ash/shell_delegate.h" #include "ash/strings/grit/ash_strings.h" #include "ash/style/ash_color_provider.h" +#include "ash/system/channel_indicator/channel_indicator_quick_settings_view.h" +#include "ash/system/channel_indicator/channel_indicator_utils.h" #include "ash/system/enterprise/enterprise_domain_observer.h" #include "ash/system/model/clock_model.h" #include "ash/system/model/clock_observer.h" @@ -24,6 +27,7 @@ #include "ash/system/tray/system_tray_notifier.h" #include "ash/system/tray/tray_popup_utils.h" #include "base/bind.h" +#include "base/callback_helpers.h" #include "base/i18n/time_formatting.h" #include "base/strings/utf_string_conversions.h" #include "base/time/time.h" @@ -260,7 +264,7 @@ auto seperator = std::make_unique<views::Label>(); seperator->SetText(l10n_util::GetStringUTF16( IDS_ASH_STATUS_TRAY_BATTERY_STATUS_SEPARATOR)); - separator_ = AddChildView(std::move(seperator)); + separator_view_ = AddChildView(std::move(seperator)); status_ = AddChildView(std::make_unique<views::Label>()); Update(); } @@ -275,7 +279,7 @@ const auto color = GetContentLayerColor(ContentLayerType::kTextColorSecondary); ConfigureLabel(percentage_, color); - ConfigureLabel(separator_, color); + ConfigureLabel(separator_view_, color); ConfigureLabel(status_, color); } @@ -291,8 +295,9 @@ percentage_->SetVisible(!percentage_text.empty() && !use_smart_charging_ui_); - separator_->SetVisible(!percentage_text.empty() && - !use_smart_charging_ui_ && !status_text.empty()); + separator_view_->SetVisible(!percentage_text.empty() && + !use_smart_charging_ui_ && + !status_text.empty()); status_->SetVisible(!status_text.empty()); percentage_->NotifyAccessibilityEvent(ax::mojom::Event::kTextChanged, true); @@ -300,7 +305,7 @@ } views::Label* percentage_ = nullptr; - views::Label* separator_ = nullptr; + views::Label* separator_view_ = nullptr; views::Label* status_ = nullptr; const bool use_smart_charging_ui_; @@ -585,34 +590,88 @@ } // namespace +// A view that contains date, battery status, and whether the device +// is enterprise managed. +class ManagementPowerDateComboView : public views::View { + public: + explicit ManagementPowerDateComboView( + UnifiedSystemTrayController* controller) { + auto* layout = SetLayoutManager(std::make_unique<views::BoxLayout>( + views::BoxLayout::Orientation::kHorizontal, + kUnifiedSystemInfoViewPadding, kUnifiedSystemInfoSpacing)); + layout->set_cross_axis_alignment( + views::BoxLayout::CrossAxisAlignment::kCenter); + AddChildView(std::make_unique<DateView>(controller)); + + if (PowerStatus::Get()->IsBatteryPresent()) { + separator_view_ = AddChildView(std::make_unique<views::Separator>()); + separator_view_->SetColorId(ui::kColorAshSystemUIMenuSeparator); + separator_view_->SetPreferredLength(kUnifiedSystemInfoHeight); + + const bool use_smart_charging_ui = UseSmartChargingUI(); + if (use_smart_charging_ui) + AddChildView(std::make_unique<BatteryIconView>(controller)); + AddChildView(std::make_unique<BatteryLabelView>(controller, + use_smart_charging_ui)); + } + + auto* spacing = AddChildView(std::make_unique<views::View>()); + layout->SetFlexForView(spacing, 1); + + enterprise_managed_view_ = + AddChildView(std::make_unique<EnterpriseManagedView>(controller)); + supervised_view_ = AddChildView(std::make_unique<SupervisedUserView>()); + } + ManagementPowerDateComboView(const ManagementPowerDateComboView&) = delete; + ManagementPowerDateComboView& operator=(const ManagementPowerDateComboView&) = + delete; + ~ManagementPowerDateComboView() override = default; + + // Introspection methods for unit tests, that call into individual views. + bool IsEnterpriseManagedVisibleForTesting() { + return enterprise_managed_view_->GetVisible(); + } + + bool IsSupervisedVisibleForTesting() { + return supervised_view_->GetVisible(); + } + + private: + // Pointer to the actual child view is maintained for unit testing, owned by + // `ManagementPowerDateComboView`. + EnterpriseManagedView* enterprise_managed_view_ = nullptr; + + // Pointer to the actual child view is maintained for unit testing, owned by + // `ManagementPowerDateComboView`. + SupervisedUserView* supervised_view_ = nullptr; + + // Separator between date and battery views, owned by + // `ManagementPowerDateComboView`. + views::Separator* separator_view_ = nullptr; +}; + UnifiedSystemInfoView::UnifiedSystemInfoView( UnifiedSystemTrayController* controller) { + // Layout for the overall UnifiedSystemInfoView. auto* layout = SetLayoutManager(std::make_unique<views::BoxLayout>( - views::BoxLayout::Orientation::kHorizontal, kUnifiedSystemInfoViewPadding, + views::BoxLayout::Orientation::kVertical, kUnifiedSystemInfoViewPadding, kUnifiedSystemInfoSpacing)); layout->set_cross_axis_alignment( views::BoxLayout::CrossAxisAlignment::kCenter); - AddChildView(std::make_unique<DateView>(controller)); + // Construct a ManagementPowerDateComboView and save off a raw pointer, to + // facilitate introspection needed for unit tests. + combo_view_ = + AddChildView(std::make_unique<ManagementPowerDateComboView>(controller)); - if (PowerStatus::Get()->IsBatteryPresent()) { - separator_ = AddChildView(std::make_unique<views::Separator>()); - separator_->SetColorId(ui::kColorAshSystemUIMenuSeparator); - separator_->SetPreferredLength(kUnifiedSystemInfoHeight); - - const bool use_smart_charging_ui = UseSmartChargingUI(); - if (use_smart_charging_ui) - AddChildView(std::make_unique<BatteryIconView>(controller)); - AddChildView( - std::make_unique<BatteryLabelView>(controller, use_smart_charging_ui)); + // If the release track is not "stable" then channel indicator UI for quick + // settings is put up. + auto channel = Shell::Get()->shell_delegate()->GetChannel(); + if (features::IsReleaseTrackUiEnabled() && + channel_indicator_utils::IsDisplayableChannel(channel)) { + channel_view_ = AddChildView( + std::make_unique<ChannelIndicatorQuickSettingsView>(channel)); } - - auto* spacing = AddChildView(std::make_unique<views::View>()); - layout->SetFlexForView(spacing, 1); - - enterprise_managed_ = - AddChildView(std::make_unique<EnterpriseManagedView>(controller)); - supervised_ = AddChildView(std::make_unique<SupervisedUserView>()); } UnifiedSystemInfoView::~UnifiedSystemInfoView() = default; @@ -625,6 +684,18 @@ Layout(); } +bool UnifiedSystemInfoView::IsEnterpriseManagedVisibleForTesting() { + return combo_view_->IsEnterpriseManagedVisibleForTesting(); // IN-TEST +} + +bool UnifiedSystemInfoView::IsSupervisedVisibleForTesting() { + return combo_view_->IsSupervisedVisibleForTesting(); // IN-TEST +} + +bool UnifiedSystemInfoView::IsChannelIndicatorQuickSettingsVisibleForTesting() { + return channel_view_ && channel_view_->GetVisible(); // IN-TEST +} + BEGIN_METADATA(UnifiedSystemInfoView, views::View) END_METADATA
diff --git a/ash/system/unified/unified_system_info_view.h b/ash/system/unified/unified_system_info_view.h index db8951d5..bbbd9d62 100644 --- a/ash/system/unified/unified_system_info_view.h +++ b/ash/system/unified/unified_system_info_view.h
@@ -11,15 +11,13 @@ #include "ui/base/metadata/metadata_header_macros.h" #include "ui/views/view.h" -namespace views { -class Separator; -} // namespace views - namespace ash { +class ManagementPowerDateComboView; +class ChannelIndicatorQuickSettingsView; + // A view at the bottom of UnifiedSystemTray bubble that shows system -// information. The view contains date, battery status, and whether the device -// is enterprise managed or not. +// information. class ASH_EXPORT UnifiedSystemInfoView : public views::View { public: METADATA_HEADER(UnifiedSystemInfoView); @@ -34,6 +32,11 @@ void ChildPreferredSizeChanged(views::View* child) override; void ChildVisibilityChanged(views::View* child) override; + // Introspection methods needed for unit tests. + bool IsEnterpriseManagedVisibleForTesting(); + bool IsSupervisedVisibleForTesting(); + bool IsChannelIndicatorQuickSettingsVisibleForTesting(); + private: FRIEND_TEST_ALL_PREFIXES(UnifiedSystemInfoViewTest, EnterpriseManagedVisible); FRIEND_TEST_ALL_PREFIXES(UnifiedSystemInfoViewTest, @@ -42,14 +45,14 @@ EnterpriseUserManagedVisible); FRIEND_TEST_ALL_PREFIXES(UnifiedSystemInfoViewNoSessionTest, ChildVisible); - // EnterpriseManagedView for unit testing. Owned by this view. Null if - // kManagedDeviceUIRedesign is enabled. - views::View* enterprise_managed_ = nullptr; - // SupervisedUserView for unit testing. Owned by this view . Null if - // kManagedDeviceUIRedesign is enabled. - views::View* supervised_ = nullptr; + // Raw pointer to the combo view (owned by `UnifiedSystemInfoView`) that + // facilitates introspection needed for unit tests. + ManagementPowerDateComboView* combo_view_ = nullptr; - views::Separator* separator_ = nullptr; + // Raw pointer to the channel indicator quick settings view (owned by + // `UnifiedSystemInfoView`) that facilitates introspection needed for unit + // tests. + ChannelIndicatorQuickSettingsView* channel_view_ = nullptr; }; } // namespace ash
diff --git a/ash/system/unified/unified_system_info_view_unittest.cc b/ash/system/unified/unified_system_info_view_unittest.cc index 0c56982..bbab3af 100644 --- a/ash/system/unified/unified_system_info_view_unittest.cc +++ b/ash/system/unified/unified_system_info_view_unittest.cc
@@ -14,13 +14,47 @@ #include "ash/system/unified/unified_system_tray_controller.h" #include "ash/system/unified/unified_system_tray_model.h" #include "ash/test/ash_test_base.h" +#include "ash/test_shell_delegate.h" #include "base/memory/scoped_refptr.h" #include "base/test/scoped_feature_list.h" +#include "components/version_info/channel.h" namespace ash { -class UnifiedSystemInfoViewTest : public AshTestBase, - public testing::WithParamInterface<bool> { +// `UnifiedSystemInfoView` contains a set of "baseline" UI elements that are +// always visible, but some elements are visible only under certain conditions. +// To verify that these "conditional" UI elements are visible or not-visible +// only when expected, each `UnifiedSystemInfoViewTest` test case is executed +// with every possible combination of the following flags, passed as a +// parameter. +enum class TestFlags : uint8_t { + // No conditional UI flags are set. + kNone = 0b00000000, + + // Enterprise/management status display is enabled. + kManagedDeviceUi = 0b00000001, + + // Release track UI is visible if two conditions are met: (1) the feature that + // guards its display is enabled (kReleaseTrackUi) and (2) the release track + // itself is a value other than "stable" (kReleaseTrackNotStable). Each + // combination of one, none, or both of these conditions is a valid scenario. + kReleaseTrackUi = 0b00000010, + kReleaseTrackNotStable = 0b00000100, +}; + +TestFlags operator&(TestFlags a, TestFlags b) { + return static_cast<TestFlags>(static_cast<uint8_t>(a) & + static_cast<uint8_t>(b)); +} + +TestFlags operator|(TestFlags a, TestFlags b) { + return static_cast<TestFlags>(static_cast<uint8_t>(a) | + static_cast<uint8_t>(b)); +} + +class UnifiedSystemInfoViewTest + : public AshTestBase, + public testing::WithParamInterface<TestFlags> { public: UnifiedSystemInfoViewTest() = default; UnifiedSystemInfoViewTest(const UnifiedSystemInfoViewTest&) = delete; @@ -29,18 +63,45 @@ ~UnifiedSystemInfoViewTest() override = default; void SetUp() override { - AshTestBase::SetUp(); + // Provide our own `TestShellDelegate`, with a non-stable channel set if + // the passed-in parameter dictates. + std::unique_ptr<TestShellDelegate> shell_delegate = + std::make_unique<TestShellDelegate>(); + if (IsReleaseTrackNotStable()) + shell_delegate->set_channel(version_info::Channel::BETA); + AshTestBase::SetUp(std::move(shell_delegate)); + // Enable/disable of the two features we care about is conditional on the + // passed-in parameter. scoped_feature_list_ = std::make_unique<base::test::ScopedFeatureList>(); - scoped_feature_list_->InitWithFeatureState( - features::kManagedDeviceUIRedesign, IsManagedDeviceUIRedesignEnabled()); + std::vector<base::Feature> enabled_features, disabled_features; + if (IsManagedDeviceUIRedesignEnabled()) + enabled_features.push_back(features::kManagedDeviceUIRedesign); + else + disabled_features.push_back(features::kManagedDeviceUIRedesign); + if (IsReleaseTrackUiEnabled()) + enabled_features.push_back(features::kReleaseTrackUi); + else + disabled_features.push_back(features::kReleaseTrackUi); + scoped_feature_list_->InitWithFeatures(enabled_features, disabled_features); + // Instantiate members. model_ = base::MakeRefCounted<UnifiedSystemTrayModel>(nullptr); controller_ = std::make_unique<UnifiedSystemTrayController>(model_.get()); info_view_ = std::make_unique<UnifiedSystemInfoView>(controller_.get()); } - bool IsManagedDeviceUIRedesignEnabled() const { return GetParam(); } + bool IsManagedDeviceUIRedesignEnabled() const { + return (GetParam() & TestFlags::kManagedDeviceUi) != TestFlags::kNone; + } + + bool IsReleaseTrackUiEnabled() const { + return (GetParam() & TestFlags::kReleaseTrackUi) != TestFlags::kNone; + } + + bool IsReleaseTrackNotStable() const { + return (GetParam() & TestFlags::kReleaseTrackNotStable) != TestFlags::kNone; + } void TearDown() override { info_view_.reset(); @@ -63,14 +124,25 @@ std::unique_ptr<base::test::ScopedFeatureList> scoped_feature_list_; }; +// Execute each test case with every possible combination of `TestFlags`. INSTANTIATE_TEST_SUITE_P( All, UnifiedSystemInfoViewTest, - testing::Bool() /* IsManagedDeviceUIRedesignEnabled() */); + testing::Values(TestFlags::kNone, + TestFlags::kManagedDeviceUi, + TestFlags::kReleaseTrackUi, + TestFlags::kManagedDeviceUi | TestFlags::kReleaseTrackUi, + TestFlags::kReleaseTrackNotStable, + TestFlags::kManagedDeviceUi | + TestFlags::kReleaseTrackNotStable, + TestFlags::kReleaseTrackUi | + TestFlags::kReleaseTrackNotStable, + TestFlags::kManagedDeviceUi | TestFlags::kReleaseTrackUi | + TestFlags::kReleaseTrackNotStable)); TEST_P(UnifiedSystemInfoViewTest, EnterpriseManagedVisible) { // By default, EnterpriseManagedView is not shown. - EXPECT_FALSE(info_view()->enterprise_managed_->GetVisible()); + EXPECT_FALSE(info_view()->IsEnterpriseManagedVisibleForTesting()); // Simulate enterprise information becoming available. enterprise_domain()->SetDeviceEnterpriseInfo( @@ -78,7 +150,12 @@ ManagementDeviceMode::kChromeEnterprise}); // EnterpriseManagedView should be shown. - EXPECT_TRUE(info_view()->enterprise_managed_->GetVisible()); + EXPECT_TRUE(info_view()->IsEnterpriseManagedVisibleForTesting()); + + // If the release track UI is enabled AND the release track is non-stable, the + // ChannelIndicatorQuickSettingsView is shown. + EXPECT_EQ(IsReleaseTrackUiEnabled() && IsReleaseTrackNotStable(), + info_view()->IsChannelIndicatorQuickSettingsVisibleForTesting()); } TEST_P(UnifiedSystemInfoViewTest, EnterpriseManagedVisibleForActiveDirectory) { @@ -89,19 +166,29 @@ ManagementDeviceMode::kChromeEnterprise}); // EnterpriseManagedView should be shown. - EXPECT_TRUE(info_view()->enterprise_managed_->GetVisible()); + EXPECT_TRUE(info_view()->IsEnterpriseManagedVisibleForTesting()); + + // If the release track UI is enabled AND the release track is non-stable, the + // ChannelIndicatorQuickSettingsView is shown. + EXPECT_EQ(IsReleaseTrackUiEnabled() && IsReleaseTrackNotStable(), + info_view()->IsChannelIndicatorQuickSettingsVisibleForTesting()); } TEST_P(UnifiedSystemInfoViewTest, EnterpriseUserManagedVisible) { // By default, EnterpriseManagedView is not shown. - EXPECT_FALSE(info_view()->enterprise_managed_->GetVisible()); + EXPECT_FALSE(info_view()->IsEnterpriseManagedVisibleForTesting()); // Simulate enterprise information becoming available. enterprise_domain()->SetEnterpriseAccountDomainInfo("example.com"); // EnterpriseManagedView should be shown if the feature is enabled. EXPECT_EQ(IsManagedDeviceUIRedesignEnabled(), - info_view()->enterprise_managed_->GetVisible()); + info_view()->IsEnterpriseManagedVisibleForTesting()); + + // If the release track UI is enabled AND the release track is non-stable, the + // ChannelIndicatorQuickSettingsView is shown. + EXPECT_EQ(IsReleaseTrackUiEnabled() && IsReleaseTrackNotStable(), + info_view()->IsChannelIndicatorQuickSettingsVisibleForTesting()); } using UnifiedSystemInfoViewNoSessionTest = NoSessionAshTestBase; @@ -118,7 +205,7 @@ // Before login the supervised user view is invisible. { auto info_view = std::make_unique<UnifiedSystemInfoView>(controller.get()); - EXPECT_FALSE(info_view->supervised_->GetVisible()); + EXPECT_FALSE(info_view->IsSupervisedVisibleForTesting()); } // Simulate a supervised user logging in. @@ -133,7 +220,7 @@ // Now the supervised user view is visible. { auto info_view = std::make_unique<UnifiedSystemInfoView>(controller.get()); - EXPECT_TRUE(info_view->supervised_->GetVisible()); + EXPECT_TRUE(info_view->IsSupervisedVisibleForTesting()); } }
diff --git a/ash/test_shell_delegate.cc b/ash/test_shell_delegate.cc index 2d401a7c..0cd0493 100644 --- a/ash/test_shell_delegate.cc +++ b/ash/test_shell_delegate.cc
@@ -5,6 +5,7 @@ #include "ash/test_shell_delegate.h" #include <memory> +#include <string> #include "ash/accessibility/default_accessibility_delegate.h" #include "ash/capture_mode/test_capture_mode_delegate.h" @@ -119,4 +120,8 @@ return channel_; } +std::string TestShellDelegate::GetVersionString() { + return version_string_; +} + } // namespace ash
diff --git a/ash/test_shell_delegate.h b/ash/test_shell_delegate.h index c9c2d8b5b..fe3f6c0 100644 --- a/ash/test_shell_delegate.h +++ b/ash/test_shell_delegate.h
@@ -6,6 +6,7 @@ #define ASH_TEST_SHELL_DELEGATE_H_ #include <memory> +#include <string> #include "ash/services/multidevice_setup/public/mojom/multidevice_setup.mojom.h" #include "ash/shell_delegate.h" @@ -65,9 +66,14 @@ void OpenFeedbackPageForPersistentDesksBar() override {} void SetLastCommittedURLForWindow(const GURL& url); version_info::Channel GetChannel() override; + std::string GetVersionString() override; void set_channel(version_info::Channel channel) { channel_ = channel; } + void set_version_string(const std::string& string) { + version_string_ = string; + } + private: // True if the current top window can go back. bool can_go_back_ = true; @@ -89,6 +95,8 @@ GURL last_committed_url_ = GURL::EmptyGURL(); version_info::Channel channel_ = version_info::Channel::UNKNOWN; + + std::string version_string_; }; } // namespace ash
diff --git a/ash/webui/os_feedback_ui/resources/confirmation_page.html b/ash/webui/os_feedback_ui/resources/confirmation_page.html index 66dd084..21588eff 100644 --- a/ash/webui/os_feedback_ui/resources/confirmation_page.html +++ b/ash/webui/os_feedback_ui/resources/confirmation_page.html
@@ -5,7 +5,7 @@ cr-link-row { --cr-link-row-icon-width: 40px; - border: 1px solid; + border: 1px solid var(--cros-separator-color); border-radius: 4px; height: 64px; margin: 12px 0 0 0;
diff --git a/ash/webui/os_feedback_ui/resources/file_attachment.html b/ash/webui/os_feedback_ui/resources/file_attachment.html index 733e6e6..b7bba435 100644 --- a/ash/webui/os_feedback_ui/resources/file_attachment.html +++ b/ash/webui/os_feedback_ui/resources/file_attachment.html
@@ -61,7 +61,7 @@ #addFileLabel { background: none; border: none; - color: var(--google-blue-600); + color: var(--cros-color-prominent); font-size: 13px; font-weight: var(--feedback-medium-font-weight); line-height: 20px;
diff --git a/ash/webui/os_feedback_ui/resources/help_resources_icons.html b/ash/webui/os_feedback_ui/resources/help_resources_icons.html index 3fa438a..7010bbb9 100644 --- a/ash/webui/os_feedback_ui/resources/help_resources_icons.html +++ b/ash/webui/os_feedback_ui/resources/help_resources_icons.html
@@ -318,8 +318,7 @@ <defs> <g id="add-file"> <path fill-rule="evenodd" clip-rule="evenodd" - d="M14.6172 9.1377V11.1377H11.6172V14.1377H9.61719V11.1377H6.61719V9.1377H9.61719V6.1377H11.6172V9.1377H14.6172ZM10.6172 2.1377C6.19319 2.1377 2.61719 5.7137 2.61719 10.1377C2.61719 14.5617 6.19319 18.1377 10.6172 18.1377C15.0412 18.1377 18.6172 14.5617 18.6172 10.1377C18.6172 5.7137 15.0412 2.1377 10.6172 2.1377ZM10.6172 16.1377C7.30969 16.1377 4.61719 13.4452 4.61719 10.1377C4.61719 6.8302 7.30969 4.1377 10.6172 4.1377C13.9247 4.1377 16.6172 6.8302 16.6172 10.1377C16.6172 13.4452 13.9247 16.1377 10.6172 16.1377Z" - fill="#1A73E8"> + d="M14.6172 9.1377V11.1377H11.6172V14.1377H9.61719V11.1377H6.61719V9.1377H9.61719V6.1377H11.6172V9.1377H14.6172ZM10.6172 2.1377C6.19319 2.1377 2.61719 5.7137 2.61719 10.1377C2.61719 14.5617 6.19319 18.1377 10.6172 18.1377C15.0412 18.1377 18.6172 14.5617 18.6172 10.1377C18.6172 5.7137 15.0412 2.1377 10.6172 2.1377ZM10.6172 16.1377C7.30969 16.1377 4.61719 13.4452 4.61719 10.1377C4.61719 6.8302 7.30969 4.1377 10.6172 4.1377C13.9247 4.1377 16.6172 6.8302 16.6172 10.1377C16.6172 13.4452 13.9247 16.1377 10.6172 16.1377Z"> </g> </defs> </svg>
diff --git a/ash/webui/os_feedback_ui/resources/share_data_page.html b/ash/webui/os_feedback_ui/resources/share_data_page.html index f5fcaf45..81577e4 100644 --- a/ash/webui/os_feedback_ui/resources/share_data_page.html +++ b/ash/webui/os_feedback_ui/resources/share_data_page.html
@@ -30,7 +30,7 @@ .card-frame { align-items: center; - border: 1px solid var(--google-grey-200); + border: 1px solid var(--cros-separator-color); border-radius: 4px; display: flex; }
diff --git a/ash/wm/desks/desk_preview_view.cc b/ash/wm/desks/desk_preview_view.cc index 9545134c..63220ea 100644 --- a/ash/wm/desks/desk_preview_view.cc +++ b/ash/wm/desks/desk_preview_view.cc
@@ -261,8 +261,7 @@ desk_mirrored_contents_view_(new views::View), force_occlusion_tracker_visible_( std::make_unique<aura::WindowOcclusionTracker::ScopedForceVisible>( - mini_view->GetDeskContainer())), - shadow_(std::make_unique<SystemShadow>(kDefaultShadowType)) { + mini_view->GetDeskContainer())) { DCHECK(mini_view_); SetFocusPainter(nullptr); @@ -278,9 +277,6 @@ layer()->SetFillsBoundsOpaquely(false); layer()->SetMasksToBounds(false); - shadow_->SetRoundedCornerRadius(kCornerRadius); - layer()->Add(shadow_->layer()); - wallpaper_preview_->SetPaintToLayer(); auto* wallpaper_preview_layer = wallpaper_preview_->layer(); wallpaper_preview_layer->SetFillsBoundsOpaquely(false); @@ -288,6 +284,10 @@ wallpaper_preview_layer->SetIsFastRoundedCorner(true); AddChildView(wallpaper_preview_); + shadow_ = SystemShadow::CreateShadowOnNinePatchLayerForView( + wallpaper_preview_, kDefaultShadowType); + shadow_->SetRoundedCornerRadius(kCornerRadius); + desk_mirrored_contents_view_->SetPaintToLayer(ui::LAYER_NOT_DRAWN); ui::Layer* contents_view_layer = desk_mirrored_contents_view_->layer(); contents_view_layer->SetMasksToBounds(true); @@ -394,7 +394,6 @@ void DeskPreviewView::Layout() { const gfx::Rect bounds = GetContentsBounds(); - shadow_->SetContentBounds(bounds); wallpaper_preview_->SetBoundsRect(bounds); desk_mirrored_contents_view_->SetBoundsRect(bounds);
diff --git a/ash/wm/desks/templates/saved_desk_feedback_button.cc b/ash/wm/desks/templates/saved_desk_feedback_button.cc new file mode 100644 index 0000000..96cfb3e --- /dev/null +++ b/ash/wm/desks/templates/saved_desk_feedback_button.cc
@@ -0,0 +1,48 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/wm/desks/templates/saved_desk_feedback_button.h" + +#include "ash/style/style_util.h" +#include "ash/wm/overview/overview_constants.h" +#include "base/check.h" +#include "ui/views/controls/focus_ring.h" + +namespace ash { + +FeedbackButton::FeedbackButton(base::RepeatingClosure callback, + const std::u16string& text, + Type type, + const gfx::VectorIcon* icon) + : PillButton(callback, text, type, icon), callback_(callback) { + views::FocusRing* focus_ring = + StyleUtil::SetUpFocusRingForView(this, kFocusRingHaloInset); + focus_ring->SetHasFocusPredicate([](views::View* view) { + return static_cast<FeedbackButton*>(view)->IsViewHighlighted(); + }); + focus_ring->SetColorId(ui::kColorAshFocusRing); +} + +FeedbackButton::~FeedbackButton() = default; + +views::View* FeedbackButton::GetView() { + return this; +} + +void FeedbackButton::MaybeActivateHighlightedView() { + DCHECK(callback_); + callback_.Run(); +} + +void FeedbackButton::OnViewHighlighted() { + views::FocusRing::Get(this)->SchedulePaint(); + + ScrollViewToVisible(); +} + +void FeedbackButton::OnViewUnhighlighted() { + views::FocusRing::Get(this)->SchedulePaint(); +} + +} // namespace ash
diff --git a/ash/wm/desks/templates/saved_desk_feedback_button.h b/ash/wm/desks/templates/saved_desk_feedback_button.h new file mode 100644 index 0000000..1ada31f --- /dev/null +++ b/ash/wm/desks/templates/saved_desk_feedback_button.h
@@ -0,0 +1,38 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_WM_DESKS_TEMPLATES_SAVED_DESK_FEEDBACK_BUTTON_H_ +#define ASH_WM_DESKS_TEMPLATES_SAVED_DESK_FEEDBACK_BUTTON_H_ + +#include "ash/style/pill_button.h" +#include "ash/wm/overview/overview_highlightable_view.h" + +namespace ash { + +class ASH_EXPORT FeedbackButton : public PillButton, + public OverviewHighlightableView { + public: + FeedbackButton(base::RepeatingClosure callback, + const std::u16string& text, + Type type, + const gfx::VectorIcon* icon); + FeedbackButton(const FeedbackButton&) = delete; + FeedbackButton& operator=(const FeedbackButton&) = delete; + ~FeedbackButton() override; + + // OverviewHighlightableView: + views::View* GetView() override; + void MaybeActivateHighlightedView() override; + void MaybeCloseHighlightedView(bool primary_action) override {} + void MaybeSwapHighlightedView(bool right) override {} + void OnViewHighlighted() override; + void OnViewUnhighlighted() override; + + private: + base::RepeatingClosure callback_; +}; + +} // namespace ash + +#endif // ASH_WM_DESKS_TEMPLATES_SAVED_DESK_FEEDBACK_BUTTON_H_
diff --git a/ash/wm/desks/templates/saved_desk_library_view.cc b/ash/wm/desks/templates/saved_desk_library_view.cc index acfb063..68ecd9dc 100644 --- a/ash/wm/desks/templates/saved_desk_library_view.cc +++ b/ash/wm/desks/templates/saved_desk_library_view.cc
@@ -279,12 +279,13 @@ grid_views_.push_back(save_and_recall_grid_view_); } - feedback_button_ = scroll_contents->AddChildView(std::make_unique<PillButton>( - base::BindRepeating(&SavedDeskLibraryView::OnFeedbackButtonPressed, - base::Unretained(this)), - l10n_util::GetStringUTF16( - IDS_ASH_PERSISTENT_DESKS_BAR_CONTEXT_MENU_FEEDBACK), - PillButton::Type::kIcon, &kPersistentDesksBarFeedbackIcon)); + feedback_button_ = + scroll_contents->AddChildView(std::make_unique<FeedbackButton>( + base::BindRepeating(&SavedDeskLibraryView::OnFeedbackButtonPressed, + base::Unretained(this)), + l10n_util::GetStringUTF16( + IDS_ASH_PERSISTENT_DESKS_BAR_CONTEXT_MENU_FEEDBACK), + PillButton::Type::kIcon, &kPersistentDesksBarFeedbackIcon)); feedback_button_->SetBorder(std::make_unique<views::HighlightBorder>( feedback_button_->CalculatePreferredSize().height() / 2, views::HighlightBorder::Type::kHighlightBorder1,
diff --git a/ash/wm/desks/templates/saved_desk_library_view.h b/ash/wm/desks/templates/saved_desk_library_view.h index 0ce8f35..477b0c7 100644 --- a/ash/wm/desks/templates/saved_desk_library_view.h +++ b/ash/wm/desks/templates/saved_desk_library_view.h
@@ -9,11 +9,11 @@ #include <string> #include <vector> +#include "ash/wm/desks/templates/saved_desk_feedback_button.h" #include "base/guid.h" #include "ui/aura/window_observer.h" #include "ui/base/metadata/metadata_header_macros.h" #include "ui/events/event.h" -#include "ui/views/animation/bounds_animator.h" #include "ui/views/controls/label.h" #include "ui/views/controls/scroll_view.h" #include "ui/views/view.h" @@ -22,7 +22,6 @@ namespace ash { class DeskTemplate; -class PillButton; class SavedDeskGridView; class SavedDeskItemView; class SavedDeskLibraryEventHandler; @@ -48,6 +47,8 @@ const std::vector<SavedDeskGridView*>& grid_views() { return grid_views_; } + FeedbackButton* feedback_button() { return feedback_button_; } + // Retrieve the item view for a given saved desk, or nullptr. SavedDeskItemView* GetItemForUUID(const base::GUID& uuid); @@ -113,7 +114,7 @@ // Owned by views hierarchy. Temporary button to help users give feedback. // TODO(crbug.com/1289880): Remove this button when it is no longer needed. - PillButton* feedback_button_ = nullptr; + FeedbackButton* feedback_button_ = nullptr; // Label that shows up when the library has no items. views::Label* no_items_label_ = nullptr;
diff --git a/ash/wm/desks/templates/saved_desk_test_util.cc b/ash/wm/desks/templates/saved_desk_test_util.cc index 447b9e1..b002b9e 100644 --- a/ash/wm/desks/templates/saved_desk_test_util.cc +++ b/ash/wm/desks/templates/saved_desk_test_util.cc
@@ -9,6 +9,7 @@ #include "ash/wm/desks/desks_bar_view.h" #include "ash/wm/desks/expanded_desks_bar_button.h" #include "ash/wm/desks/templates/saved_desk_dialog_controller.h" +#include "ash/wm/desks/templates/saved_desk_feedback_button.h" #include "ash/wm/desks/templates/saved_desk_item_view.h" #include "ash/wm/desks/templates/saved_desk_library_view.h" #include "ash/wm/desks/templates/saved_desk_presenter.h" @@ -218,6 +219,15 @@ return dialog_widget->widget_delegate()->AsDialogDelegate()->GetOkButton(); } +FeedbackButton* GetSavedDeskFeedbackButton() { + const auto* overview_grid = GetPrimaryOverviewGrid(); + if (!overview_grid) + return nullptr; + auto* saved_desk_library_view = overview_grid->GetSavedDeskLibraryView(); + return saved_desk_library_view ? saved_desk_library_view->feedback_button() + : nullptr; +} + void WaitForDesksTemplatesUI() { auto* overview_session = GetOverviewSession(); DCHECK(overview_session);
diff --git a/ash/wm/desks/templates/saved_desk_test_util.h b/ash/wm/desks/templates/saved_desk_test_util.h index 3ead912..c262711 100644 --- a/ash/wm/desks/templates/saved_desk_test_util.h +++ b/ash/wm/desks/templates/saved_desk_test_util.h
@@ -8,6 +8,7 @@ #include <vector> #include "ash/public/cpp/desk_template.h" +#include "ash/wm/desks/templates/saved_desk_feedback_button.h" #include "ash/wm/desks/templates/saved_desk_grid_view.h" #include "ash/wm/desks/templates/saved_desk_icon_container.h" #include "ash/wm/desks/templates/saved_desk_icon_view.h" @@ -165,6 +166,7 @@ views::Button* GetTemplateItemButton(int index); views::Button* GetTemplateItemDeleteButton(int index); views::Button* GetSavedDeskDialogAcceptButton(); +FeedbackButton* GetSavedDeskFeedbackButton(); // A lot of the UI relies on calling into the local desk data manager to // update, which sends callbacks via posting tasks. Call
diff --git a/ash/wm/desks/templates/saved_desk_unittest.cc b/ash/wm/desks/templates/saved_desk_unittest.cc index 39e63519..6ef9b92 100644 --- a/ash/wm/desks/templates/saved_desk_unittest.cc +++ b/ash/wm/desks/templates/saved_desk_unittest.cc
@@ -3793,18 +3793,25 @@ for (size_t i = 0; i < 12; i++) { SavedDeskItemView* item_view = GetItemViewFromTemplatesGrid(i); - // Verify item view is fully visible. + // Verify item view is highlighted and fully visible. SendKey(ui::VKEY_TAB); EXPECT_TRUE(item_view->IsViewHighlighted()); EXPECT_EQ(item_view->GetPreferredSize(), item_view->GetVisibleBounds().size()); - // Verify name view is fully visible. + // Verify name view is highlighted and fully visible. SendKey(ui::VKEY_TAB); EXPECT_TRUE(item_view->name_view()->IsViewHighlighted()); EXPECT_EQ(item_view->name_view()->GetPreferredSize(), item_view->name_view()->GetVisibleBounds().size()); } + + // Verify feedback button is highlighted and fully visible. + FeedbackButton* feedback_button = GetSavedDeskFeedbackButton(); + SendKey(ui::VKEY_TAB); + EXPECT_TRUE(feedback_button->IsViewHighlighted()); + EXPECT_EQ(feedback_button->GetPreferredSize(), + feedback_button->GetVisibleBounds().size()); } // Tests that the scroll bar works with the keyboard.
diff --git a/ash/wm/overview/overview_highlight_controller.cc b/ash/wm/overview/overview_highlight_controller.cc index b2396b1e0..61b8cd0 100644 --- a/ash/wm/overview/overview_highlight_controller.cc +++ b/ash/wm/overview/overview_highlight_controller.cc
@@ -240,6 +240,7 @@ traversable_views.push_back(name_view); } } + traversable_views.push_back(desk_library_view->feedback_button()); } else { for (auto& item : grid->window_list()) traversable_views.push_back(item->overview_item_view());
diff --git a/ash/wm/overview/overview_item.cc b/ash/wm/overview/overview_item.cc index b138f224..116aa2b5 100644 --- a/ash/wm/overview/overview_item.cc +++ b/ash/wm/overview/overview_item.cc
@@ -699,7 +699,7 @@ transform_window_.IsMinimized() ? std::make_unique<DragWindowController>( item_widget_->GetNativeWindow(), is_touch_dragging, - absl::make_optional(shadow_->content_bounds())) + absl::make_optional(shadow_->GetContentBounds())) : std::make_unique<DragWindowController>(GetWindow(), is_touch_dragging); } @@ -720,11 +720,11 @@ return; if (!bounds_in_screen) { - shadow_->layer()->SetVisible(false); + shadow_->GetLayer()->SetVisible(false); return; } - shadow_->layer()->SetVisible(true); + shadow_->GetLayer()->SetVisible(true); gfx::Rect bounds_in_item = gfx::Rect(item_widget_->GetNativeWindow()->GetTargetBounds().size()); bounds_in_item.Inset(gfx::Insets::TLBR(kHeaderHeightDp, 0, 0, 0)); @@ -1073,10 +1073,10 @@ } gfx::Rect OverviewItem::GetShadowBoundsForTesting() { - if (!shadow_ || !shadow_->layer()->visible()) + if (!shadow_ || !shadow_->GetLayer()->visible()) return gfx::Rect(); - return shadow_->content_bounds(); + return shadow_->GetContentBounds(); } gfx::RectF OverviewItem::GetWindowTargetBoundsWithInsets() const { @@ -1266,8 +1266,11 @@ aura::Window* widget_window = item_widget_->GetNativeWindow(); widget_window->parent()->StackChildBelow(widget_window, GetWindow()); - shadow_ = std::make_unique<SystemShadow>(kDefaultShadowType); - item_widget_->GetLayer()->Add(shadow_->layer()); + shadow_ = SystemShadow::CreateShadowOnNinePatchLayer(kDefaultShadowType); + auto* shadow_layer = shadow_->GetLayer(); + auto* widget_layer = item_widget_->GetLayer(); + widget_layer->Add(shadow_layer); + widget_layer->StackAtBottom(shadow_layer); overview_item_view_ = item_widget_->SetContentsView(std::make_unique<OverviewItemView>( @@ -1277,7 +1280,7 @@ GetWindow(), transform_window_.IsMinimized())); item_widget_->Show(); item_widget_->SetOpacity(0.f); - item_widget_->GetLayer()->SetMasksToBounds(false); + widget_layer->SetMasksToBounds(false); } void OverviewItem::UpdateHeaderLayout(OverviewAnimationType animation_type) {
diff --git a/base/allocator/allocator_shim_default_dispatch_to_partition_alloc.cc b/base/allocator/allocator_shim_default_dispatch_to_partition_alloc.cc index 65402ef1..3a34f62 100644 --- a/base/allocator/allocator_shim_default_dispatch_to_partition_alloc.cc +++ b/base/allocator/allocator_shim_default_dispatch_to_partition_alloc.cc
@@ -27,6 +27,7 @@ #include "base/feature_list.h" #include "base/memory/nonscannable_memory.h" #include "base/numerics/checked_math.h" +#include "base/numerics/safe_conversions.h" #include "base/threading/platform_thread.h" #include "build/build_config.h" #include "build/chromecast_buildflags.h" @@ -764,20 +765,23 @@ info.arena = 0; // Memory *not* allocated with mmap(). // Memory allocated with mmap(), aka virtual size. - info.hblks = allocator_dumper.stats().total_mmapped_bytes + - aligned_allocator_dumper.stats().total_mmapped_bytes + - nonscannable_allocator_dumper.stats().total_mmapped_bytes + - nonquarantinable_allocator_dumper.stats().total_mmapped_bytes; + info.hblks = base::checked_cast<decltype(info.hblks)>( + allocator_dumper.stats().total_mmapped_bytes + + aligned_allocator_dumper.stats().total_mmapped_bytes + + nonscannable_allocator_dumper.stats().total_mmapped_bytes + + nonquarantinable_allocator_dumper.stats().total_mmapped_bytes); // Resident bytes. - info.hblkhd = allocator_dumper.stats().total_resident_bytes + - aligned_allocator_dumper.stats().total_resident_bytes + - nonscannable_allocator_dumper.stats().total_resident_bytes + - nonquarantinable_allocator_dumper.stats().total_resident_bytes; + info.hblkhd = base::checked_cast<decltype(info.hblkhd)>( + allocator_dumper.stats().total_resident_bytes + + aligned_allocator_dumper.stats().total_resident_bytes + + nonscannable_allocator_dumper.stats().total_resident_bytes + + nonquarantinable_allocator_dumper.stats().total_resident_bytes); // Allocated bytes. - info.uordblks = allocator_dumper.stats().total_active_bytes + - aligned_allocator_dumper.stats().total_active_bytes + - nonscannable_allocator_dumper.stats().total_active_bytes + - nonquarantinable_allocator_dumper.stats().total_active_bytes; + info.uordblks = base::checked_cast<decltype(info.uordblks)>( + allocator_dumper.stats().total_active_bytes + + aligned_allocator_dumper.stats().total_active_bytes + + nonscannable_allocator_dumper.stats().total_active_bytes + + nonquarantinable_allocator_dumper.stats().total_active_bytes); return info; }
diff --git a/base/allocator/partition_allocator/partition_root.h b/base/allocator/partition_allocator/partition_root.h index 74b955c..4f3e230 100644 --- a/base/allocator/partition_allocator/partition_root.h +++ b/base/allocator/partition_allocator/partition_root.h
@@ -914,7 +914,8 @@ PartitionDirectMapMetadata<ThreadSafe>::FromSlotSpan(slot_span); size_t padding_for_alignment = metadata->direct_map_extent.padding_for_alignment; - PA_DCHECK(padding_for_alignment == (page - first_page) * PartitionPageSize()); + PA_DCHECK(padding_for_alignment == + static_cast<size_t>(page - first_page) * PartitionPageSize()); PA_DCHECK(slot_start == reservation_start + PartitionPageSize() + padding_for_alignment); #endif // BUILDFLAG(PA_DCHECK_IS_ON) @@ -987,7 +988,7 @@ PA_DCHECK(root->brp_enabled()); uintptr_t object_addr = root->SlotStartToObjectAddr(slot_start); - uintptr_t new_address = address + delta_in_bytes; + uintptr_t new_address = address + static_cast<uintptr_t>(delta_in_bytes); return object_addr <= new_address && // We use "greater than or equal" below because we want to include // pointers right past the end of an allocation.
diff --git a/base/allocator/winheap_stubs_win.cc b/base/allocator/winheap_stubs_win.cc index 2364c231..20e41c93 100644 --- a/base/allocator/winheap_stubs_win.cc +++ b/base/allocator/winheap_stubs_win.cc
@@ -17,6 +17,7 @@ #include "base/bits.h" #include "base/check_op.h" +#include "base/numerics/safe_conversions.h" namespace base { namespace allocator { @@ -122,7 +123,7 @@ // Write the prefix. AlignedPrefix* prefix = reinterpret_cast<AlignedPrefix*>(address) - 1; prefix->original_allocation_offset = - address - reinterpret_cast<uintptr_t>(ptr); + checked_cast<unsigned int>(address - reinterpret_cast<uintptr_t>(ptr)); #if DCHECK_IS_ON() prefix->magic = AlignedPrefix::kMagic; #endif // DCHECK_IS_ON()
diff --git a/base/android/java_exception_reporter.cc b/base/android/java_exception_reporter.cc index fa3a72a..a31ea324 100644 --- a/base/android/java_exception_reporter.cc +++ b/base/android/java_exception_reporter.cc
@@ -26,7 +26,8 @@ using JavaExceptionFilter = base::RepeatingCallback<bool(const JavaRef<jthrowable>&)>; -LazyInstance<JavaExceptionFilter>::Leaky g_java_exception_filter; +LazyInstance<JavaExceptionFilter>::Leaky g_java_exception_filter = + LAZY_INSTANCE_INITIALIZER; } // namespace
diff --git a/base/android/native_uma_recorder.cc b/base/android/native_uma_recorder.cc index 561d1de..81bcffc 100644 --- a/base/android/native_uma_recorder.cc +++ b/base/android/native_uma_recorder.cc
@@ -156,7 +156,7 @@ } }; -LazyInstance<HistogramCache>::Leaky g_histograms; +LazyInstance<HistogramCache>::Leaky g_histograms = LAZY_INSTANCE_INITIALIZER; struct ActionCallbackWrapper { base::ActionCallback action_callback;
diff --git a/base/android/reached_addresses_bitset.cc b/base/android/reached_addresses_bitset.cc index 599e9bb..c4a0937 100644 --- a/base/android/reached_addresses_bitset.cc +++ b/base/android/reached_addresses_bitset.cc
@@ -7,6 +7,7 @@ #include "base/android/library_loader/anchor_functions.h" #include "base/android/library_loader/anchor_functions_buildflags.h" #include "base/check_op.h" +#include "base/numerics/safe_conversions.h" namespace base { namespace android { @@ -56,8 +57,8 @@ if (address < start_address_ || address >= end_address_) return; - uint32_t offset = address - start_address_; - uint32_t offset_index = offset / kBytesGranularity; + size_t offset = static_cast<size_t>(address - start_address_); + uint32_t offset_index = checked_cast<uint32_t>(offset / kBytesGranularity); // Atomically set the corresponding bit in the array. std::atomic<uint32_t>* element = reached_ + (offset_index / kBitsPerElement); @@ -85,9 +86,9 @@ if (!((element >> j) & 1)) continue; - uint32_t offset_index = i * 32 + j; - uint32_t offset = offset_index * kBytesGranularity; - offsets.push_back(offset); + size_t offset_index = i * 32 + j; + size_t offset = offset_index * kBytesGranularity; + offsets.push_back(checked_cast<uint32_t>(offset)); } }
diff --git a/base/android/thread_instruction_count.cc b/base/android/thread_instruction_count.cc index 79db88c2..ad3797e5 100644 --- a/base/android/thread_instruction_count.cc +++ b/base/android/thread_instruction_count.cc
@@ -7,6 +7,7 @@ #include "base/check_op.h" #include "base/logging.h" #include "base/no_destructor.h" +#include "base/numerics/safe_conversions.h" #include "base/threading/thread_local_storage.h" #include <linux/perf_event.h> @@ -22,7 +23,7 @@ ThreadLocalStorage::Slot& InstructionCounterFdSlot() { static NoDestructor<ThreadLocalStorage::Slot> fd_slot([](void* fd_ptr) { - int fd = reinterpret_cast<intptr_t>(fd_ptr); + int fd = checked_cast<int>(reinterpret_cast<intptr_t>(fd_ptr)); if (fd > 0) close(fd); }); @@ -42,20 +43,20 @@ pe.exclude_kernel = 1; pe.exclude_hv = 1; - int fd = syscall(__NR_perf_event_open, &pe, thread_id, /* cpu */ -1, - /* group_fd */ -1, /* flags */ 0); + long fd = syscall(__NR_perf_event_open, &pe, thread_id, /* cpu */ -1, + /* group_fd */ -1, /* flags */ 0); if (fd < 0) { PLOG(ERROR) << "perf_event_open: omitting instruction counters"; return kPerfFdOpenFailed; } - return fd; + return checked_cast<int>(fd); } // Retrieves the active perf counter FD for the current thread, performing // lazy-initialization if necessary. int InstructionCounterFdForCurrentThread() { auto& slot = InstructionCounterFdSlot(); - int fd = reinterpret_cast<intptr_t>(slot.Get()); + int fd = checked_cast<int>(reinterpret_cast<intptr_t>(slot.Get())); if (fd == 0) { fd = OpenInstructionCounterFdForThread(0); slot.Set(reinterpret_cast<void*>(fd));
diff --git a/base/bind_internal.h b/base/bind_internal.h index a8ea7d7..f83c94c 100644 --- a/base/bind_internal.h +++ b/base/bind_internal.h
@@ -410,10 +410,11 @@ template <typename Functor, typename SFINAE> struct FunctorTraits; -// For empty callable types. -// This specialization is intended to allow binding captureless lambdas, based -// on the fact that captureless lambdas are empty while capturing lambdas are -// not. This also allows any functors as far as it's an empty class. +// For callable types. +// This specialization handles lambdas (captureless and capturing) and functors +// with a call operator. Capturing lambdas and stateful functors are explicitly +// disallowed by BindImpl(). +// // Example: // // // Captureless lambdas are allowed. @@ -430,12 +431,12 @@ // }; template <typename Functor> struct FunctorTraits<Functor, - std::enable_if_t<IsCallableObject<Functor>::value && - std::is_empty_v<Functor>>> { + std::enable_if_t<IsCallableObject<Functor>::value>> { using RunType = ExtractCallableRunType<Functor>; static constexpr bool is_method = false; static constexpr bool is_nullable = false; static constexpr bool is_callback = false; + static constexpr bool is_stateless = std::is_empty_v<Functor>; template <typename RunFunctor, typename... RunArgs> static ExtractReturnType<RunType> Invoke(RunFunctor&& functor, @@ -451,6 +452,7 @@ static constexpr bool is_method = false; static constexpr bool is_nullable = true; static constexpr bool is_callback = false; + static constexpr bool is_stateless = true; template <typename Function, typename... RunArgs> static R Invoke(Function&& function, RunArgs&&... args) { @@ -467,6 +469,7 @@ static constexpr bool is_method = false; static constexpr bool is_nullable = true; static constexpr bool is_callback = false; + static constexpr bool is_stateless = true; template <typename... RunArgs> static R Invoke(R(__stdcall* function)(Args...), RunArgs&&... args) { @@ -481,6 +484,7 @@ static constexpr bool is_method = false; static constexpr bool is_nullable = true; static constexpr bool is_callback = false; + static constexpr bool is_stateless = true; template <typename... RunArgs> static R Invoke(R(__fastcall* function)(Args...), RunArgs&&... args) { @@ -511,6 +515,7 @@ static constexpr bool is_method = false; static constexpr bool is_nullable = true; static constexpr bool is_callback = false; + static constexpr bool is_stateless = true; template <typename BlockType, typename... RunArgs> static R Invoke(BlockType&& block, RunArgs&&... args) { @@ -533,6 +538,7 @@ static constexpr bool is_method = false; static constexpr bool is_nullable = true; static constexpr bool is_callback = false; + static constexpr bool is_stateless = true; template <typename BlockType, typename... RunArgs> static R Invoke(BlockType&& block, RunArgs&&... args) { @@ -554,6 +560,7 @@ static constexpr bool is_method = true; static constexpr bool is_nullable = true; static constexpr bool is_callback = false; + static constexpr bool is_stateless = true; template <typename Method, typename ReceiverPtr, typename... RunArgs> static R Invoke(Method method, @@ -570,6 +577,7 @@ static constexpr bool is_method = true; static constexpr bool is_nullable = true; static constexpr bool is_callback = false; + static constexpr bool is_stateless = true; template <typename Method, typename ReceiverPtr, typename... RunArgs> static R Invoke(Method method, @@ -588,6 +596,7 @@ static constexpr bool is_method = true; static constexpr bool is_nullable = true; static constexpr bool is_callback = false; + static constexpr bool is_stateless = true; template <typename Method, typename ReceiverPtr, typename... RunArgs> static R Invoke(Method method, @@ -604,6 +613,7 @@ static constexpr bool is_method = true; static constexpr bool is_nullable = true; static constexpr bool is_callback = false; + static constexpr bool is_stateless = true; template <typename Method, typename ReceiverPtr, typename... RunArgs> static R Invoke(Method method, @@ -654,6 +664,7 @@ static constexpr bool is_method = false; static constexpr bool is_nullable = true; static constexpr bool is_callback = true; + static constexpr bool is_stateless = true; template <typename CallbackType, typename... RunArgs> static R Invoke(CallbackType&& callback, RunArgs&&... args) { @@ -670,6 +681,7 @@ static constexpr bool is_method = false; static constexpr bool is_nullable = true; static constexpr bool is_callback = true; + static constexpr bool is_stateless = true; template <typename CallbackType, typename... RunArgs> static R Invoke(CallbackType&& callback, RunArgs&&... args) { @@ -1270,6 +1282,10 @@ MakeUnwrappedTypeList<kIsOnce, FunctorTraits::is_method, Args&&...>; using BoundParamsList = typename Helper::BoundParamsList; static_assert( + MakeFunctorTraits<Functor>::is_stateless, + "Capturing lambdas and stateful lambdas are intentionally not supported. " + "Please use base::Bind{Once,Repeating} directly to bind arguments."); + static_assert( AssertBindArgsValidity<std::make_index_sequence<Helper::num_bounds>, BoundArgsList, UnwrappedArgsList, BoundParamsList>::ok,
diff --git a/base/bind_unittest.nc b/base/bind_unittest.nc index b8c96b4..2581596a 100644 --- a/base/bind_unittest.nc +++ b/base/bind_unittest.nc
@@ -294,7 +294,7 @@ BindRepeating(&VoidPolymorphic1<int>); } -#elif defined(NCTEST_DISALLOW_CAPTURING_LAMBDA) // [r"fatal error: implicit instantiation of undefined template 'base::internal::FunctorTraits<\(lambda at (\.\./)+base/bind_unittest.nc:[0-9]+:[0-9]+\)>'"] +#elif defined(NCTEST_DISALLOW_CAPTURING_LAMBDA) // [r"static_assert failed due to requirement 'FunctorTraits<\(lambda at [^)]+\), void>::is_stateless': Capturing lambdas and stateful lambdas are intentionally not supported\."] void WontCompile() { int i = 0, j = 0; @@ -362,7 +362,7 @@ BindRepeating(&TakesMoveOnly, std::move(x)); } -#elif defined(NCTEST_BIND_NON_EMPTY_FUNCTOR) // [r"fatal error: implicit instantiation of undefined template 'base::internal::FunctorTraits<base::NonEmptyFunctor>'"] +#elif defined(NCTEST_BIND_NON_EMPTY_FUNCTOR) // [r"static_assert failed due to requirement 'FunctorTraits<base::NonEmptyFunctor, void>::is_stateless': Capturing lambdas and stateful lambdas are intentionally not supported\."] void WontCompile() { BindRepeating(NonEmptyFunctor());
diff --git a/base/debug/stack_trace_fuchsia.cc b/base/debug/stack_trace_fuchsia.cc index 3840187..22c9e05 100644 --- a/base/debug/stack_trace_fuchsia.cc +++ b/base/debug/stack_trace_fuchsia.cc
@@ -188,7 +188,7 @@ reinterpret_cast<const char*>(next_entry.addr) + phdr.p_vaddr; segment.relative_addr = phdr.p_vaddr; segment.size = phdr.p_memsz; - segment.permission_flags = phdr.p_flags; + segment.permission_flags = static_cast<int>(phdr.p_flags); next_entry.segments[next_entry.segment_count] = std::move(segment); ++next_entry.segment_count;
diff --git a/base/files/file_posix.cc b/base/files/file_posix.cc index 76eaa7c..81ffdc2 100644 --- a/base/files/file_posix.cc +++ b/base/files/file_posix.cc
@@ -518,7 +518,7 @@ static_assert(O_RDONLY == 0, "O_RDONLY must equal zero"); - int mode = S_IRUSR | S_IWUSR; + mode_t mode = S_IRUSR | S_IWUSR; #if BUILDFLAG(IS_CHROMEOS) mode |= S_IRGRP | S_IROTH; #endif
diff --git a/base/files/file_util_posix.cc b/base/files/file_util_posix.cc index 1da777f0..7c44e03 100644 --- a/base/files/file_util_posix.cc +++ b/base/files/file_util_posix.cc
@@ -250,11 +250,11 @@ // use the base::File constructor. On Chrome OS, base::File uses a different // set of permissions than it does on other POSIX platforms. #if BUILDFLAG(IS_APPLE) - int mode = 0600 | (stat_at_use.st_mode & 0177); + mode_t mode = 0600 | (stat_at_use.st_mode & 0177); #elif BUILDFLAG(IS_CHROMEOS) - int mode = 0644; + mode_t mode = 0644; #else - int mode = 0600; + mode_t mode = 0600; #endif File outfile(open(target_path.value().c_str(), open_flags, mode)); if (!outfile.IsValid()) { @@ -962,7 +962,7 @@ stat_wrapper_t statbuf; if (File::Fstat(file->GetPlatformFile(), &statbuf) == 0 && statbuf.st_blksize > 0 && base::bits::IsPowerOfTwo(statbuf.st_blksize)) { - block_size = statbuf.st_blksize; + block_size = static_cast<blksize_t>(statbuf.st_blksize); } // Write starting at the next block boundary after the old file length.
diff --git a/base/fuchsia/mem_buffer_util.cc b/base/fuchsia/mem_buffer_util.cc index c08949b..dc430fb 100644 --- a/base/fuchsia/mem_buffer_util.cc +++ b/base/fuchsia/mem_buffer_util.cc
@@ -12,6 +12,7 @@ #include "base/files/file.h" #include "base/fuchsia/fuchsia_logging.h" +#include "base/numerics/safe_conversions.h" #include "base/strings/string_piece.h" #include "base/strings/utf_string_conversions.h" @@ -128,7 +129,7 @@ fuchsia::mem::Buffer output; output.vmo = std::move(vmo); - output.size = file.GetLength(); + output.size = checked_cast<uint64_t>(file.GetLength()); return output; }
diff --git a/base/hash/hash.cc b/base/hash/hash.cc index a00505d..debc9f9 100644 --- a/base/hash/hash.cc +++ b/base/hash/hash.cc
@@ -22,13 +22,13 @@ size_t FastHashImpl(base::span<const uint8_t> data) { // We use the updated CityHash within our namespace (not the deprecated // version from third_party/smhasher). -#if defined(ARCH_CPU_64_BITS) - return base::internal::cityhash_v111::CityHash64( - reinterpret_cast<const char*>(data.data()), data.size()); -#else - return base::internal::cityhash_v111::CityHash32( - reinterpret_cast<const char*>(data.data()), data.size()); -#endif + if constexpr (sizeof(size_t) > 4) { + return base::internal::cityhash_v111::CityHash64( + reinterpret_cast<const char*>(data.data()), data.size()); + } else { + return base::internal::cityhash_v111::CityHash32( + reinterpret_cast<const char*>(data.data()), data.size()); + } } // Implement hashing for pairs of at-most 32 bit integer values.
diff --git a/base/hash/md5_nacl.cc b/base/hash/md5_nacl.cc index 827bbbdb..7dc40b8 100644 --- a/base/hash/md5_nacl.cc +++ b/base/hash/md5_nacl.cc
@@ -267,7 +267,7 @@ std::string ret; ret.resize(32); - for (int i = 0, j = 0; i < 16; i++, j += 2) { + for (size_t i = 0, j = 0; i < 16; i++, j += 2) { uint8_t a = digest.a[i]; ret[j] = zEncode[(a >> 4) & 0xf]; ret[j + 1] = zEncode[a & 0xf];
diff --git a/base/ios/device_util.mm b/base/ios/device_util.mm index 06a8e85..b2466291 100644 --- a/base/ios/device_util.mm +++ b/base/ios/device_util.mm
@@ -17,6 +17,7 @@ #include "base/check.h" #include "base/mac/scoped_cftyperef.h" +#include "base/numerics/safe_conversions.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "base/strings/sys_string_conversions.h" @@ -169,7 +170,8 @@ dataUsingEncoding:NSUTF8StringEncoding]; unsigned char hash[CC_SHA256_DIGEST_LENGTH]; - CC_SHA256([hash_data bytes], [hash_data length], hash); + CC_SHA256([hash_data bytes], base::checked_cast<CC_LONG>([hash_data length]), + hash); CFUUIDBytes* uuid_bytes = reinterpret_cast<CFUUIDBytes*>(hash); base::ScopedCFTypeRef<CFUUIDRef> uuid_object(
diff --git a/base/ios/ns_error_util.mm b/base/ios/ns_error_util.mm index 1bff3d4d..c03ef29 100644 --- a/base/ios/ns_error_util.mm +++ b/base/ios/ns_error_util.mm
@@ -37,8 +37,8 @@ DCHECK(underlying_error); NSArray* error_chain = GetFullErrorChainForError(original_error); NSError* current_error = underlying_error; - for (NSInteger idx = error_chain.count - 1; idx >= 0; --idx) { - NSError* error = error_chain[idx]; + for (size_t idx = error_chain.count; idx > 0; --idx) { + NSError* error = error_chain[idx - 1]; scoped_nsobject<NSMutableDictionary> user_info( [error.userInfo mutableCopy]); [user_info setObject:current_error forKey:NSUnderlyingErrorKey];
diff --git a/base/ios/scoped_critical_action.h b/base/ios/scoped_critical_action.h index 00421d5..f75342e 100644 --- a/base/ios/scoped_critical_action.h +++ b/base/ios/scoped_critical_action.h
@@ -61,10 +61,10 @@ // |UIBackgroundTaskIdentifier| returned by // |beginBackgroundTaskWithName:expirationHandler:| when marking the - // beginning of a long-running background task. It is defined as an - // |unsigned int| instead of a |UIBackgroundTaskIdentifier| so this class - // can be used in .cc files. - unsigned int background_task_id_ GUARDED_BY(background_task_id_lock_); + // beginning of a long-running background task. It is defined as a uint64_t + // instead of a |UIBackgroundTaskIdentifier| so this class can be used in + // .cc files. + uint64_t background_task_id_ GUARDED_BY(background_task_id_lock_); Lock background_task_id_lock_; };
diff --git a/base/ios/scoped_critical_action.mm b/base/ios/scoped_critical_action.mm index 2e3c3c4..41f1e7cf7 100644 --- a/base/ios/scoped_critical_action.mm +++ b/base/ios/scoped_critical_action.mm
@@ -79,7 +79,8 @@ if (core->background_task_id_ == UIBackgroundTaskInvalid) { return; } - task_id = core->background_task_id_; + task_id = + static_cast<UIBackgroundTaskIdentifier>(core->background_task_id_); core->background_task_id_ = UIBackgroundTaskInvalid; }
diff --git a/base/logging.cc b/base/logging.cc index 582b9e30..827565f 100644 --- a/base/logging.cc +++ b/base/logging.cc
@@ -280,8 +280,9 @@ #if BUILDFLAG(IS_WIN) return GetTickCount(); #elif BUILDFLAG(IS_FUCHSIA) - return zx_clock_get_monotonic() / - static_cast<zx_time_t>(base::Time::kNanosecondsPerMicrosecond); + return static_cast<uint64_t>( + zx_clock_get_monotonic() / + static_cast<zx_time_t>(base::Time::kNanosecondsPerMicrosecond)); #elif BUILDFLAG(IS_APPLE) return mach_absolute_time(); #elif BUILDFLAG(IS_NACL) @@ -819,7 +820,7 @@ // Skip the final character of |str_newline|, since LogMessage() will add // a newline. const auto message = base::StringPiece(str_newline).substr(message_start_); - GetScopedFxLogger().LogMessage(file_, line_, + GetScopedFxLogger().LogMessage(file_, static_cast<uint32_t>(line_), message.substr(0, message.size() - 1), LogSeverityToFuchsiaLogSeverity(severity_)); #endif // BUILDFLAG(IS_FUCHSIA)
diff --git a/base/memory/page_size_nacl.cc b/base/memory/page_size_nacl.cc index 025ffd5..18b3f76 100644 --- a/base/memory/page_size_nacl.cc +++ b/base/memory/page_size_nacl.cc
@@ -10,7 +10,7 @@ namespace base { size_t GetPageSize() { - return getpagesize(); + return static_cast<size_t>(getpagesize()); } } // namespace base
diff --git a/base/memory/raw_ptr.h b/base/memory/raw_ptr.h index 99a4c9d..5d8c1cfd 100644 --- a/base/memory/raw_ptr.h +++ b/base/memory/raw_ptr.h
@@ -461,7 +461,7 @@ #if DCHECK_IS_ON() || BUILDFLAG(ENABLE_BACKUP_REF_PTR_SLOW_CHECKS) uintptr_t address = partition_alloc::UntagPtr(wrapped_ptr); if (IsSupportedAndNotNull(address)) - CHECK(IsValidDelta(address, delta_elems * sizeof(T))); + CHECK(IsValidDelta(address, delta_elems * static_cast<Z>(sizeof(T)))); #endif T* new_wrapped_ptr = WrapRawPtr(wrapped_ptr + delta_elems); ReleaseWrappedPtr(wrapped_ptr);
diff --git a/base/message_loop/message_pump_android.cc b/base/message_loop/message_pump_android.cc index b94d865..0d0d37e 100644 --- a/base/message_loop/message_pump_android.cc +++ b/base/message_loop/message_pump_android.cc
@@ -20,6 +20,7 @@ #include "base/check_op.h" #include "base/lazy_instance.h" #include "base/notreached.h" +#include "base/numerics/safe_conversions.h" #include "base/run_loop.h" #include "build/build_config.h" @@ -42,15 +43,15 @@ namespace { // See sys/timerfd.h -int timerfd_create(int clockid, int flags) { +long timerfd_create(int clockid, int flags) { return syscall(__NR_timerfd_create, clockid, flags); } // See sys/timerfd.h -int timerfd_settime(int ufc, - int flags, - const struct itimerspec* utmr, - struct itimerspec* otmr) { +long timerfd_settime(int ufc, + int flags, + const struct itimerspec* utmr, + struct itimerspec* otmr) { return syscall(__NR_timerfd_settime, ufc, flags, utmr, otmr); } @@ -101,7 +102,8 @@ // include timerfd.h. See comments above on __NR_timerfd_create. It looks like // they're just aliases to O_NONBLOCK and O_CLOEXEC anyways, so this should be // fine. - delayed_fd_ = timerfd_create(CLOCK_MONOTONIC, O_NONBLOCK | O_CLOEXEC); + delayed_fd_ = checked_cast<int>( + timerfd_create(CLOCK_MONOTONIC, O_NONBLOCK | O_CLOEXEC)); CHECK_NE(delayed_fd_, -1); looper_ = ALooper_prepare(0); @@ -141,7 +143,7 @@ // Clear the fd. uint64_t value; - int ret = read(delayed_fd_, &value, sizeof(value)); + long ret = read(delayed_fd_, &value, sizeof(value)); // TODO(mthiesse): Figure out how it's possible to hit EAGAIN here. // According to http://man7.org/linux/man-pages/man2/timerfd_create.2.html @@ -196,7 +198,7 @@ // should be greater than 0 since work having been scheduled is the reason // we're here. See http://man7.org/linux/man-pages/man2/eventfd.2.html uint64_t value = 0; - int ret = read(non_delayed_fd_, &value, sizeof(value)); + long ret = read(non_delayed_fd_, &value, sizeof(value)); DPCHECK(ret >= 0); DCHECK_GT(value, 0U); bool do_idle_work = value == kTryNativeWorkBeforeIdleBit; @@ -335,7 +337,7 @@ // work from being run and trigger another call to this method with // |do_idle_work| set to true. uint64_t value = do_idle_work ? kTryNativeWorkBeforeIdleBit : 1; - int ret = write(non_delayed_fd_, &value, sizeof(value)); + long ret = write(non_delayed_fd_, &value, sizeof(value)); DPCHECK(ret >= 0); } @@ -360,7 +362,7 @@ static_cast<time_t>(nanos / TimeTicks::kNanosecondsPerSecond); ts.it_value.tv_nsec = nanos % TimeTicks::kNanosecondsPerSecond; - int ret = timerfd_settime(delayed_fd_, TFD_TIMER_ABSTIME, &ts, nullptr); + long ret = timerfd_settime(delayed_fd_, TFD_TIMER_ABSTIME, &ts, nullptr); DPCHECK(ret >= 0); }
diff --git a/base/metrics/field_trial.cc b/base/metrics/field_trial.cc index 8663c18a..9fef083 100644 --- a/base/metrics/field_trial.cc +++ b/base/metrics/field_trial.cc
@@ -15,6 +15,7 @@ #include "base/metrics/field_trial_param_associator.h" #include "base/metrics/histogram_macros.h" #include "base/notreached.h" +#include "base/numerics/safe_conversions.h" #include "base/process/memory.h" #include "base/process/process_handle.h" #include "base/process/process_info.h" @@ -1238,7 +1239,8 @@ #elif BUILDFLAG(IS_FUCHSIA) static bool startup_handle_taken = false; DCHECK(!startup_handle_taken) << "Shared memory region initialized twice"; - zx::vmo scoped_handle(zx_take_startup_handle(field_trial_handle)); + zx::vmo scoped_handle( + zx_take_startup_handle(checked_cast<uint32_t>(field_trial_handle))); startup_handle_taken = true; if (!scoped_handle.is_valid()) return ReadOnlySharedMemoryRegion();
diff --git a/base/metrics/statistics_recorder.cc b/base/metrics/statistics_recorder.cc index 1f808ca..8ca2df9c 100644 --- a/base/metrics/statistics_recorder.cc +++ b/base/metrics/statistics_recorder.cc
@@ -32,7 +32,7 @@ } // namespace // static -LazyInstance<Lock>::Leaky StatisticsRecorder::lock_; +LazyInstance<Lock>::Leaky StatisticsRecorder::lock_ = LAZY_INSTANCE_INITIALIZER; // static StatisticsRecorder* StatisticsRecorder::top_ = nullptr;
diff --git a/base/os_compat_android.cc b/base/os_compat_android.cc index 854091a..8b02c40 100644 --- a/base/os_compat_android.cc +++ b/base/os_compat_android.cc
@@ -18,6 +18,7 @@ #endif #include "base/files/file.h" +#include "base/numerics/safe_conversions.h" #include "base/rand_util.h" #include "base/strings/string_piece.h" @@ -25,8 +26,8 @@ // There is no futimes() avaiable in Bionic, so we provide our own // implementation until it is there. int futimes(int fd, const struct timeval tv[2]) { - if (tv == NULL) - return syscall(__NR_utimensat, fd, NULL, NULL, 0); + if (tv == nullptr) + return base::checked_cast<int>(syscall(__NR_utimensat, fd, NULL, NULL, 0)); if (tv[0].tv_usec < 0 || tv[0].tv_usec >= 1000000 || tv[1].tv_usec < 0 || tv[1].tv_usec >= 1000000) { @@ -40,7 +41,7 @@ ts[0].tv_nsec = tv[0].tv_usec * 1000; ts[1].tv_sec = tv[1].tv_sec; ts[1].tv_nsec = tv[1].tv_usec * 1000; - return syscall(__NR_utimensat, fd, NULL, ts, 0); + return base::checked_cast<int>(syscall(__NR_utimensat, fd, NULL, ts, 0)); } #if !defined(__LP64__)
diff --git a/base/posix/unix_domain_socket.cc b/base/posix/unix_domain_socket.cc index bf2d0b13..e18e02f5 100644 --- a/base/posix/unix_domain_socket.cc +++ b/base/posix/unix_domain_socket.cc
@@ -77,12 +77,19 @@ struct cmsghdr* cmsg; msg.msg_control = control_buffer; +#if BUILDFLAG(IS_APPLE) msg.msg_controllen = checked_cast<socklen_t>(control_len); +#else + msg.msg_controllen = control_len; +#endif cmsg = CMSG_FIRSTHDR(&msg); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; - cmsg->cmsg_len = - checked_cast<socklen_t>(CMSG_LEN(sizeof(int) * fds.size())); +#if BUILDFLAG(IS_APPLE) + cmsg->cmsg_len = checked_cast<u_int>(CMSG_LEN(sizeof(int) * fds.size())); +#else + cmsg->cmsg_len = CMSG_LEN(sizeof(int) * fds.size()); +#endif memcpy(CMSG_DATA(cmsg), &fds[0], sizeof(int) * fds.size()); msg.msg_controllen = cmsg->cmsg_len; }
diff --git a/base/process/kill_fuchsia.cc b/base/process/kill_fuchsia.cc index 3fa64898..ead99f4 100644 --- a/base/process/kill_fuchsia.cc +++ b/base/process/kill_fuchsia.cc
@@ -33,7 +33,7 @@ return TERMINATION_STATUS_STILL_RUNNING; } - *exit_code = process_info.return_code; + *exit_code = static_cast<int>(process_info.return_code); switch (process_info.return_code) { case 0: return TERMINATION_STATUS_NORMAL_TERMINATION;
diff --git a/base/process/launch_fuchsia.cc b/base/process/launch_fuchsia.cc index da174cc5..50567e42 100644 --- a/base/process/launch_fuchsia.cc +++ b/base/process/launch_fuchsia.cc
@@ -61,7 +61,7 @@ ssize_t bytes_read = read(pipe_fd[0], buffer, sizeof(buffer)); if (bytes_read <= 0) break; - output->append(buffer, bytes_read); + output->append(buffer, static_cast<size_t>(bytes_read)); } close(pipe_fd[0]); @@ -114,7 +114,8 @@ zx_handle_t handle) { CHECK_LE(handles_to_transfer->size(), std::numeric_limits<uint16_t>::max()) << "Number of handles to transfer exceeds total allowed"; - uint32_t handle_id = PA_HND(PA_USER1, handles_to_transfer->size()); + auto handle_id = + static_cast<uint32_t>(PA_HND(PA_USER1, handles_to_transfer->size())); handles_to_transfer->push_back({handle_id, handle}); return handle_id; }
diff --git a/base/process/process_fuchsia.cc b/base/process/process_fuchsia.cc index e37192c..02c10fe 100644 --- a/base/process/process_fuchsia.cc +++ b/base/process/process_fuchsia.cc
@@ -266,7 +266,7 @@ } if (exit_code) - *exit_code = proc_info.return_code; + *exit_code = static_cast<int>(proc_info.return_code); return true; }
diff --git a/base/profiler/native_unwinder_win.cc b/base/profiler/native_unwinder_win.cc index 68b5e45..05ddc708 100644 --- a/base/profiler/native_unwinder_win.cc +++ b/base/profiler/native_unwinder_win.cc
@@ -58,7 +58,7 @@ return UnwindResult::kAborted; } - if (ContextPC(thread_context) == 0) + if (RegisterContextInstructionPointer(thread_context) == 0) return UnwindResult::kCompleted; // Exclusive range of expected stack pointer values after the unwind. @@ -83,9 +83,9 @@ } // Record the frame to which we just unwound. - stack->emplace_back( - ContextPC(thread_context), - module_cache()->GetModuleForAddress(ContextPC(thread_context))); + stack->emplace_back(RegisterContextInstructionPointer(thread_context), + module_cache()->GetModuleForAddress( + RegisterContextInstructionPointer(thread_context))); } NOTREACHED();
diff --git a/base/sync_socket_nacl.cc b/base/sync_socket_nacl.cc index c22d786..e3c961a 100644 --- a/base/sync_socket_nacl.cc +++ b/base/sync_socket_nacl.cc
@@ -25,12 +25,12 @@ size_t SyncSocket::Send(const void* buffer, size_t length) { const ssize_t bytes_written = write(handle(), buffer, length); - return bytes_written > 0 ? bytes_written : 0; + return bytes_written > 0 ? static_cast<size_t>(bytes_written) : 0; } size_t SyncSocket::Receive(void* buffer, size_t length) { const ssize_t bytes_read = read(handle(), buffer, length); - return bytes_read > 0 ? bytes_read : 0; + return bytes_read > 0 ? static_cast<size_t>(bytes_read) : 0; } size_t SyncSocket::ReceiveWithTimeout(void* buffer, size_t length, TimeDelta) {
diff --git a/base/system/sys_info_fuchsia.cc b/base/system/sys_info_fuchsia.cc index c555946..642510d 100644 --- a/base/system/sys_info_fuchsia.cc +++ b/base/system/sys_info_fuchsia.cc
@@ -104,7 +104,7 @@ // static int SysInfo::NumberOfProcessors() { - return zx_system_get_num_cpus(); + return static_cast<int>(zx_system_get_num_cpus()); } // static @@ -204,7 +204,7 @@ // static size_t SysInfo::VMAllocationGranularity() { - return getpagesize(); + return static_cast<size_t>(getpagesize()); } SysInfo::HardwareInfo SysInfo::GetHardwareInfoSync() {
diff --git a/base/system/sys_info_nacl.cc b/base/system/sys_info_nacl.cc index 7854d6d..3c3da24 100644 --- a/base/system/sys_info_nacl.cc +++ b/base/system/sys_info_nacl.cc
@@ -10,7 +10,7 @@ // static size_t SysInfo::VMAllocationGranularity() { - return getpagesize(); + return static_cast<size_t>(getpagesize()); } } // namespace base
diff --git a/base/time/time_exploded_posix.cc b/base/time/time_exploded_posix.cc index a2562a9..2a56a75c 100644 --- a/base/time/time_exploded_posix.cc +++ b/base/time/time_exploded_posix.cc
@@ -187,7 +187,7 @@ timestruct.tm_zone = nullptr; // not a POSIX field, so mktime/timegm ignore #endif - SysTime seconds; + int64_t seconds; // Certain exploded dates do not really exist due to daylight saving times, // and this causes mktime() to return implementation-defined values when
diff --git a/base/trace_event/cfi_backtrace_android.cc b/base/trace_event/cfi_backtrace_android.cc index 04c4afe..2539794 100644 --- a/base/trace_event/cfi_backtrace_android.cc +++ b/base/trace_event/cfi_backtrace_android.cc
@@ -9,6 +9,7 @@ #include "base/android/apk_assets.h" #include "base/android/library_loader/anchor_functions.h" +#include "build/build_config.h" #if !defined(ARCH_CPU_ARMEL) #error This file should not be built for this architecture. @@ -106,10 +107,10 @@ uint16_t cfi_data; // Return the RA offset for the current unwind row. - size_t ra_offset() const { return (cfi_data & kRAMask) << kRAShift; } + uint16_t ra_offset() const { return cfi_data & kRAMask << kRAShift; } // Returns the CFA offset for the current unwind row. - size_t cfa_offset() const { return cfi_data & kCFAMask; } + uint16_t cfa_offset() const { return cfi_data & kCFAMask; } }; static_assert( @@ -271,7 +272,7 @@ // less than the value returned by std::lower_bound(). --found; uintptr_t func_start_addr = *found; - size_t row_num = found - unw_index_function_col_; + size_t row_num = static_cast<size_t>(found - unw_index_function_col_); uint16_t index = unw_index_indices_col_[row_num]; DCHECK_LE(func_start_addr, func_addr); // If the index is CANT_UNWIND then we do not have unwind infomation for the @@ -316,7 +317,7 @@ ra_offset = cfi_row.ra_offset(); } DCHECK_NE(0u, cfi_row.addr_offset); - *cfi = {static_cast<uint16_t>(cfi_row.cfa_offset()), ra_offset}; + *cfi = {cfi_row.cfa_offset(), ra_offset}; DCHECK(cfi->cfa_offset); DCHECK(cfi->ra_offset);
diff --git a/base/trace_event/malloc_dump_provider.cc b/base/trace_event/malloc_dump_provider.cc index 69251d6..1e36f878 100644 --- a/base/trace_event/malloc_dump_provider.cc +++ b/base/trace_event/malloc_dump_provider.cc
@@ -393,8 +393,8 @@ // Still report waste, as on some platforms, PartitionAlloc doesn't capture // all of malloc()'s memory footprint. #if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) - int64_t pa_waste = static_cast<int64_t>(pa_only_resident_size) - - pa_only_allocated_objects_size; + int64_t pa_waste = static_cast<int64_t>(pa_only_resident_size - + pa_only_allocated_objects_size); waste -= pa_waste; #endif
diff --git a/base/trace_event/trace_event_impl.cc b/base/trace_event/trace_event_impl.cc index 5d9aec8..461a645 100644 --- a/base/trace_event/trace_event_impl.cc +++ b/base/trace_event/trace_event_impl.cc
@@ -56,12 +56,12 @@ void WriteDebugAnnotation(protos::pbzero::DebugAnnotation* annotation, ::base::TimeTicks ticks) { - annotation->set_uint_value(ticks.since_origin().InMilliseconds()); + annotation->set_int_value(ticks.since_origin().InMilliseconds()); } void WriteDebugAnnotation(protos::pbzero::DebugAnnotation* annotation, ::base::Time time) { - annotation->set_uint_value(time.since_origin().InMilliseconds()); + annotation->set_int_value(time.since_origin().InMilliseconds()); } } // namespace internal
diff --git a/base/trace_event/trace_log.cc b/base/trace_event/trace_log.cc index aa721f6..35b1185 100644 --- a/base/trace_event/trace_log.cc +++ b/base/trace_event/trace_log.cc
@@ -50,6 +50,7 @@ #include "build/build_config.h" #if BUILDFLAG(USE_PERFETTO_CLIENT_LIBRARY) +#include "base/numerics/safe_conversions.h" #include "base/run_loop.h" #include "base/task/thread_pool/thread_pool_instance.h" #include "base/tracing/perfetto_platform.h" @@ -904,7 +905,7 @@ if (size_limit == 0) size_limit = 200 * 1024; auto* buffer_config = perfetto_config.add_buffers(); - buffer_config->set_size_kb(size_limit); + buffer_config->set_size_kb(checked_cast<uint32_t>(size_limit)); switch (trace_config.GetTraceRecordMode()) { case base::trace_event::RECORD_UNTIL_FULL: case base::trace_event::RECORD_AS_MUCH_AS_POSSIBLE:
diff --git a/base/tracing/protos/chrome_track_event.proto b/base/tracing/protos/chrome_track_event.proto index fbaf9f9..aa15ff1a 100644 --- a/base/tracing/protos/chrome_track_event.proto +++ b/base/tracing/protos/chrome_track_event.proto
@@ -672,6 +672,7 @@ TASK_TYPE_INTERNAL_INPUT_BLOCKING = 77; TASK_TYPE_WEB_GPU = 78; TASK_TYPE_INTERNAL_POST_MESSAGE_FORWARDING = 79; + TASK_TYPE_INTERNAL_NAVIGATION_CANCELLATION = 80; } enum FrameType {
diff --git a/base/win/com_init_check_hook.cc b/base/win/com_init_check_hook.cc index 88af932a..a535dba4 100644 --- a/base/win/com_init_check_hook.cc +++ b/base/win/com_init_check_hook.cc
@@ -170,8 +170,8 @@ uint32_t dchecked_co_create_instance_address = reinterpret_cast<uint32_t>(&HookManager::DCheckedCoCreateInstance); uint32_t jmp_offset_base_address = co_create_instance_padded_address_ + 5; - structured_hotpatch_.relative_address = - dchecked_co_create_instance_address - jmp_offset_base_address; + structured_hotpatch_.relative_address = static_cast<int32_t>( + dchecked_co_create_instance_address - jmp_offset_base_address); HotpatchPlaceholderFormat format = GetHotpatchPlaceholderFormat( reinterpret_cast<const void*>(co_create_instance_padded_address_));
diff --git a/build/fuchsia/test/ffx_integration.py b/build/fuchsia/test/ffx_integration.py index 9e10cc1..8f0cb8d 100644 --- a/build/fuchsia/test/ffx_integration.py +++ b/build/fuchsia/test/ffx_integration.py
@@ -18,175 +18,6 @@ SDK_ROOT -QEMU_ARM64_CONFIG = """{ - "args": [ - "-kernel", - "{{guest.kernel_image}}", - "-initrd", - "{{guest.zbi_image}}", - "-m", - "{{device.memory.quantity}}{{ua device.memory.units}}", - "-smp", - {{! These should probably be predicated on the host CPU. }} - "4,threads=2", - {{#if guest.fvm_image}} - "-drive", "file={{guest.fvm_image}},format=raw,if=none,id=vdisk", - "-object", "iothread,id=iothread0", - "-device", "virtio-blk-pci,drive=vdisk,iothread=iothread0", - {{/if}} - {{! The QMP is an interface for issuing commands to the emulator. The - commands are sent in JSON, as are the results. The syntax for this - interface is documented at - https://github.com/qemu/qemu/blob/master/qga/qapi-schema.json. }} - "-qmp-pretty", - "unix:{{runtime.instance_directory}}/qmp,server,nowait", - {{#if (eq runtime.console "monitor")}} - "-monitor", - "stdio", - {{else}} - "-monitor", - "unix:{{runtime.instance_directory}}/monitor,server,nowait", - {{/if}} - {{#if (eq runtime.console "console")}} - "-serial", - "stdio", - {{else}} - "-serial", - "unix:{{runtime.instance_directory}}/serial,server,nowait", - {{/if}} - "-machine", - "virt-2.12", - "-machine", - "gic-version=host", - "-cpu", - "host", - "-enable-kvm", - {{#if (eq device.pointing_device "mouse")}} - "-device", - "virtio-mouse-pci", - {{/if}} - {{#if (eq device.pointing_device "touch")}} - {{#if (eq runtime.engine_type "femu")}} - "-device", - "virtio_input_multi_touch_pci_1", - {{/if}} - {{/if}} - {{#if (eq device.audio.model "none")}} - "-no-audio", - {{else}} - "-device", - "intel-hda", - "-device", - "hda-duplex", - {{/if}} - {{! Networking goes here }} - {{#if (eq host.networking "none")}} - "-nic", - "none", - "-nodefaults", - {{else}} - {{#if (eq host.networking "tap")}} - "-netdev", - "type=tap,ifname=qemu,id=net0,script=no,downscript=no", - "-device", - "virtio-net-pci,vectors=8,netdev=net0,mac={{runtime.mac_address}}", - {{else}} - {{!-- host.networking must be "user"}} - "-netdev", - "type=user,id=net0,restrict=off - {{~#each host.port_map~}} - ,hostfwd=tcp::{{this.host}}-:{{this.guest}} - {{~/each~}}", - "-device", - "virtio-net-pci,vectors=8,netdev=net0,mac={{runtime.mac_address}}", - {{/if}} - {{/if}} - {{#if runtime.headless}} - "-nographic", - {{/if}} - "-parallel", - "none", - "-vga", - "none", - "-device", - "virtio-keyboard-pci", - "-device", - "edu" - ], - "features": [ - {{! We don't bother checking for "auto" here because the Rust code - will resolve "auto" to an actual value before it resolves the - template. }} - {{#if (eq host.acceleration "hyper")}} - {{#if (eq host.os "linux")}} - "KVM", - {{else}} - "HVF", - {{/if}} - {{/if}} - {{#if (eq device.pointing_device "mouse")}} - "VirtioMouse", - {{/if}} - "VirtioInput", - "GLDirectMem", - "HostComposition", - "Vulkan", - "RefCountPipe" - ], - "kernel_args": [ - {{#if (eq host.acceleration "hyper")}} - {{#if (eq host.os "macos")}} - "kernel.page-scanner.page-table-eviction-policy=never", - {{/if}} - {{/if}} - {{#if (eq runtime.log_level "verbose")}} - "verbose", - {{/if}} - "kernel.serial=legacy", - "TERM=xterm-256color", - "kernel.entropy-mixin=42ac2452e99c1c979ebfca03bce0cbb14126e4021a6199ccfeca217999c0aaa0", - "kernel.halt-on-panic=true", - "zircon.nodename={{runtime.name}}", - "kernel.lockup-detector.critical-section-fatal-threshold-ms=0", - "kernel.lockup-detector.critical-section-threshold-ms=5000", - "kernel.lockup-detector.heartbeat-age-fatal-threshold-ms=0" - {{#each runtime.addl_kernel_args}} - ,"{{this}}" - {{/each}} - ], - "options": [ - "-metrics-collection", - {{#if (eq device.cpu.architecture "arm64")}} - "-avd-arch", "arm64", - {{/if}} - {{#unless runtime.hidpi_scaling}} - "-no-hidpi-scaling", - {{/unless}} - "-gpu", - "{{host.gpu}}", - {{#if runtime.headless}} - "-no-window", - {{else}} - "-window-size", - "{{device.screen.width}}x{{device.screen.height}}", - {{/if}} - {{#if (eq runtime.log_level "verbose")}} - "-verbose", - {{/if}} - {{#if runtime.debugger}} - "-wait-for-debugger", - {{/if}} - "-no-location-ui" - ], - "envs": { - {{#unless runtime.headless}} - "DISPLAY": "{{env "DISPLAY"}}", - {{/unless}} - "QEMU_AUDIO_DRV": "none" - } -}""" - - def get_config(name: str) -> Optional[str]: """Run a ffx config get command to retrieve the config value.""" @@ -360,15 +191,7 @@ json.dump(ast.literal_eval(qemu_arm64_meta), f) emu_command.extend(['--engine', 'qemu']) - # Use a customized config file. - with tempfile.NamedTemporaryFile(mode='w+t') as f: - f.writelines(QEMU_ARM64_CONFIG) - f.flush() - emu_command.extend(('--config', f.name)) - run_ffx_command(emu_command) - else: - run_ffx_command(emu_command) - + run_ffx_command(emu_command) return self._node_name def __exit__(self, exc_type, exc_value, traceback) -> bool:
diff --git a/build/rust/run_rs_bindings_from_cc.py b/build/rust/run_rs_bindings_from_cc.py index 6190856..c031f44df 100755 --- a/build/rust/run_rs_bindings_from_cc.py +++ b/build/rust/run_rs_bindings_from_cc.py
@@ -25,30 +25,6 @@ RS_BINDINGS_FROM_CC_EXE_PATH = os.path.join(RUST_TOOLCHAIN_DIR, "bin", "rs_bindings_from_cc") -# TODO(crbug.com/1329611): The instructions below can be moved (once -# tools/rust/package_rust.py includes Crubit binaries) into a (new) -# doc with a title like: "Developing Crubit in Chromium". - -# Instructions for manually building -# //third_party/rust-toolchain/bin/rs_bindings_from_cc: -# -# 1. Run: -# $ tools/clang/scripts/build.py \ -# --bootstrap --without-android --without-fuchsia -# -# (needed to generate third_party/llvm-bootstrap-install where -# the next step will look for LLVM/Clang libs and headers) -# -# 2. Run: -# $ tools/rust/build_crubit.py -# -# 3. Run: -# $ cp \ -# third_party/crubit/src/bazel-bin/rs_bindings_from_cc/rs_bindings_from_cc_impl \ -# third_party/rust-toolchain/rs_bindings_from_cc -# -# (note that the `_impl` suffix has been dropped from the binary name). - def format_cmdline(args): def quote_arg(x):
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc index bcd7585..916c156b 100644 --- a/cc/trees/layer_tree_host_impl_unittest.cc +++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -14819,7 +14819,13 @@ // Verify no jump. float y = CurrentScrollOffset(scrolling_layer).y(); - EXPECT_TRUE(y > 1 && y < 49); + if (features::IsImpulseScrollAnimationEnabled()) { + // Impulse scroll animation is faster than non-impulse, which results in a + // traveled distance larger than the original 50px. + EXPECT_TRUE(y > 50 && y < 100); + } else { + EXPECT_TRUE(y > 1 && y < 49); + } } TEST_P(ScrollUnifiedLayerTreeHostImplTest, ScrollAnimatedWithDelay) {
diff --git a/chrome/android/chrome_junit_test_java_sources.gni b/chrome/android/chrome_junit_test_java_sources.gni index ad8cfb8..6fd5bff0 100644 --- a/chrome/android/chrome_junit_test_java_sources.gni +++ b/chrome/android/chrome_junit_test_java_sources.gni
@@ -136,6 +136,7 @@ "junit/src/org/chromium/chrome/browser/history/HistoryUITest.java", "junit/src/org/chromium/chrome/browser/history_clusters/HistoryClustersCoordinatorTest.java", "junit/src/org/chromium/chrome/browser/history_clusters/HistoryClustersMediatorTest.java", + "junit/src/org/chromium/chrome/browser/history_clusters/HistoryClustersMetricsLoggerTest.java", "junit/src/org/chromium/chrome/browser/homepage/HomepageManagerTest.java", "junit/src/org/chromium/chrome/browser/homepage/HomepagePolicyManagerTest.java", "junit/src/org/chromium/chrome/browser/homepage/settings/HomepageSettingsUnitTest.java",
diff --git a/chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/VrShell.java b/chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/VrShell.java index c83420a..65486b8 100644 --- a/chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/VrShell.java +++ b/chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/VrShell.java
@@ -50,7 +50,6 @@ import org.chromium.chrome.browser.page_info.ChromePageInfo; import org.chromium.chrome.browser.page_info.ChromePageInfoHighlight; import org.chromium.chrome.browser.tab.EmptyTabObserver; -import org.chromium.chrome.browser.tab.RedirectHandlerTabHelper; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.TabAssociatedApp; import org.chromium.chrome.browser.tab.TabBrowserControlsConstraintsHelper; @@ -67,7 +66,6 @@ import org.chromium.chrome.browser.toolbar.ToolbarManager; import org.chromium.chrome.browser.vr.keyboard.VrInputMethodManagerWrapper; import org.chromium.components.browser_ui.widget.MenuOrKeyboardActionController; -import org.chromium.components.external_intents.RedirectHandler; import org.chromium.components.page_info.PageInfoController.OpenedFromSource; import org.chromium.content_public.browser.ImeAdapter; import org.chromium.content_public.browser.LoadUrlParams; @@ -98,7 +96,6 @@ private final VrCompositorSurfaceManager mVrCompositorSurfaceManager; private final VrShellDelegate mDelegate; private final VirtualDisplayAndroid mContentVirtualDisplay; - private final RedirectHandler mRedirectHandler; private final TabObserver mTabObserver; private final TabModelSelectorObserver mTabModelSelectorObserver; private final View.OnTouchListener mTouchListener; @@ -134,7 +131,6 @@ private boolean mReprojectedRendering; - private RedirectHandler mNonVrRedirectHandler; private UiWidgetFactory mNonVrUiWidgetFactory; private float mLastContentWidth; @@ -269,13 +265,6 @@ mNonVrUiWidgetFactory = UiWidgetFactory.getInstance(); UiWidgetFactory.setInstance(new VrUiWidgetFactory(this, mModalDialogManagerSupplier.get())); - mRedirectHandler = new RedirectHandler() { - @Override - public boolean shouldStayInApp(boolean hasExternalProtocol) { - return !hasExternalProtocol; - } - }; - mTabObserver = new EmptyTabObserver() { @Override public void onContentChanged(Tab tab) { @@ -548,16 +537,12 @@ private void initializeTabForVR() { if (mTab == null) return; - // Make sure we are not redirecting to another app, i.e. out of VR mode. - mNonVrRedirectHandler = RedirectHandlerTabHelper.swapHandlerFor(mTab, mRedirectHandler); assert mTab.getWindowAndroid() == mContentVrWindowAndroid; configWebContentsImeForVr(mTab.getWebContents()); } private void restoreTabFromVR() { if (mTab == null) return; - RedirectHandlerTabHelper.swapHandlerFor(mTab, mNonVrRedirectHandler); - mNonVrRedirectHandler = null; restoreWebContentsImeFromVr(mTab.getWebContents()); }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/InterceptNavigationDelegateTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/InterceptNavigationDelegateTest.java index 77cee83..4f7bc00e 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/InterceptNavigationDelegateTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/InterceptNavigationDelegateTest.java
@@ -211,8 +211,6 @@ Assert.assertTrue(mNavParamHistory.get(2).isExternalProtocol()); Assert.assertFalse(mNavParamHistory.get(2).isInPrimaryMainFrame()); - Assert.assertTrue( - mExternalNavParamHistory.get(2).getRedirectHandler().shouldStayInApp(true, false)); } @Test
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/history_clusters/HistoryClustersMetricsLoggerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/history_clusters/HistoryClustersMetricsLoggerTest.java new file mode 100644 index 0000000..bf77cf22 --- /dev/null +++ b/chrome/android/junit/src/org/chromium/chrome/browser/history_clusters/HistoryClustersMetricsLoggerTest.java
@@ -0,0 +1,185 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// 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.history_clusters; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.doReturn; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.robolectric.annotation.Config; + +import org.chromium.base.metrics.RecordHistogram; +import org.chromium.base.test.BaseRobolectricTestRunner; +import org.chromium.chrome.browser.history_clusters.HistoryClustersMetricsLogger.InitialState; +import org.chromium.components.search_engines.TemplateUrlService; +import org.chromium.url.GURL; +import org.chromium.url.JUnitTestGURLs; +import org.chromium.url.ShadowGURL; + +import java.util.ArrayList; + +/** Unit tests for HistoryClustersMetricsLogger. */ +@RunWith(BaseRobolectricTestRunner.class) +@Config(manifest = Config.NONE, shadows = {ShadowGURL.class}) +public class HistoryClustersMetricsLoggerTest { + @Rule + public MockitoRule mMockitoRule = MockitoJUnit.rule(); + + @Mock + private TemplateUrlService mTemplateUrlService; + + private ClusterVisit mSrpVisit; + private ClusterVisit mNonSrpVisit; + private GURL mSrpGurl; + private GURL mNonSrpGurl; + private HistoryClustersMetricsLogger mMetricsLogger; + + @Before + public void setUp() { + mSrpGurl = new GURL(JUnitTestGURLs.GOOGLE_URL_CAT); + mNonSrpGurl = new GURL(JUnitTestGURLs.EXAMPLE_URL); + mSrpVisit = new ClusterVisit(1.0F, mSrpGurl, "Title 4", "url3.com/foo", new ArrayList<>(), + new ArrayList<>(), mSrpGurl, 123L, new ArrayList<>()); + mSrpVisit.setIndexInParent(0); + mNonSrpVisit = new ClusterVisit(1.0F, mNonSrpGurl, "Title 4", "url3.com/foo", + new ArrayList<>(), new ArrayList<>(), mNonSrpGurl, 123L, new ArrayList<>()); + mNonSrpVisit.setIndexInParent(1); + doReturn(true).when(mTemplateUrlService).isLoaded(); + doReturn(true) + .when(mTemplateUrlService) + .isSearchResultsPageFromDefaultSearchProvider(mSrpGurl); + + mMetricsLogger = new HistoryClustersMetricsLogger(mTemplateUrlService); + } + + @Test + public void testDestroyBeforeInitialStateSet() { + mMetricsLogger.destroy(); + assertEquals(RecordHistogram.getHistogramTotalCountForTesting( + "History.Clusters.Actions.InitialState"), + 0); + assertEquals(RecordHistogram.getHistogramTotalCountForTesting( + "History.Clusters.Actions.FinalState.NumberLinksOpened"), + 0); + assertEquals(RecordHistogram.getHistogramTotalCountForTesting( + "History.Clusters.Actions.FinalState.NumberRelatedSearchesClicked"), + 0); + assertEquals(RecordHistogram.getHistogramTotalCountForTesting( + "History.Clusters.Actions.FinalState.NumberVisibilityToggles"), + 0); + assertEquals(RecordHistogram.getHistogramTotalCountForTesting( + "History.Clusters.Actions.FinalState.NumberIndividualVisitsDeleted"), + 0); + assertEquals(RecordHistogram.getHistogramTotalCountForTesting( + "History.Clusters.Actions.FinalState.TogglesToBasicHistory"), + 0); + assertEquals(RecordHistogram.getHistogramTotalCountForTesting( + "History.Clusters.Actions.FinalState.WasSuccessful"), + 0); + assertEquals(RecordHistogram.getHistogramTotalCountForTesting( + "History.Clusters.Actions.DidMakeQuery"), + 0); + assertEquals(RecordHistogram.getHistogramTotalCountForTesting( + "History.Clusters.Actions.NumQueries"), + 0); + } + + @Test + public void testSetInitialStateKeepsFirstValue() { + mMetricsLogger.setInitialState(InitialState.SAME_DOCUMENT); + mMetricsLogger.setInitialState(InitialState.INDIRECT_NAVIGATION); + mMetricsLogger.destroy(); + + assertEquals(RecordHistogram.getHistogramTotalCountForTesting( + "History.Clusters.Actions.InitialState"), + 1); + assertEquals(RecordHistogram.getHistogramValueCountForTesting( + "History.Clusters.Actions.InitialState", InitialState.SAME_DOCUMENT), + 1); + } + + @Test + public void testRelatedSearchesClickNoQueries() { + mMetricsLogger.setInitialState(InitialState.SAME_DOCUMENT); + mMetricsLogger.recordRelatedSearchesClick(3); + assertEquals(RecordHistogram.getHistogramValueCountForTesting( + "History.Clusters.UIActions.RelatedSearch.Clicked", 3), + 1); + + mMetricsLogger.destroy(); + assertEquals(RecordHistogram.getHistogramValueCountForTesting( + "History.Clusters.Actions.InitialState", InitialState.SAME_DOCUMENT), + 1); + assertEquals(RecordHistogram.getHistogramTotalCountForTesting( + "History.Clusters.Actions.FinalState.NumberRelatedSearchesClicked"), + 1); + assertEquals( + RecordHistogram.getHistogramValueCountForTesting( + "History.Clusters.Actions.DidMakeQuery", /* int equivalent of false */ 0), + 1); + } + + @Test + public void testVisitActions() { + mMetricsLogger.setInitialState(InitialState.INDIRECT_NAVIGATION); + mMetricsLogger.recordVisitAction( + HistoryClustersMetricsLogger.VisitAction.DELETED, mSrpVisit); + mMetricsLogger.recordVisitAction( + HistoryClustersMetricsLogger.VisitAction.CLICKED, mNonSrpVisit); + assertEquals( + RecordHistogram.getHistogramValueCountForTesting( + "History.Clusters.UIActions.Visit.Deleted", mSrpVisit.getIndexInParent()), + 1); + assertEquals(RecordHistogram.getHistogramValueCountForTesting( + "History.Clusters.UIActions.Visit.Clicked", + mNonSrpVisit.getIndexInParent()), + 1); + assertEquals(RecordHistogram.getHistogramValueCountForTesting( + "History.Clusters.UIActions.SRPVisit.Deleted", + mSrpVisit.getIndexInParent()), + 1); + assertEquals(RecordHistogram.getHistogramValueCountForTesting( + "History.Clusters.UIActions.nonSRPVisit.Clicked", + mNonSrpVisit.getIndexInParent()), + 1); + + mMetricsLogger.destroy(); + assertEquals(RecordHistogram.getHistogramValueCountForTesting( + "History.Clusters.Actions.FinalState.NumberLinksOpened", 1), + 1); + } + + @Test + public void testSuccessfulFinalState() { + mMetricsLogger.setInitialState(InitialState.INDIRECT_NAVIGATION); + mMetricsLogger.incrementQueryCount(); + mMetricsLogger.incrementQueryCount(); + mMetricsLogger.recordVisitAction( + HistoryClustersMetricsLogger.VisitAction.CLICKED, mSrpVisit); + + mMetricsLogger.destroy(); + assertEquals( + RecordHistogram.getHistogramValueCountForTesting( + "History.Clusters.Actions.InitialState", InitialState.INDIRECT_NAVIGATION), + 1); + assertEquals(RecordHistogram.getHistogramValueCountForTesting( + "History.Clusters.Actions.FinalState.WasSuccessful", + /* int equivalent of true */ 1), + 1); + assertEquals( + RecordHistogram.getHistogramValueCountForTesting( + "History.Clusters.Actions.DidMakeQuery", /* int equivalent of true */ 1), + 1); + assertEquals(RecordHistogram.getHistogramValueCountForTesting( + "History.Clusters.Actions.NumQueries", 2), + 1); + } +} \ No newline at end of file
diff --git a/chrome/android/profiles/newest.txt b/chrome/android/profiles/newest.txt index 52b0bf58..dda5ca0b 100644 --- a/chrome/android/profiles/newest.txt +++ b/chrome/android/profiles/newest.txt
@@ -1 +1 @@ -chromeos-chrome-amd64-105.0.5188.0_rc-r1-merged.afdo.bz2 +chromeos-chrome-amd64-105.0.5188.0_rc-r2-merged.afdo.bz2
diff --git a/chrome/app/android/chrome_main_delegate_android.cc b/chrome/app/android/chrome_main_delegate_android.cc index f17f1c1f..d76e0ac1 100644 --- a/chrome/app/android/chrome_main_delegate_android.cc +++ b/chrome/app/android/chrome_main_delegate_android.cc
@@ -33,12 +33,12 @@ ChromeMainDelegateAndroid::ChromeMainDelegateAndroid() = default; ChromeMainDelegateAndroid::~ChromeMainDelegateAndroid() = default; -bool ChromeMainDelegateAndroid::BasicStartupComplete(int* exit_code) { +absl::optional<int> ChromeMainDelegateAndroid::BasicStartupComplete() { TRACE_EVENT0("startup", "ChromeMainDelegateAndroid::BasicStartupComplete"); policy::android::AndroidCombinedPolicyProvider::SetShouldWaitForPolicy(true); SetChromeSpecificCommandLineFlags(); - return ChromeMainDelegate::BasicStartupComplete(exit_code); + return ChromeMainDelegate::BasicStartupComplete(); } void ChromeMainDelegateAndroid::PreSandboxStartup() {
diff --git a/chrome/app/android/chrome_main_delegate_android.h b/chrome/app/android/chrome_main_delegate_android.h index 8915ca65..cc53b51 100644 --- a/chrome/app/android/chrome_main_delegate_android.h +++ b/chrome/app/android/chrome_main_delegate_android.h
@@ -10,6 +10,7 @@ #include "chrome/app/chrome_main_delegate.h" #include "components/safe_browsing/buildflags.h" #include "content/public/browser/browser_main_runner.h" +#include "third_party/abseil-cpp/absl/types/optional.h" class MainThreadStackSamplingProfiler; @@ -26,7 +27,7 @@ ~ChromeMainDelegateAndroid() override; - bool BasicStartupComplete(int* exit_code) override; + absl::optional<int> BasicStartupComplete() override; void PreSandboxStartup() override; absl::variant<int, content::MainFunctionParams> RunProcess( const std::string& process_type,
diff --git a/chrome/app/chrome_main_delegate.cc b/chrome/app/chrome_main_delegate.cc index 2cfa8adc..1d5a70d 100644 --- a/chrome/app/chrome_main_delegate.cc +++ b/chrome/app/chrome_main_delegate.cc
@@ -585,13 +585,15 @@ ChromeMainDelegate::~ChromeMainDelegate() { } -void ChromeMainDelegate::PostEarlyInitialization(InvokedIn invoked_in) { +absl::optional<int> ChromeMainDelegate::PostEarlyInitialization( + InvokedIn invoked_in) { DCHECK(base::ThreadPoolInstance::Get()); const auto* invoked_in_browser = absl::get_if<InvokedInBrowserProcess>(&invoked_in); if (!invoked_in_browser) { CommonEarlyInitialization(); - return; + return absl::nullopt; + ; } #if BUILDFLAG(IS_WIN) @@ -703,6 +705,8 @@ #if BUILDFLAG(IS_MAC) chrome::CacheChannelInfo(); #endif + + return absl::nullopt; } bool ChromeMainDelegate::ShouldCreateFeatureList(InvokedIn invoked_in) { @@ -810,7 +814,7 @@ } #endif -bool ChromeMainDelegate::BasicStartupComplete(int* exit_code) { +absl::optional<int> ChromeMainDelegate::BasicStartupComplete() { #if BUILDFLAG(IS_CHROMEOS_ASH) ash::BootTimesRecorder::Get()->SaveChromeMainStats(); #endif @@ -844,10 +848,8 @@ #if BUILDFLAG(IS_WIN) // Browser should not be sandboxed. const bool is_browser = !command_line.HasSwitch(switches::kProcessType); - if (is_browser && IsSandboxedProcess()) { - *exit_code = chrome::RESULT_CODE_INVALID_SANDBOX_STATE; - return true; - } + if (is_browser && IsSandboxedProcess()) + return chrome::RESULT_CODE_INVALID_SANDBOX_STATE; #endif #if BUILDFLAG(IS_MAC) @@ -875,13 +877,12 @@ #if BUILDFLAG(IS_POSIX) if (HandleVersionSwitches(command_line)) { - *exit_code = 0; - return true; // Got a --version switch; exit with a success error code. + return 0; // Got a --version switch; exit with a success error code. } if (HandleCreditsSwitch(command_line)) { - *exit_code = 0; - return true; // Got a --credits switch; exit with a success error code. + return 0; // Got a --credits switch; exit with a success error code. } + // TODO(crbug.com/1052397): Revisit the macro expression once build flag // switch of lacros-chrome is complete. #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS) @@ -893,8 +894,7 @@ #if BUILDFLAG(IS_WIN) // Must do this before any other usage of command line! if (HasDeprecatedArguments(command_line.GetCommandLineString())) { - *exit_code = 1; - return true; + return 1; } // HandleVerifier detects and reports incorrect handle manipulations. It @@ -956,10 +956,10 @@ } diagnostics::DiagnosticsWriter writer(format); - *exit_code = diagnostics::DiagnosticsController::GetInstance()->Run( + int exit_code = diagnostics::DiagnosticsController::GetInstance()->Run( command_line, &writer); diagnostics::DiagnosticsController::GetInstance()->ClearResults(); - return true; + return exit_code; } #endif @@ -1008,8 +1008,7 @@ &writer); if (diagnostics_exit_code) { // Diagnostics has failed somehow, so we exit. - *exit_code = diagnostics_exit_code; - return true; + return diagnostics_exit_code; } // Now we run the actual recovery tasks. @@ -1019,8 +1018,7 @@ if (recovery_exit_code) { // Recovery has failed somehow, so we exit. - *exit_code = recovery_exit_code; - return true; + return recovery_exit_code; } } else { // Not running diagnostics or recovery. diagnostics::DiagnosticsController::GetInstance()->RecordRegularStartup(); @@ -1035,7 +1033,7 @@ // partially-initialized, which the TLS object is supposed to protect again. heap_profiling::InitTLSSlot(); - return false; + return absl::nullopt; } #if BUILDFLAG(IS_MAC) @@ -1476,7 +1474,7 @@ return chrome_content_utility_client_.get(); } -void ChromeMainDelegate::PreBrowserMain() { +absl::optional<int> ChromeMainDelegate::PreBrowserMain() { #if BUILDFLAG(IS_MAC) // Tell Cocoa to finish its initialization, which we want to do manually // instead of calling NSApplicationMain(). The primary reason is that NSAM() @@ -1499,4 +1497,7 @@ l10n_util::OverrideLocaleWithCocoaLocale(); } #endif + + // Do not interrupt startup. + return absl::nullopt; }
diff --git a/chrome/app/chrome_main_delegate.h b/chrome/app/chrome_main_delegate.h index ceade561..eb4dcf1c 100644 --- a/chrome/app/chrome_main_delegate.h +++ b/chrome/app/chrome_main_delegate.h
@@ -14,6 +14,7 @@ #include "chrome/browser/startup_data.h" #include "chrome/common/chrome_content_client.h" #include "content/public/app/content_main_delegate.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace base { class CommandLine; @@ -50,7 +51,7 @@ protected: // content::ContentMainDelegate: - bool BasicStartupComplete(int* exit_code) override; + absl::optional<int> BasicStartupComplete() override; void PreSandboxStartup() override; void SandboxInitialized(const std::string& process_type) override; absl::variant<int, content::MainFunctionParams> RunProcess( @@ -62,8 +63,8 @@ delegates) override; void ZygoteForked() override; #endif - void PreBrowserMain() override; - void PostEarlyInitialization(InvokedIn invoked_in) override; + absl::optional<int> PreBrowserMain() override; + absl::optional<int> PostEarlyInitialization(InvokedIn invoked_in) override; bool ShouldCreateFeatureList(InvokedIn invoked_in) override; #if BUILDFLAG(IS_WIN) bool ShouldHandleConsoleControlEvents() override;
diff --git a/chrome/app/settings_chromium_strings.grdp b/chrome/app/settings_chromium_strings.grdp index b6246b2..e34bdfa8 100644 --- a/chrome/app/settings_chromium_strings.grdp +++ b/chrome/app/settings_chromium_strings.grdp
@@ -309,4 +309,14 @@ <message name="IDS_SETTINGS_RESET_PROFILE_FEEDBACK" desc="Feedback label in the Reset Profile Settings dialog"> Help make Chromium better by reporting the <ph name="BEGIN_LINK"><a is="action-link" target="_blank"></ph>current settings<ph name="END_LINK"></a></ph> </message> + + <!-- Chrome Root Store --> + <if expr="chrome_root_store_supported"> + <message name="IDS_SETTINGS_CHROME_CERTIFICATES" desc="Text for manage certificates button in Privacy options"> + Certificates managed by Chromium + </message> + <message name="IDS_SETTINGS_CHROME_CERTIFICATES_DESCRIPTION" desc="Secondary, continued explanation of how to manage SSL certificates and settings in Privacy options"> + Information about how Chromium manages its root certificates + </message> + </if> </grit-part>
diff --git a/chrome/app/settings_chromium_strings_grdp/IDS_SETTINGS_CHROME_CERTIFICATES.png.sha1 b/chrome/app/settings_chromium_strings_grdp/IDS_SETTINGS_CHROME_CERTIFICATES.png.sha1 new file mode 100644 index 0000000..f0fe8b9 --- /dev/null +++ b/chrome/app/settings_chromium_strings_grdp/IDS_SETTINGS_CHROME_CERTIFICATES.png.sha1
@@ -0,0 +1 @@ +b523a80feba864c7a0e89eca7afea549b028f792 \ No newline at end of file
diff --git a/chrome/app/settings_chromium_strings_grdp/IDS_SETTINGS_CHROME_CERTIFICATES_DESCRIPTION.png.sha1 b/chrome/app/settings_chromium_strings_grdp/IDS_SETTINGS_CHROME_CERTIFICATES_DESCRIPTION.png.sha1 new file mode 100644 index 0000000..f0fe8b9 --- /dev/null +++ b/chrome/app/settings_chromium_strings_grdp/IDS_SETTINGS_CHROME_CERTIFICATES_DESCRIPTION.png.sha1
@@ -0,0 +1 @@ +b523a80feba864c7a0e89eca7afea549b028f792 \ No newline at end of file
diff --git a/chrome/app/settings_google_chrome_strings.grdp b/chrome/app/settings_google_chrome_strings.grdp index 4a59ff7..66f14847 100644 --- a/chrome/app/settings_google_chrome_strings.grdp +++ b/chrome/app/settings_google_chrome_strings.grdp
@@ -335,4 +335,14 @@ <message name="IDS_SETTINGS_RESET_PROFILE_FEEDBACK" desc="Feedback label in the Reset Profile Settings dialog"> Help make Chrome better by reporting the <ph name="BEGIN_LINK"><a is="action-link" target="_blank"></ph>current settings<ph name="END_LINK"></a></ph> </message> + + <!-- Chrome Root Store --> + <if expr="chrome_root_store_supported"> + <message name="IDS_SETTINGS_CHROME_CERTIFICATES" desc="Text for manage certificates button in Privacy options"> + Certificates managed by Chrome + </message> + <message name="IDS_SETTINGS_CHROME_CERTIFICATES_DESCRIPTION" desc="Secondary, continued explanation of how to manage SSL certificates and settings in Privacy options"> + Information about how Chrome manages its root certificates + </message> + </if> </grit-part>
diff --git a/chrome/app/settings_google_chrome_strings_grdp/IDS_SETTINGS_CHROME_CERTIFICATES.png.sha1 b/chrome/app/settings_google_chrome_strings_grdp/IDS_SETTINGS_CHROME_CERTIFICATES.png.sha1 new file mode 100644 index 0000000..945129a --- /dev/null +++ b/chrome/app/settings_google_chrome_strings_grdp/IDS_SETTINGS_CHROME_CERTIFICATES.png.sha1
@@ -0,0 +1 @@ +300b99399e90180a9fa1f4a4e493f3173e3a2709 \ No newline at end of file
diff --git a/chrome/app/settings_google_chrome_strings_grdp/IDS_SETTINGS_CHROME_CERTIFICATES_DESCRIPTION.png.sha1 b/chrome/app/settings_google_chrome_strings_grdp/IDS_SETTINGS_CHROME_CERTIFICATES_DESCRIPTION.png.sha1 new file mode 100644 index 0000000..945129a --- /dev/null +++ b/chrome/app/settings_google_chrome_strings_grdp/IDS_SETTINGS_CHROME_CERTIFICATES_DESCRIPTION.png.sha1
@@ -0,0 +1 @@ +300b99399e90180a9fa1f4a4e493f3173e3a2709 \ No newline at end of file
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp index d28f67196..e7d1137 100644 --- a/chrome/app/settings_strings.grdp +++ b/chrome/app/settings_strings.grdp
@@ -1252,6 +1252,11 @@ <message name="IDS_SETTINGS_LANGUAGES_PAGE_TITLE" desc="Name of the settings page which displays language preferences."> Languages </message> + <if expr="not chromeos_ash"> + <message name="IDS_SETTINGS_LANGUAGES_CARD_TITLE" desc="Name of the card which manages language preferences."> + Preferred languages + </message> + </if> <message name="IDS_SETTINGS_LANGUAGE_SEARCH" desc="Placeholder/label for the text input field that allows a user to filter languages."> Search languages </message> @@ -1989,6 +1994,14 @@ <message name="IDS_SETTINGS_MANAGE_CERTIFICATES_DESCRIPTION" desc="Secondary, continued explanation of how to manage SSL certificates and settings in Privacy options"> Manage HTTPS/SSL certificates and settings </message> + <if expr="chrome_root_store_supported"> + <message name="IDS_SETTINGS_MANAGE_DEVICE_CERTIFICATES" desc="Text for manage device certificates button in Privacy options"> + Manage device certificates + </message> + <message name="IDS_SETTINGS_MANAGE_DEVICE_CERTIFICATES_DESCRIPTION" desc="Secondary, continued explanation of how to manage SSL device certificates and settings in Privacy options"> + Manage HTTPS/SSL certificates on your device + </message> + </if> <message name="IDS_SETTINGS_MANAGE" desc="Text displayed on a button, which when clicked opens the Extensions subpage for managing an extension"> Manage </message>
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_LANGUAGES_CARD_TITLE.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_LANGUAGES_CARD_TITLE.png.sha1 new file mode 100644 index 0000000..cb3b34f --- /dev/null +++ b/chrome/app/settings_strings_grdp/IDS_SETTINGS_LANGUAGES_CARD_TITLE.png.sha1
@@ -0,0 +1 @@ +b2a84dd4043bcb38485b6af4eedc58e0fe44363a \ No newline at end of file
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_MANAGE_DEVICE_CERTIFICATES.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_MANAGE_DEVICE_CERTIFICATES.png.sha1 new file mode 100644 index 0000000..945129a --- /dev/null +++ b/chrome/app/settings_strings_grdp/IDS_SETTINGS_MANAGE_DEVICE_CERTIFICATES.png.sha1
@@ -0,0 +1 @@ +300b99399e90180a9fa1f4a4e493f3173e3a2709 \ No newline at end of file
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_MANAGE_DEVICE_CERTIFICATES_DESCRIPTION.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_MANAGE_DEVICE_CERTIFICATES_DESCRIPTION.png.sha1 new file mode 100644 index 0000000..945129a --- /dev/null +++ b/chrome/app/settings_strings_grdp/IDS_SETTINGS_MANAGE_DEVICE_CERTIFICATES_DESCRIPTION.png.sha1
@@ -0,0 +1 @@ +300b99399e90180a9fa1f4a4e493f3173e3a2709 \ No newline at end of file
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index eec8bd2..a285009 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -5171,6 +5171,7 @@ "//chromeos/ash/components/local_search_service/public/mojom", "//chromeos/ash/components/memory", "//chromeos/ash/services/assistant/public/cpp", + "//chromeos/ash/services/auth_factor_config", "//chromeos/ash/services/cros_healthd/public/cpp", "//chromeos/ash/services/cros_healthd/public/mojom", "//chromeos/components/onc",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index fba3bfa..0d41d74 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -5718,6 +5718,14 @@ FEATURE_VALUE_TYPE(blink::features::kZeroCopyTabCapture), }, + { + "region-capture-experimental-subtypes", + flag_descriptions::kEnableRegionCaptureExperimentalSubtypesName, + flag_descriptions::kEnableRegionCaptureExperimentalSubtypesDescription, + kOsDesktop, + FEATURE_VALUE_TYPE(blink::features::kRegionCaptureExperimentalSubtypes), + }, + #if BUILDFLAG(ENABLE_PDF) {"accessible-pdf-form", flag_descriptions::kAccessiblePDFFormName, flag_descriptions::kAccessiblePDFFormDescription, kOsDesktop,
diff --git a/chrome/browser/apps/app_service/intent_util.cc b/chrome/browser/apps/app_service/intent_util.cc index 1c5f791c..dfa9b39 100644 --- a/chrome/browser/apps/app_service/intent_util.cc +++ b/chrome/browser/apps/app_service/intent_util.cc
@@ -686,6 +686,9 @@ extras.insert(std::make_pair(kIntentExtraStartType + kIntentPrefixLength, intent->start_type.value())); } + if (!intent->extras.empty()) { + extras.insert(intent->extras.begin(), intent->extras.end()); + } return extras; } @@ -707,6 +710,9 @@ extras.insert(std::make_pair(kIntentExtraStartType + kIntentPrefixLength, intent->start_type.value())); } + if (intent->extras.has_value()) { + extras.insert(intent->extras->begin(), intent->extras->end()); + } return extras; }
diff --git a/chrome/browser/apps/app_service/publishers/arc_apps.cc b/chrome/browser/apps/app_service/publishers/arc_apps.cc index 3cd1a9e7..e9b8166 100644 --- a/chrome/browser/apps/app_service/publishers/arc_apps.cc +++ b/chrome/browser/apps/app_service/publishers/arc_apps.cc
@@ -426,7 +426,8 @@ : intent->mime_type.value(); request->urls.push_back(std::move(url_with_type)); } - if (intent->share_text.has_value() || intent->share_title.has_value()) { + if (intent->share_text.has_value() || intent->share_title.has_value() || + intent->extras.has_value()) { request->extras = apps_util::CreateArcIntentExtras(intent); } return request;
diff --git a/chrome/browser/apps/app_service/publishers/arc_apps_unittest.cc b/chrome/browser/apps/app_service/publishers/arc_apps_unittest.cc index 7193d85..3f629008 100644 --- a/chrome/browser/apps/app_service/publishers/arc_apps_unittest.cc +++ b/chrome/browser/apps/app_service/publishers/arc_apps_unittest.cc
@@ -10,6 +10,7 @@ #include "ash/components/arc/test/connection_holder_util.h" #include "ash/components/arc/test/fake_app_instance.h" #include "ash/components/arc/test/fake_file_system_instance.h" +#include "base/callback_helpers.h" #include "base/strings/string_util.h" #include "base/test/bind.h" #include "base/test/scoped_feature_list.h" @@ -21,6 +22,7 @@ #include "chrome/browser/ash/file_manager/path_util.h" #include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h" #include "chrome/browser/ui/app_list/arc/arc_app_test.h" +#include "chrome/browser/ui/app_list/arc/intent.h" #include "chrome/browser/web_applications/test/fake_web_app_provider.h" #include "chrome/browser/web_applications/test/web_app_install_test_utils.h" #include "chrome/common/chrome_features.h" @@ -520,3 +522,38 @@ ASSERT_TRUE( base::EndsWith(url_request->urls[0]->content_url.spec(), file_name)); } + +TEST_F(ArcAppsPublisherTest, LaunchAppWithIntent_ShareFilesIntent_SendsExtras) { + SetUpFileSystemInstance(); + + constexpr char kTestIntentText[] = "launch text"; + constexpr char kTestIntentTitle[] = "launch title"; + constexpr char kTestExtraKey[] = "extra_key"; + constexpr char kTestExtraValue[] = "extra_value"; + + GURL url = FileInDownloads(profile(), base::FilePath("test.jpeg")); + auto intent = apps_util::CreateShareIntentFromFiles( + {url}, {"image/jpeg"}, kTestIntentText, kTestIntentTitle); + intent->extras = {std::make_pair(kTestExtraKey, kTestExtraValue)}; + + const auto& fake_apps = arc_test()->fake_apps(); + std::string package_name = fake_apps[0]->package_name; + std::string app_id = ArcAppListPrefs::GetAppId(fake_apps[0]->package_name, + fake_apps[0]->activity); + arc_test()->app_instance()->SendRefreshAppList(fake_apps); + + app_service_proxy()->LaunchAppWithIntent( + app_id, 0, std::move(intent), apps::mojom::LaunchSource::kFromFileManager, + /*window_info=*/nullptr, base::DoNothing()); + FlushMojoCalls(); + + ASSERT_EQ(file_system_instance()->handledUrlRequests().size(), 1); + auto& url_request = file_system_instance()->handledUrlRequests()[0]; + ASSERT_EQ(url_request->action_type, arc::mojom::ActionType::SEND); + ASSERT_EQ(url_request->urls.size(), 1); + ASSERT_EQ(url_request->extras.value()[kTestExtraKey], kTestExtraValue); + ASSERT_EQ(url_request->extras.value()["android.intent.extra.TEXT"], + kTestIntentText); + ASSERT_EQ(url_request->extras.value()["android.intent.extra.SUBJECT"], + kTestIntentTitle); +}
diff --git a/chrome/browser/ash/crosapi/browser_util.cc b/chrome/browser/ash/crosapi/browser_util.cc index 6447da6..b091718 100644 --- a/chrome/browser/ash/crosapi/browser_util.cc +++ b/chrome/browser/ash/crosapi/browser_util.cc
@@ -124,10 +124,12 @@ LacrosAvailability DetermineLacrosAvailabilityFromPolicyValue( base::StringPiece policy_value) { // Users can set this switch in chrome://flags to disable the effect of the - // lacros-availability policy. + // lacros-availability policy. This should only be allows for googlers. base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); - if (command_line->HasSwitch(ash::switches::kLacrosAvailabilityIgnore)) + if (command_line->HasSwitch(ash::switches::kLacrosAvailabilityIgnore) && + IsGoogleInternal()) { return LacrosAvailability::kUserChoice; + } if (policy_value.empty()) { // Some tests call IsLacrosAllowedToBeEnabled but don't have the value set. @@ -993,8 +995,10 @@ // Note: this check needs to be consistent with the one in // DetermineLacrosAvailabilityFromPolicyValue. base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); - if (command_line->HasSwitch(ash::switches::kLacrosAvailabilityIgnore)) + if (command_line->HasSwitch(ash::switches::kLacrosAvailabilityIgnore) && + IsGoogleInternal()) { return LacrosLaunchSwitchSource::kForcedByUser; + } return GetCachedLacrosAvailability() == LacrosAvailability::kUserChoice ? LacrosLaunchSwitchSource::kPossiblySetByUser
diff --git a/chrome/browser/ash/crosapi/browser_util_unittest.cc b/chrome/browser/ash/crosapi/browser_util_unittest.cc index bb6d9a6..76b9433 100644 --- a/chrome/browser/ash/crosapi/browser_util_unittest.cc +++ b/chrome/browser/ash/crosapi/browser_util_unittest.cc
@@ -40,6 +40,7 @@ namespace crosapi { +namespace { // This implementation of RAII for LacrosAvailability is to make it easy reset // the state between runs. class ScopedLacrosAvailabilityCache { @@ -67,6 +68,16 @@ } }; +class ScopedSetLacrosEnabled { + public: + ScopedSetLacrosEnabled() { browser_util::SetLacrosEnabledForTest(true); } + ~ScopedSetLacrosEnabled() { browser_util::SetLacrosEnabledForTest(false); } + ScopedSetLacrosEnabled(const ScopedSetLacrosEnabled&) = delete; + ScopedSetLacrosEnabled& operator=(const ScopedSetLacrosEnabled&) = delete; +}; + +} // namespace + class BrowserUtilTest : public testing::Test { public: BrowserUtilTest() = default; @@ -811,14 +822,13 @@ TEST_F(BrowserUtilTest, IsAshBrowserSyncEnabled) { { - browser_util::SetLacrosEnabledForTest(false); EXPECT_FALSE(browser_util::IsLacrosEnabled()); EXPECT_TRUE(browser_util::IsAshWebBrowserEnabled()); EXPECT_TRUE(browser_util::IsAshBrowserSyncEnabled()); } { - browser_util::SetLacrosEnabledForTest(true); + ScopedSetLacrosEnabled scoped_enabled; EXPECT_TRUE(browser_util::IsLacrosEnabled()); EXPECT_TRUE(browser_util::IsAshWebBrowserEnabled()); EXPECT_TRUE(browser_util::IsAshBrowserSyncEnabled()); @@ -830,7 +840,6 @@ {chromeos::features::kLacrosOnly, chromeos::features::kLacrosPrimary, chromeos::features::kLacrosSupport}, {}); - browser_util::SetLacrosEnabledForTest(false); EXPECT_FALSE(browser_util::IsLacrosEnabled()); EXPECT_TRUE(browser_util::IsAshWebBrowserEnabled()); EXPECT_TRUE(browser_util::IsAshBrowserSyncEnabled()); @@ -842,14 +851,16 @@ {chromeos::features::kLacrosOnly, chromeos::features::kLacrosPrimary, chromeos::features::kLacrosSupport}, {}); - browser_util::SetLacrosEnabledForTest(true); + ScopedSetLacrosEnabled scoped_enabled; EXPECT_TRUE(browser_util::IsLacrosEnabled()); EXPECT_FALSE(browser_util::IsAshWebBrowserEnabled()); EXPECT_FALSE(browser_util::IsAshBrowserSyncEnabled()); } } -TEST_F(BrowserUtilTest, GetLacrosLaunchSwitchSource) { +TEST_F(BrowserUtilTest, GetLacrosLaunchSwitchSourceNonGoogle) { + AddRegularUser("user@random.com"); + // If LaunchSwitch is not set, the source is unknown. EXPECT_EQ(LacrosLaunchSwitchSource::kUnknown, browser_util::GetLacrosLaunchSwitchSource()); @@ -861,15 +872,13 @@ browser_util::GetLacrosLaunchSwitchSource()); } - // The policy can be ignored by command line flag. - // In the case, it is forced by user. Note that if the flag is set, - // LacrosAvailability is always kUserChoice. + // The policy cannot be ignored by command line flag. { ScopedLacrosAvailabilityCache cache(LacrosAvailability::kUserChoice); base::test::ScopedCommandLine cmd_line; cmd_line.GetProcessCommandLine()->AppendSwitch( ash::switches::kLacrosAvailabilityIgnore); - EXPECT_EQ(LacrosLaunchSwitchSource::kForcedByUser, + EXPECT_EQ(LacrosLaunchSwitchSource::kPossiblySetByUser, browser_util::GetLacrosLaunchSwitchSource()); } @@ -884,6 +893,65 @@ } } +TEST_F(BrowserUtilTest, GetLacrosLaunchSwitchSourceGoogle) { + AddRegularUser("user@google.com"); + + // If LaunchSwitch is not set, the source is unknown. + EXPECT_EQ(LacrosLaunchSwitchSource::kUnknown, + browser_util::GetLacrosLaunchSwitchSource()); + + // If the policy says UserChoice, lacros state may be set by user. + { + ScopedLacrosAvailabilityCache cache(LacrosAvailability::kUserChoice); + EXPECT_EQ(LacrosLaunchSwitchSource::kPossiblySetByUser, + browser_util::GetLacrosLaunchSwitchSource()); + } + + // The policy can be ignored by command line flag. + { + ScopedLacrosAvailabilityCache cache(LacrosAvailability::kUserChoice); + base::test::ScopedCommandLine cmd_line; + cmd_line.GetProcessCommandLine()->AppendSwitch( + ash::switches::kLacrosAvailabilityIgnore); + EXPECT_EQ(LacrosLaunchSwitchSource::kForcedByUser, + browser_util::GetLacrosLaunchSwitchSource()); + } +} + +// Lacros availability has no effect on non-googlers +TEST_F(BrowserUtilTest, LacrosAvailabilityIgnoreNonGoogle) { + AddRegularUser("user@random.com"); + + base::test::ScopedCommandLine cmd_line; + cmd_line.GetProcessCommandLine()->AppendSwitch( + ash::switches::kLacrosAvailabilityIgnore); + ScopedLacrosAvailabilityCache cache(LacrosAvailability::kLacrosDisallowed); + EXPECT_FALSE(browser_util::IsLacrosAllowedToBeEnabled()); +} + +// Lacros availability has an effect on googlers +TEST_F(BrowserUtilTest, LacrosAvailabilityIgnoreGoogleDisableToUserChoice) { + AddRegularUser("user@google.com"); + + base::test::ScopedCommandLine cmd_line; + cmd_line.GetProcessCommandLine()->AppendSwitch( + ash::switches::kLacrosAvailabilityIgnore); + ScopedLacrosAvailabilityCache cache(LacrosAvailability::kLacrosDisallowed); + EXPECT_TRUE(browser_util::IsLacrosAllowedToBeEnabled()); +} + +// Lacros availability has an effect on googlers +TEST_F(BrowserUtilTest, LacrosAvailabilityIgnoreGoogleEnableToUserChoice) { + AddRegularUser("user@google.com"); + + base::test::ScopedCommandLine cmd_line; + cmd_line.GetProcessCommandLine()->AppendSwitch( + ash::switches::kLacrosAvailabilityIgnore); + ScopedLacrosAvailabilityCache cache(LacrosAvailability::kLacrosOnly); + EXPECT_TRUE(browser_util::IsLacrosAllowedToBeEnabled()); + EXPECT_FALSE(browser_util::IsLacrosEnabled()); +} + // Check that the exist configurations used for the Google rollout have the // precisely intended side-effects. TEST_F(BrowserUtilTest, LacrosGoogleRolloutUserChoice) {
diff --git a/chrome/browser/ash/web_applications/media_app/chrome_media_app_ui_delegate.cc b/chrome/browser/ash/web_applications/media_app/chrome_media_app_ui_delegate.cc index 7cebbb5..96a2814 100644 --- a/chrome/browser/ash/web_applications/media_app/chrome_media_app_ui_delegate.cc +++ b/chrome/browser/ash/web_applications/media_app/chrome_media_app_ui_delegate.cc
@@ -10,6 +10,7 @@ #include "ash/webui/media_app_ui/file_system_access_helpers.h" #include "ash/webui/media_app_ui/url_constants.h" #include "base/bind.h" +#include "base/containers/flat_map.h" #include "base/notreached.h" #include "chrome/browser/apps/app_service/app_service_proxy.h" #include "chrome/browser/apps/app_service/app_service_proxy_factory.h" @@ -133,6 +134,10 @@ const std::string& mime_type, base::OnceCallback<void()> edit_in_photos_callback, absl::optional<storage::FileSystemURL> url) { + constexpr char kPhotosKeepOpenExtraName[] = + "com.google.android.apps.photos.editor.contract.keep_photos_open"; + constexpr char kPhotosKeepOpenExtraValue[] = "true"; + if (!url.has_value()) { std::move(edit_in_photos_callback).Run(); return; @@ -148,6 +153,8 @@ &filesystem_url); auto intent = apps_util::CreateEditIntentFromFile(filesystem_url, mime_type); + intent->extras = { + std::make_pair(kPhotosKeepOpenExtraName, kPhotosKeepOpenExtraValue)}; proxy->LaunchAppWithIntent( arc::kGooglePhotosAppId, ui::EF_NONE, std::move(intent),
diff --git a/chrome/browser/chrome_browser_interface_binders.cc b/chrome/browser/chrome_browser_interface_binders.cc index a1dd3194..186ba4c 100644 --- a/chrome/browser/chrome_browser_interface_binders.cc +++ b/chrome/browser/chrome_browser_interface_binders.cc
@@ -272,6 +272,7 @@ #include "chrome/browser/ui/webui/settings/ash/search/user_action_recorder.mojom.h" #include "chrome/browser/ui/webui/settings/chromeos/os_settings_ui.h" #include "chromeos/ash/components/local_search_service/public/mojom/index.mojom.h" +#include "chromeos/ash/services/auth_factor_config/public/mojom/auth_factor_config.mojom.h" #include "chromeos/services/bluetooth_config/public/mojom/cros_bluetooth_config.mojom.h" #include "chromeos/services/network_config/public/mojom/cros_network_config.mojom.h" // nogncheck #include "chromeos/services/network_health/public/mojom/network_diagnostics.mojom.h" // nogncheck @@ -1004,6 +1005,12 @@ ash::cellular_setup::mojom::CellularSetup, chromeos::settings::OSSettingsUI>(map); + RegisterWebUIControllerInterfaceBinder<ash::auth::mojom::AuthFactorConfig, + chromeos::settings::OSSettingsUI>(map); + + RegisterWebUIControllerInterfaceBinder<ash::auth::mojom::RecoveryFactorEditor, + chromeos::settings::OSSettingsUI>(map); + RegisterWebUIControllerInterfaceBinder< ash::cellular_setup::mojom::ESimManager, chromeos::settings::OSSettingsUI, chromeos::NetworkUI, chromeos::OobeUI>(map);
diff --git a/chrome/browser/download/bubble/download_bubble_controller.cc b/chrome/browser/download/bubble/download_bubble_controller.cc index eea76722..4c70ae4 100644 --- a/chrome/browser/download/bubble/download_bubble_controller.cc +++ b/chrome/browser/download/bubble/download_bubble_controller.cc
@@ -12,6 +12,9 @@ #include "chrome/browser/content_index/content_index_provider_impl.h" #include "chrome/browser/download/bubble/download_bubble_prefs.h" #include "chrome/browser/download/bubble/download_display_controller.h" +#include "chrome/browser/download/chrome_download_manager_delegate.h" +#include "chrome/browser/download/download_core_service.h" +#include "chrome/browser/download/download_core_service_factory.h" #include "chrome/browser/download/download_item_model.h" #include "chrome/browser/download/offline_item_model_manager.h" #include "chrome/browser/download/offline_item_model_manager_factory.h" @@ -486,3 +489,15 @@ download_manager_->DownloadUrl(std::move(download_url_params)); } + +void DownloadBubbleUIController::ScheduleCancelForEphemeralWarning( + const std::string& guid) { + DownloadCoreService* download_core_service = + DownloadCoreServiceFactory::GetForBrowserContext(profile_); + if (!download_core_service) + return; + ChromeDownloadManagerDelegate* delegate = + download_core_service->GetDownloadManagerDelegate(); + if (delegate) + delegate->ScheduleCancelForEphemeralWarning(guid); +}
diff --git a/chrome/browser/download/bubble/download_bubble_controller.h b/chrome/browser/download/bubble/download_bubble_controller.h index b6d3ea5..ae08ecd 100644 --- a/chrome/browser/download/bubble/download_bubble_controller.h +++ b/chrome/browser/download/bubble/download_bubble_controller.h
@@ -84,6 +84,11 @@ // Returns whether the incognito icon should be shown for the download. bool ShouldShowIncognitoIcon(const DownloadUIModel* model) const; + // Schedules the ephemeral warning download to be canceled. It will only be + // canceled if it continues to be an ephemeral warning that hasn't been acted + // on when the scheduled time arrives. + void ScheduleCancelForEphemeralWarning(const std::string& guid); + // Returns the DownloadDisplayController. Should always return a valid // controller. DownloadDisplayController* display_controller_for_testing() {
diff --git a/chrome/browser/download/chrome_download_manager_delegate.cc b/chrome/browser/download/chrome_download_manager_delegate.cc index 84c434c..6f14a54 100644 --- a/chrome/browser/download/chrome_download_manager_delegate.cc +++ b/chrome/browser/download/chrome_download_manager_delegate.cc
@@ -139,6 +139,13 @@ namespace { +#if !BUILDFLAG(IS_ANDROID) +// How long an ephemeral warning lasts before being automatically canceled (if +// there is no user interaction). +constexpr base::TimeDelta kEphemeralWarningLifetimeBeforeCancel = + base::Hours(1); +#endif + // Used with GetPlatformDownloadPath() to indicate which platform path to // return. enum PlatformDownloadPathType { @@ -1590,7 +1597,8 @@ return true; bool file_type_dangerous = - (DownloadItemModel(item).GetDangerLevel() != + (item && + DownloadItemModel(item).GetDangerLevel() != DownloadFileType::NOT_DANGEROUS && danger_type == download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS); @@ -1788,3 +1796,29 @@ std::move(receiver)); #endif // !BUILDFLAG(IS_WIN) } + +#if !BUILDFLAG(IS_ANDROID) +void ChromeDownloadManagerDelegate::ScheduleCancelForEphemeralWarning( + const std::string& guid) { + base::SequencedTaskRunnerHandle::Get()->PostDelayedTask( + FROM_HERE, + base::BindOnce(&ChromeDownloadManagerDelegate::CancelForEphemeralWarning, + weak_ptr_factory_.GetWeakPtr(), guid), + kEphemeralWarningLifetimeBeforeCancel); +} + +void ChromeDownloadManagerDelegate::CancelForEphemeralWarning( + const std::string& guid) { + download::DownloadItem* download = download_manager_->GetDownloadByGuid(guid); + + if (!download) { + // The download may have been destroyed since the task was scheduled + return; + } + + // Confirm that the user has not already acted on the warning. + if (std::make_unique<DownloadItemModel>(download)->IsEphemeralWarning()) { + download->Cancel(/*user_cancel=*/false); + } +} +#endif // !BUILDFLAG(IS_ANDROID)
diff --git a/chrome/browser/download/chrome_download_manager_delegate.h b/chrome/browser/download/chrome_download_manager_delegate.h index 7c459e54..a915ef5e 100644 --- a/chrome/browser/download/chrome_download_manager_delegate.h +++ b/chrome/browser/download/chrome_download_manager_delegate.h
@@ -185,6 +185,13 @@ bool ShouldBlockFile(download::DownloadItem* item, download::DownloadDangerType danger_type) const; +#if !BUILDFLAG(IS_ANDROID) + // Schedules the ephemeral warning download to be canceled. It will only be + // canceled if it continues to be an ephemeral warning that hasn't been acted + // on when the scheduled time arrives. + void ScheduleCancelForEphemeralWarning(const std::string& guid); +#endif + protected: virtual safe_browsing::DownloadProtectionService* GetDownloadProtectionService(); @@ -294,6 +301,12 @@ // multiple downloads are associated with the same file path. bool IsMostRecentDownloadItemAtFilePath(download::DownloadItem* download); +#if !BUILDFLAG(IS_ANDROID) + // Cancels a download if it's still an ephemeral warning (and has not been + // acted on by the user). + void CancelForEphemeralWarning(const std::string& guid); +#endif + #if BUILDFLAG(IS_ANDROID) // Called after a unique file name is generated in the case that there is a // TARGET_CONFLICT and the new file name should be displayed to the user.
diff --git a/chrome/browser/download/chrome_download_manager_delegate_unittest.cc b/chrome/browser/download/chrome_download_manager_delegate_unittest.cc index 258603d..af838e4 100644 --- a/chrome/browser/download/chrome_download_manager_delegate_unittest.cc +++ b/chrome/browser/download/chrome_download_manager_delegate_unittest.cc
@@ -45,11 +45,13 @@ #include "chrome/test/base/testing_profile_manager.h" #include "components/content_settings/core/browser/host_content_settings_map.h" #include "components/content_settings/core/common/content_settings.h" +#include "components/download/public/common/download_danger_type.h" #include "components/download/public/common/download_features.h" #include "components/download/public/common/download_interrupt_reasons.h" #include "components/download/public/common/mock_download_item.h" #include "components/prefs/pref_service.h" #include "components/safe_browsing/buildflags.h" +#include "components/safe_browsing/core/common/features.h" #include "components/sync_preferences/testing_pref_service_syncable.h" #include "content/public/browser/download_item_utils.h" #include "content/public/browser/web_contents.h" @@ -309,7 +311,9 @@ }; ChromeDownloadManagerDelegateTest::ChromeDownloadManagerDelegateTest() - : download_manager_(new ::testing::NiceMock<content::MockDownloadManager>), + : ChromeRenderViewHostTestHarness( + base::test::TaskEnvironment::TimeSource::MOCK_TIME), + download_manager_(new ::testing::NiceMock<content::MockDownloadManager>), testing_profile_manager_(TestingBrowserProcess::GetGlobal()) {} void ChromeDownloadManagerDelegateTest::SetUp() { @@ -1324,6 +1328,47 @@ } #endif // BUILDFLAG(IS_ANDROID) +#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_ASH) +TEST_F(ChromeDownloadManagerDelegateTest, ScheduleCancelForEphemeralWarning) { + base::test::ScopedFeatureList feature_list; + feature_list.InitWithFeatures( + {safe_browsing::kDownloadBubble, safe_browsing::kDownloadBubbleV2}, {}); + + std::unique_ptr<download::MockDownloadItem> download_item = + CreateActiveDownloadItem(0); + EXPECT_CALL(*download_item, GetDangerType()) + .WillRepeatedly(Return(download::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE)); + + delegate()->ScheduleCancelForEphemeralWarning(download_item->GetGuid()); + + // Cancel should not be called until threshold is reached + EXPECT_CALL(*download_item, Cancel(false)).Times(0); + task_environment()->AdvanceClock(base::Minutes(59)); + base::RunLoop().RunUntilIdle(); + EXPECT_CALL(*download_item, Cancel(false)).Times(1); + task_environment()->AdvanceClock(base::Hours(1)); + task_environment()->RunUntilIdle(); +} + +TEST_F(ChromeDownloadManagerDelegateTest, + ScheduleCancelForEphemeralWarning_DownloadKept) { + base::test::ScopedFeatureList feature_list; + feature_list.InitWithFeatures( + {safe_browsing::kDownloadBubble, safe_browsing::kDownloadBubbleV2}, {}); + std::unique_ptr<download::MockDownloadItem> download_item = + CreateActiveDownloadItem(0); + EXPECT_CALL(*download_item, GetDangerType()) + .WillRepeatedly(Return(download::DOWNLOAD_DANGER_TYPE_USER_VALIDATED)); + + delegate()->ScheduleCancelForEphemeralWarning(download_item->GetGuid()); + + // Cancel should not be called until threshold is reached + EXPECT_CALL(*download_item, Cancel(false)).Times(0); + task_environment()->AdvanceClock(base::Hours(1)); + base::RunLoop().RunUntilIdle(); +} +#endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_ASH) + #if BUILDFLAG(FULL_SAFE_BROWSING) namespace {
diff --git a/chrome/browser/download/download_item_model.cc b/chrome/browser/download/download_item_model.cc index 83484e0..69e492a 100644 --- a/chrome/browser/download/download_item_model.cc +++ b/chrome/browser/download/download_item_model.cc
@@ -64,6 +64,11 @@ namespace { +#if !BUILDFLAG(IS_ANDROID) +// How long an ephemeral warning is displayed on the download bubble. +constexpr base::TimeDelta kEphemeralWarningLifetimeOnBubble = base::Minutes(5); +#endif + // Per DownloadItem data used by DownloadItemModel. The model doesn't keep any // state since there could be multiple models associated with a single // DownloadItem, and the lifetime of the model is shorter than the DownloadItem. @@ -101,6 +106,11 @@ // on the UI. bool was_ui_warning_shown_ = false; + // Tracks when an ephemeral warning was first displayed on the UI. Does not + // persist on restart, though ephemeral warning downloads are canceled by + // then as all in-progress downloads are. + absl::optional<base::Time> ephemeral_warning_ui_shown_time_; + private: DownloadItemModelData(); @@ -371,23 +381,6 @@ data->should_show_in_shelf_ = should_show; } -bool DownloadItemModel::ShouldShowInBubble() const { - // Downloads blocked by local policies should be notified, otherwise users - // won't get any feedback that the download has failed. - bool should_notify = - download_->GetLastReason() == - download::DOWNLOAD_INTERRUPT_REASON_FILE_BLOCKED && - download_->GetMixedContentStatus() != - download::DownloadItem::MixedContentStatus::SILENT_BLOCK; - - // Wait until the target path is determined. - if (download_->GetTargetFilePath().empty() && !should_notify) { - return false; - } - - return DownloadUIModel::ShouldShowInBubble(); -} - bool DownloadItemModel::ShouldNotifyUI() const { if (download_->IsTransient()) return false; @@ -428,6 +421,19 @@ data->was_ui_warning_shown_ = was_ui_warning_shown; } +absl::optional<base::Time> DownloadItemModel::GetEphemeralWarningUiShownTime() + const { + const DownloadItemModelData* data = DownloadItemModelData::Get(download_); + return data ? data->ephemeral_warning_ui_shown_time_ + : absl::optional<base::Time>(); +} + +void DownloadItemModel::SetEphemeralWarningUiShownTime( + absl::optional<base::Time> ephemeral_warning_ui_shown_time) { + DownloadItemModelData* data = DownloadItemModelData::GetOrCreate(download_); + data->ephemeral_warning_ui_shown_time_ = ephemeral_warning_ui_shown_time; +} + bool DownloadItemModel::ShouldPreferOpeningInBrowser() const { const DownloadItemModelData* data = DownloadItemModelData::Get(download_); return data && data->should_prefer_opening_in_browser_; @@ -874,7 +880,87 @@ break; } } -#endif + +bool DownloadItemModel::ShouldShowInBubble() const { + // Downloads blocked by local policies should be notified, otherwise users + // won't get any feedback that the download has failed. + bool should_notify = + download_->GetLastReason() == + download::DOWNLOAD_INTERRUPT_REASON_FILE_BLOCKED && + download_->GetMixedContentStatus() != + download::DownloadItem::MixedContentStatus::SILENT_BLOCK; + + // Wait until the target path is determined. + if (download_->GetTargetFilePath().empty() && !should_notify) { + return false; + } + + if (IsEphemeralWarning()) { + // Ephemeral warnings become canceled if the browser shuts down (or an hour + // after being displayed if the user hasn't acted on them). These should no + // longer be shown, regardless of what the shown time is set to. + if (download_->GetState() == download::DownloadItem::CANCELLED) { + return false; + } + + // If the user hasn't acted on an ephemeral warning within 5 minutes, it + // should no longer be shown in the bubble. (IsEphemeralWarning no longer + // returns true once the user has acted on the warning.) + auto warning_shown_time = GetEphemeralWarningUiShownTime(); + if (warning_shown_time.has_value() && + base::Time::Now() - warning_shown_time.value() > + kEphemeralWarningLifetimeOnBubble) { + return false; + } + } + + return DownloadUIModel::ShouldShowInBubble(); +} + +bool DownloadItemModel::IsEphemeralWarning() const { + if (!IsBubbleV2Enabled()) { + return false; + } + + switch (GetMixedContentStatus()) { + case download::DownloadItem::MixedContentStatus::BLOCK: + case download::DownloadItem::MixedContentStatus::WARN: + return true; + case download::DownloadItem::MixedContentStatus::UNKNOWN: + case download::DownloadItem::MixedContentStatus::SAFE: + case download::DownloadItem::MixedContentStatus::VALIDATED: + case download::DownloadItem::MixedContentStatus::SILENT_BLOCK: + break; + } + + switch (GetDangerType()) { + case download::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE: + case download::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT: + case download::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST: + case download::DOWNLOAD_DANGER_TYPE_DANGEROUS_ACCOUNT_COMPROMISE: + case download::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED: + case download::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL: + case download::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT: + case download::DOWNLOAD_DANGER_TYPE_SENSITIVE_CONTENT_WARNING: + return true; + case download::DOWNLOAD_DANGER_TYPE_DEEP_SCANNED_OPENED_DANGEROUS: + case download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS: + case download::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT: + case download::DOWNLOAD_DANGER_TYPE_USER_VALIDATED: + case download::DOWNLOAD_DANGER_TYPE_ALLOWLISTED_BY_POLICY: + case download::DOWNLOAD_DANGER_TYPE_MAX: + case download::DOWNLOAD_DANGER_TYPE_ASYNC_SCANNING: + case download::DOWNLOAD_DANGER_TYPE_DEEP_SCANNED_SAFE: + case download::DOWNLOAD_DANGER_TYPE_PROMPT_FOR_SCANNING: + case download::DOWNLOAD_DANGER_TYPE_BLOCKED_UNSUPPORTED_FILETYPE: + case download::DOWNLOAD_DANGER_TYPE_BLOCKED_PASSWORD_PROTECTED: + case download::DOWNLOAD_DANGER_TYPE_BLOCKED_TOO_LARGE: + case download::DOWNLOAD_DANGER_TYPE_SENSITIVE_CONTENT_BLOCK: + return false; + } +} + +#endif // !BUILDFLAG(IS_ANDROID) offline_items_collection::FailState DownloadItemModel::GetLastFailState() const {
diff --git a/chrome/browser/download/download_item_model.h b/chrome/browser/download/download_item_model.h index db818f8..9351923 100644 --- a/chrome/browser/download/download_item_model.h +++ b/chrome/browser/download/download_item_model.h
@@ -61,13 +61,14 @@ bool ShouldRemoveFromShelfWhenComplete() const override; bool ShouldShowDownloadStartedAnimation() const override; bool ShouldShowInShelf() const override; - bool ShouldShowInBubble() const override; void SetShouldShowInShelf(bool should_show) override; bool ShouldNotifyUI() const override; bool WasUINotified() const override; void SetWasUINotified(bool should_notify) override; bool WasUIWarningShown() const override; void SetWasUIWarningShown(bool should_notify) override; + absl::optional<base::Time> GetEphemeralWarningUiShownTime() const override; + void SetEphemeralWarningUiShownTime(absl::optional<base::Time> time) override; bool ShouldPreferOpeningInBrowser() const override; void SetShouldPreferOpeningInBrowser(bool preference) override; safe_browsing::DownloadFileType::DangerLevel GetDangerLevel() const override; @@ -115,6 +116,8 @@ DownloadCommands::Command command) const override; void ExecuteCommand(DownloadCommands* download_commands, DownloadCommands::Command command) override; + bool ShouldShowInBubble() const override; + bool IsEphemeralWarning() const override; #endif #if BUILDFLAG(FULL_SAFE_BROWSING)
diff --git a/chrome/browser/download/download_item_model_unittest.cc b/chrome/browser/download/download_item_model_unittest.cc index eef7e88b..83a1f8a1 100644 --- a/chrome/browser/download/download_item_model_unittest.cc +++ b/chrome/browser/download/download_item_model_unittest.cc
@@ -16,6 +16,7 @@ #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" +#include "base/test/scoped_feature_list.h" #include "base/test/simple_test_clock.h" #include "base/time/time.h" #include "build/build_config.h" @@ -23,6 +24,7 @@ #include "components/download/public/common/download_danger_type.h" #include "components/download/public/common/mock_download_item.h" #include "components/enterprise/common/download_item_reroute_info.h" +#include "components/safe_browsing/core/common/features.h" #include "components/vector_icons/vector_icons.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -855,7 +857,45 @@ } } } -#endif + +TEST_F(DownloadItemModelTest, ShouldShowInBubble) { + auto in_progress = DownloadItem::IN_PROGRESS; + auto canceled = DownloadItem::CANCELLED; + auto never = absl::optional<base::Time>(); + auto two_mins_ago = base::Time::Now() - base::Minutes(2); + auto ten_mins_ago = base::Time::Now() - base::Minutes(10); + auto dangerous_file = download::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE; + auto not_dangerous = download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS; + + const struct TestCase { + DownloadItem::DownloadState state; + download::DownloadDangerType danger_type; + absl::optional<base::Time> shown_time; + bool expected_should_show; + } kTestCases[] = { + {in_progress, not_dangerous, two_mins_ago, true}, + {in_progress, not_dangerous, ten_mins_ago, true}, + {in_progress, dangerous_file, never, true}, + {in_progress, dangerous_file, two_mins_ago, true}, + {in_progress, dangerous_file, ten_mins_ago, false}, + {canceled, dangerous_file, two_mins_ago, false}, + {canceled, dangerous_file, ten_mins_ago, false}, + {canceled, not_dangerous, two_mins_ago, true}, + {canceled, not_dangerous, ten_mins_ago, true}, + }; + + SetIsBubbleV2Enabled(true); + SetupDownloadItemDefaults(); + for (const auto& test_case : kTestCases) { + EXPECT_CALL(item(), GetState()).WillRepeatedly(Return(test_case.state)); + EXPECT_CALL(item(), GetDangerType()) + .WillRepeatedly(Return(test_case.danger_type)); + model().SetEphemeralWarningUiShownTime(test_case.shown_time); + + EXPECT_EQ(test_case.expected_should_show, model().ShouldShowInBubble()); + } +} +#endif // !BUILDFLAG(IS_ANDROID) TEST_F(DownloadItemModelTest, ShouldShowInShelf) { SetupDownloadItemDefaults();
diff --git a/chrome/browser/download/download_ui_model.cc b/chrome/browser/download/download_ui_model.cc index 84eb3ed..8142bb0 100644 --- a/chrome/browser/download/download_ui_model.cc +++ b/chrome/browser/download/download_ui_model.cc
@@ -395,10 +395,6 @@ void DownloadUIModel::SetShouldShowInShelf(bool should_show) {} -bool DownloadUIModel::ShouldShowInBubble() const { - return ShouldShowInShelf(); -} - bool DownloadUIModel::ShouldNotifyUI() const { return true; } @@ -415,6 +411,14 @@ void DownloadUIModel::SetWasUIWarningShown(bool was_ui_warning_shown) {} +absl::optional<base::Time> DownloadUIModel::GetEphemeralWarningUiShownTime() + const { + return absl::optional<base::Time>(); +} + +void DownloadUIModel::SetEphemeralWarningUiShownTime( + absl::optional<base::Time> time) {} + bool DownloadUIModel::ShouldPreferOpeningInBrowser() const { return true; } @@ -1138,7 +1142,16 @@ ui::kColorSecondaryForeground); } } -#endif + +bool DownloadUIModel::ShouldShowInBubble() const { + return ShouldShowInShelf(); +} + +bool DownloadUIModel::IsEphemeralWarning() const { + return false; +} + +#endif // !BUILDFLAG(IS_ANDROID) std::string DownloadUIModel::GetMimeType() const { return "text/html";
diff --git a/chrome/browser/download/download_ui_model.h b/chrome/browser/download/download_ui_model.h index 0125724a..900b7798 100644 --- a/chrome/browser/download/download_ui_model.h +++ b/chrome/browser/download/download_ui_model.h
@@ -283,9 +283,6 @@ // Returns |true| if this download should be displayed in the downloads shelf. virtual bool ShouldShowInShelf() const; - // Returns |true| if this download should be displayed in the download bubble. - virtual bool ShouldShowInBubble() const; - // Change whether the download should be displayed on the downloads // shelf. Setting this is only effective if the download hasn't already been // displayed in the shelf. @@ -313,6 +310,13 @@ // Change what's returned by WasUIWarningShown(). virtual void SetWasUIWarningShown(bool was_ui_warning_shown); + // If this is an ephemeral warning, returns when the bubble first displayed + // the warning. If the warning has not yet shown (or this isn't an ephemeral + // warning), it returns no value. This does not persist across restarts. + virtual absl::optional<base::Time> GetEphemeralWarningUiShownTime() const; + + virtual void SetEphemeralWarningUiShownTime(absl::optional<base::Time> time); + // Returns |true| if opening in the browser is preferred for this download. If // |false|, the download should be opened with the system default application. virtual bool ShouldPreferOpeningInBrowser() const; @@ -475,6 +479,14 @@ BubbleUIInfo GetBubbleUIInfoForInterrupted( offline_items_collection::FailState fail_state) const; BubbleUIInfo GetBubbleUIInfoForInProgressOrComplete() const; + + // Returns |true| if this download should be displayed in the download bubble. + virtual bool ShouldShowInBubble() const; + + // Ephemeral warnings are ones that are quickly removed from the bubble if the + // user has not acted on them, and later deleted altogether. Is this that kind + // of warning? + virtual bool IsEphemeralWarning() const; #endif #if BUILDFLAG(FULL_SAFE_BROWSING) @@ -500,6 +512,11 @@ raw_ptr<Delegate> delegate_ = nullptr; +#if !BUILDFLAG(IS_ANDROID) + // Returns whether the DownloadBubbleV2 functionality is enabled. + bool IsBubbleV2Enabled() const; +#endif + private: friend class DownloadItemModelTest; @@ -512,8 +529,6 @@ // Setting an override for whether the DownloadBubbleV2 functionality is // enabled. void set_is_bubble_v2_enabled_for_testing(bool is_enabled); - // Returns whether the DownloadBubbleV2 functionality is enabled. - bool IsBubbleV2Enabled() const; #endif // Unowned Clock to override the time of "Now".
diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc index 895daf2..40e72e9 100644 --- a/chrome/browser/extensions/extension_service.cc +++ b/chrome/browser/extensions/extension_service.cc
@@ -803,8 +803,12 @@ // Unload before doing more cleanup to ensure that nothing is hanging on to // any of these resources. UnloadExtension(extension->id(), UnloadedExtensionReason::UNINSTALL); + + // `UnloadExtension` ignores extensions that are `BLOCKLISTED` or `BLOCKED` if (registry_->blocklisted_extensions().Contains(extension->id())) registry_->RemoveBlocklisted(extension->id()); + if (registry_->blocked_extensions().Contains(extension->id())) + registry_->RemoveBlocked(extension->id()); // Prepare barrier closure for UninstallExtensionOnFileThread() task (if // applicable) and DataDeleter::StartDeleting().
diff --git a/chrome/browser/extensions/extension_service_test_with_install.cc b/chrome/browser/extensions/extension_service_test_with_install.cc index 685ae50d..9664719 100644 --- a/chrome/browser/extensions/extension_service_test_with_install.cc +++ b/chrome/browser/extensions/extension_service_test_with_install.cc
@@ -370,6 +370,10 @@ service()->TerminateExtension(id); } +void ExtensionServiceTestWithInstall::BlockAllExtensions() { + service()->BlockAllExtensions(); +} + void ExtensionServiceTestWithInstall::ClearLoadedExtensions() { loaded_extensions_.clear(); }
diff --git a/chrome/browser/extensions/extension_service_test_with_install.h b/chrome/browser/extensions/extension_service_test_with_install.h index fbe61af..649d7410 100644 --- a/chrome/browser/extensions/extension_service_test_with_install.h +++ b/chrome/browser/extensions/extension_service_test_with_install.h
@@ -128,6 +128,8 @@ void TerminateExtension(const std::string& id); + void BlockAllExtensions(); + void ClearLoadedExtensions(); const ExtensionList& loaded_extensions() const { return loaded_extensions_; }
diff --git a/chrome/browser/extensions/extension_service_unittest.cc b/chrome/browser/extensions/extension_service_unittest.cc index 9b37d26a..4d38f073 100644 --- a/chrome/browser/extensions/extension_service_unittest.cc +++ b/chrome/browser/extensions/extension_service_unittest.cc
@@ -4935,6 +4935,29 @@ EXPECT_EQ(UnloadedExtensionReason::TERMINATE, unloaded_reason()); } +TEST_F(ExtensionServiceTest, UninstallBlockedExtension) { + InitializeEmptyExtensionService(); + + MockExtensionRegistryObserver observer; + registry()->AddObserver(&observer); + + ASSERT_TRUE(observer.last_extension_installed.empty()); + InstallCRX(data_dir().AppendASCII("good.crx"), INSTALL_NEW); + ASSERT_EQ(good_crx, observer.last_extension_installed); + EXPECT_EQ(1u, registry()->enabled_extensions().size()); + + BlockAllExtensions(); + EXPECT_EQ(UnloadedExtensionReason::LOCK_ALL, unloaded_reason()); + EXPECT_EQ(1u, registry()->blocked_extensions().size()); + + ASSERT_TRUE(observer.last_extension_uninstalled.empty()); + UninstallExtension(good_crx); + ASSERT_EQ(good_crx, observer.last_extension_uninstalled); + EXPECT_EQ(0u, registry()->blocked_extensions().size()); + + registry()->RemoveObserver(&observer); +} + // An extension disabled because of unsupported requirements should re-enabled // if updated to a version with supported requirements as long as there are no // other disable reasons.
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index ada754e3..a66f96c 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -5395,6 +5395,11 @@ "expiry_milestone": 90 }, { + "name": "region-capture-experimental-subtypes", + "owners": [ "jophba", "eladalon" ], + "expiry_milestone": 115 + }, + { "name": "related-searches", "owners": [ "gangwu", "related-searches-vteam@google.com" ], "expiry_milestone": 110
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index 440aaff..2e3cf77 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -1365,6 +1365,12 @@ const char kEnableZeroCopyTabCaptureDescription[] = "Enable zero-copy content tab for getDisplayMedia() APIs."; +const char kEnableRegionCaptureExperimentalSubtypesName[] = + "Region capture experimental subtypes"; +const char kEnableRegionCaptureExperimentalSubtypesDescription[] = + "Enables experiment support for CropTarget.fromElement to use other " + "Element subtypes than just <div> and <iframe>."; + const char kExperimentalWebAssemblyFeaturesName[] = "Experimental WebAssembly"; const char kExperimentalWebAssemblyFeaturesDescription[] = "Enable web pages to use experimental WebAssembly features.";
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index f93d31a5c..3e39c17c 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -759,6 +759,9 @@ extern const char kEnableZeroCopyTabCaptureName[]; extern const char kEnableZeroCopyTabCaptureDescription[]; +extern const char kEnableRegionCaptureExperimentalSubtypesName[]; +extern const char kEnableRegionCaptureExperimentalSubtypesDescription[]; + extern const char kExperimentalWebAssemblyFeaturesName[]; extern const char kExperimentalWebAssemblyFeaturesDescription[];
diff --git a/chrome/browser/media/webrtc/region_capture_browsertest.cc b/chrome/browser/media/webrtc/region_capture_browsertest.cc index 4edd3b52..cf11073 100644 --- a/chrome/browser/media/webrtc/region_capture_browsertest.cc +++ b/chrome/browser/media/webrtc/region_capture_browsertest.cc
@@ -32,6 +32,7 @@ #include "content/public/test/browser_test_utils.h" #include "content/public/test/prerender_test_util.h" #include "testing/gmock/include/gmock/gmock-matchers.h" +#include "third_party/blink/public/common/features.h" // TODO(crbug.com/1215089): Enable this test suite on Lacros. #if !BUILDFLAG(IS_CHROMEOS_LACROS) @@ -182,17 +183,27 @@ // [*] Actually, because `CropTarget`s are not stringifiable, an index // of the CropTarget is used, and translated by JS code back into // the CropTarget it had stored. - std::string CropTo(const std::string& crop_target, - Frame frame, - Track track = Track::kOriginal) { + bool CropTo(const std::string& crop_target, + Frame frame, + Track track = Track::kOriginal) { std::string script_result = "error-not-modified"; EXPECT_TRUE(content::ExecuteScriptAndExtractString( web_contents->GetPrimaryMainFrame(), base::StringPrintf("cropToByIndex('%s', '%s', '%s');", crop_target.c_str(), ToString(frame), ToString(track)), - &script_result)); - return script_result; + &script_result)) + << "Failed to crop to: " << crop_target; + + if (frame == Frame::kTopLevelDocument) { + EXPECT_EQ(0u, script_result.rfind("top-level-", 0)) << script_result; + return script_result == "top-level-crop-success"; + } + if (frame == Frame::kEmbeddedFrame) { + EXPECT_EQ(0u, script_result.rfind("embedded-", 0)) << script_result; + return script_result == "embedded-crop-success"; + } + return false; } bool CloneTrack() { @@ -215,26 +226,36 @@ return script_result == "deallocate-success"; } - bool HideElement(const std::string& element_id) { + bool HideElement(const char* element_id) { std::string script_result = "error-not-modified"; EXPECT_TRUE(content::ExecuteScriptAndExtractString( web_contents->GetPrimaryMainFrame(), - base::StringPrintf("hideElement('%s');", element_id.c_str()), - &script_result)); + base::StringPrintf("hideElement('%s');", element_id), &script_result)); DCHECK(script_result == "hide-element-failure" || script_result == "hide-element-success"); return script_result == "hide-element-success"; } - std::string CreateNewDivElement(Frame frame, const std::string& div_id) { + bool CreateNewElement(Frame frame, const char* tag, const std::string& id) { DCHECK_NE(frame, Frame::kNone); std::string script_result = "error-not-modified"; EXPECT_TRUE(content::ExecuteScriptAndExtractString( web_contents->GetPrimaryMainFrame(), - base::StrCat({"createNewDivElement(\"", ToString(frame), "\", \"", - div_id, "\");"}), + base::StrCat({"createNewElement(\"", ToString(frame), "\", \"", tag, + "\", \"", id, "\");"}), &script_result)); - return script_result; + + if (frame == Frame::kEmbeddedFrame) { + EXPECT_EQ(0u, script_result.rfind("embedded-", 0)) << script_result; + return script_result == "embedded-new-element-success"; + } + DCHECK(frame == Frame::kTopLevelDocument); + EXPECT_EQ(0u, script_result.rfind("top-level-", 0)) << script_result; + return script_result == "top-level-new-element-success"; + } + + bool CreateNewDivElement(Frame frame, const std::string& id) { + return CreateNewElement(frame, "div", id); } raw_ptr<Browser> browser; @@ -248,6 +269,10 @@ // detection of JS errors. class RegionCaptureBrowserTest : public WebRtcTestBase { public: + RegionCaptureBrowserTest() { + scoped_feature_list_.InitAndEnableFeature( + blink::features::kRegionCaptureExperimentalSubtypes); + } ~RegionCaptureBrowserTest() override = default; void SetUpInProcessBrowserTestFixture() override { @@ -349,6 +374,8 @@ // Each page is served from a distinct origin, thereby proving that cropping // works irrespective of whether iframes are in/out-of-process. std::vector<std::unique_ptr<net::EmbeddedTestServer>> servers_; + + base::test::ScopedFeatureList scoped_feature_list_; }; IN_PROC_BROWSER_TEST_F(RegionCaptureBrowserTest, @@ -373,8 +400,7 @@ const std::string crop_target = tab.CropTargetFromElement(Frame::kTopLevelDocument); ASSERT_THAT(crop_target, IsExpectedCropTarget("0")); - EXPECT_EQ(tab.CropTo(crop_target, Frame::kTopLevelDocument), - "top-level-crop-success"); + EXPECT_TRUE(tab.CropTo(crop_target, Frame::kTopLevelDocument)); } IN_PROC_BROWSER_TEST_F(RegionCaptureBrowserTest, @@ -385,8 +411,7 @@ const std::string crop_target = tab.CropTargetFromElement(Frame::kEmbeddedFrame); ASSERT_THAT(crop_target, IsExpectedCropTarget("0")); - EXPECT_EQ(tab.CropTo(crop_target, Frame::kTopLevelDocument), - "top-level-crop-success"); + EXPECT_TRUE(tab.CropTo(crop_target, Frame::kTopLevelDocument)); } IN_PROC_BROWSER_TEST_F(RegionCaptureBrowserTest, @@ -397,8 +422,7 @@ const std::string crop_target = tab.CropTargetFromElement(Frame::kTopLevelDocument); ASSERT_THAT(crop_target, IsExpectedCropTarget("0")); - EXPECT_EQ(tab.CropTo(crop_target, Frame::kEmbeddedFrame), - "embedded-crop-success"); + EXPECT_TRUE(tab.CropTo(crop_target, Frame::kEmbeddedFrame)); } IN_PROC_BROWSER_TEST_F(RegionCaptureBrowserTest, @@ -409,8 +433,7 @@ const std::string crop_target = tab.CropTargetFromElement(Frame::kEmbeddedFrame); ASSERT_THAT(crop_target, IsExpectedCropTarget("0")); - EXPECT_EQ(tab.CropTo(crop_target, Frame::kEmbeddedFrame), - "embedded-crop-success"); + EXPECT_TRUE(tab.CropTo(crop_target, Frame::kEmbeddedFrame)); } IN_PROC_BROWSER_TEST_F(RegionCaptureBrowserTest, CropToAllowedToUncrop) { @@ -420,11 +443,8 @@ const std::string crop_target = tab.CropTargetFromElement(Frame::kTopLevelDocument); ASSERT_THAT(crop_target, IsExpectedCropTarget("0")); - ASSERT_EQ(tab.CropTo(crop_target, Frame::kTopLevelDocument), - "top-level-crop-success"); - - EXPECT_EQ(tab.CropTo("undefined", Frame::kTopLevelDocument), - "top-level-crop-success"); + ASSERT_TRUE(tab.CropTo(crop_target, Frame::kTopLevelDocument)); + EXPECT_TRUE(tab.CropTo("undefined", Frame::kTopLevelDocument)); } IN_PROC_BROWSER_TEST_F(RegionCaptureBrowserTest, @@ -438,8 +458,7 @@ // CropTo(cropTarget) is intentionally not called. // Instead, the test immediately calls CropTo(undefined) on a still-uncropped // track, attempting to stop cropping when no cropping was ever specified. - EXPECT_EQ(tab.CropTo("undefined", Frame::kTopLevelDocument), - "top-level-crop-success"); + EXPECT_TRUE(tab.CropTo("undefined", Frame::kTopLevelDocument)); } // The Promise resolves when it's guaranteed that no additional frames will @@ -456,8 +475,31 @@ const std::string crop_target = tab.CropTargetFromElement(Frame::kTopLevelDocument, "div"); ASSERT_THAT(crop_target, IsExpectedCropTarget("0")); - EXPECT_EQ(tab.CropTo(crop_target, Frame::kTopLevelDocument), - "top-level-crop-success"); + EXPECT_TRUE(tab.CropTo(crop_target, Frame::kTopLevelDocument)); +} + +IN_PROC_BROWSER_TEST_F(RegionCaptureBrowserTest, + CropToWorksForAllHtmlElements) { + // NOTE: this list is intentionally non-exhaustive, but represents a wide + // variety of element types. + static const std::vector<const char*> kElementTags{ + "a", "blockquote", "body", "button", "canvas", "col", + "div", "fieldset", "form", "h1", "header", "hr", + "iframe", "img", "input", "output", "span", "video"}; + + SetUpTest(Frame::kTopLevelDocument, /*self_capture=*/true); + TabInfo& tab = tabs_[kMainTab]; + + for (size_t i = 0; i < kElementTags.size(); ++i) { + const std::string element_id = ("new_id_" + base::NumberToString(i)); + ASSERT_TRUE(tab.CreateNewElement(Frame::kTopLevelDocument, kElementTags[i], + element_id)); + const std::string crop_target = + tab.CropTargetFromElement(Frame::kTopLevelDocument, element_id); + ASSERT_THAT(crop_target, IsExpectedCropTarget(base::NumberToString(i))); + + EXPECT_TRUE(tab.CropTo(crop_target, Frame::kTopLevelDocument)); + } } IN_PROC_BROWSER_TEST_F(RegionCaptureBrowserTest, MaxCropIdsInTopLevelDocument) { @@ -466,8 +508,7 @@ for (size_t i = 0; i < kMaxCropIdsPerWebContents; ++i) { const std::string element_id = ("new_id_" + base::NumberToString(i)); - ASSERT_EQ(tab.CreateNewDivElement(Frame::kTopLevelDocument, element_id), - "top-level-new-div-success"); + ASSERT_TRUE(tab.CreateNewDivElement(Frame::kTopLevelDocument, element_id)); const std::string crop_target = tab.CropTargetFromElement(Frame::kTopLevelDocument, element_id); ASSERT_THAT(crop_target, IsExpectedCropTarget(base::NumberToString(i))); @@ -476,8 +517,7 @@ // Create one more element - this one won't get a crop-target. const std::string element_id = ("new_id_" + base::NumberToString(kMaxCropIdsPerWebContents)); - ASSERT_EQ(tab.CreateNewDivElement(Frame::kTopLevelDocument, element_id), - "top-level-new-div-success"); + ASSERT_TRUE(tab.CreateNewDivElement(Frame::kTopLevelDocument, element_id)); EXPECT_EQ(tab.CropTargetFromElement(Frame::kTopLevelDocument, element_id), "top-level-produce-crop-target-error"); } @@ -488,8 +528,7 @@ for (size_t i = 0; i < kMaxCropIdsPerWebContents; ++i) { const std::string element_id = ("new_id_" + base::NumberToString(i)); - ASSERT_EQ(tab.CreateNewDivElement(Frame::kEmbeddedFrame, element_id), - "embedded-new-div-success"); + ASSERT_TRUE(tab.CreateNewDivElement(Frame::kEmbeddedFrame, element_id)); const std::string crop_target = tab.CropTargetFromElement(Frame::kEmbeddedFrame, element_id); ASSERT_THAT(crop_target, IsExpectedCropTarget(base::NumberToString(i))); @@ -498,8 +537,7 @@ // Create one more element - this one won't get a crop-target. const std::string element_id = ("new_id_" + base::NumberToString(kMaxCropIdsPerWebContents)); - ASSERT_EQ(tab.CreateNewDivElement(Frame::kEmbeddedFrame, element_id), - "embedded-new-div-success"); + ASSERT_TRUE(tab.CreateNewDivElement(Frame::kEmbeddedFrame, element_id)); EXPECT_EQ(tab.CropTargetFromElement(Frame::kEmbeddedFrame, element_id), "embedded-produce-crop-target-error"); } @@ -515,8 +553,7 @@ // crop-target. for (size_t i = 0; i < kMaxCropIdsPerWebContents - 1; ++i) { const std::string element_id = ("new_id_" + base::NumberToString(i)); - ASSERT_EQ(tab.CreateNewDivElement(Frame::kTopLevelDocument, element_id), - "top-level-new-div-success"); + ASSERT_TRUE(tab.CreateNewDivElement(Frame::kTopLevelDocument, element_id)); const std::string crop_target = tab.CropTargetFromElement(Frame::kTopLevelDocument, element_id); ASSERT_THAT(crop_target, IsExpectedCropTarget(base::NumberToString(i))); @@ -525,8 +562,7 @@ // One more in the embedded frame is possible. std::string element_id = ("new_id_" + base::NumberToString(kMaxCropIdsPerWebContents - 1)); - ASSERT_EQ(tab.CreateNewDivElement(Frame::kEmbeddedFrame, element_id), - "embedded-new-div-success"); + ASSERT_TRUE(tab.CreateNewDivElement(Frame::kEmbeddedFrame, element_id)); const std::string crop_target = tab.CropTargetFromElement(Frame::kEmbeddedFrame, element_id); EXPECT_THAT(crop_target, IsExpectedCropTarget(base::NumberToString( @@ -534,15 +570,13 @@ // Create one more element - this one won't get a crop-target. element_id = ("new_id_" + base::NumberToString(kMaxCropIdsPerWebContents)); - ASSERT_EQ(tab.CreateNewDivElement(Frame::kTopLevelDocument, element_id), - "top-level-new-div-success"); + ASSERT_TRUE(tab.CreateNewDivElement(Frame::kTopLevelDocument, element_id)); EXPECT_EQ(tab.CropTargetFromElement(Frame::kTopLevelDocument, element_id), "top-level-produce-crop-target-error"); // Neither in the top-level nor in the embedded frame. element_id = ("new_id_" + base::NumberToString(kMaxCropIdsPerWebContents + 1)); - ASSERT_EQ(tab.CreateNewDivElement(Frame::kEmbeddedFrame, element_id), - "embedded-new-div-success"); + ASSERT_TRUE(tab.CreateNewDivElement(Frame::kEmbeddedFrame, element_id)); EXPECT_EQ(tab.CropTargetFromElement(Frame::kEmbeddedFrame, element_id), "embedded-produce-crop-target-error"); } @@ -572,14 +606,7 @@ } bool CropTo(const std::string& crop_target, Frame frame, Track track) { - const std::string result = - tabs_[kMainTab].CropTo(crop_target, frame, track); - - // This test suite only ever starts the capture from the top-level frame. - DCHECK(result == base::StrCat({ToString(frame), "-crop-success"}) || - result == base::StrCat({ToString(frame), "-crop-error"})); - - return result == base::StrCat({ToString(frame), "-crop-success"}); + return tabs_[kMainTab].CropTo(crop_target, frame, track); } bool CloneTrack() { return tabs_[kMainTab].CloneTrack(); } @@ -914,12 +941,8 @@ const bool expect_permitted = (self_capture_ && target_element_tab_ == kMainTab); - const std::string expected_result = base::StrCat( - {capturing_entity_ == Frame::kTopLevelDocument ? "top-level" : "embedded", - "-", expect_permitted ? "crop-success" : "crop-error"}); - - EXPECT_EQ(tabs_[kMainTab].CropTo(crop_target, capturing_entity_), - expected_result); + EXPECT_EQ(expect_permitted, + tabs_[kMainTab].CropTo(crop_target, capturing_entity_)); } #endif // !BUILDFLAG(IS_CHROMEOS_LACROS)
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/BUILD.gn b/chrome/browser/resources/chromeos/accessibility/chromevox/BUILD.gn index 47f495f7..05b68541 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/BUILD.gn +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/BUILD.gn
@@ -29,7 +29,6 @@ "background/braille/liblouis.js", "background/braille/pan_strategy.js", "background/chromevox.js", - "background/logging/log_store.js", "common/abstract_earcons.js", "common/background_bridge.js", "common/braille/braille_interface.js", @@ -99,6 +98,7 @@ "background/keyboard_handler.js", "background/live_regions.js", "background/logging/event_stream_logger.js", + "background/logging/log_store.js", "background/logging/log_url_watcher.js", "background/math_handler.js", "background/media_automation_handler.js",
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/background.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/background.js index 93e54ca..8ea5c4e 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/background.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/background.js
@@ -26,6 +26,7 @@ import {GestureCommandHandler} from './gesture_command_handler.js'; import {BackgroundKeyboardHandler} from './keyboard_handler.js'; import {LiveRegions} from './live_regions.js'; +import {LogStore} from './logging/log_store.js'; import {MathHandler} from './math_handler.js'; import {MediaAutomationHandler} from './media_automation_handler.js'; import {Output} from './output/output.js';
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/braille/braille_background.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/braille/braille_background.js index f91eaaee..e2716915 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/braille/braille_background.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/braille/braille_background.js
@@ -6,6 +6,7 @@ * @fileoverview Sends Braille commands to the Braille API. */ import {ChromeVoxState} from '../chromevox_state.js'; +import {LogStore} from '../logging/log_store.js'; import {BrailleDisplayManager} from './braille_display_manager.js'; import {BrailleInputHandler} from './braille_input_handler.js';
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/command_handler.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/command_handler.js index afeed5e..c91e403 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/command_handler.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/command_handler.js
@@ -28,6 +28,7 @@ import {TypingEcho} from './editing/editable_text_base.js'; import {EventSourceState} from './event_source.js'; import {GestureInterface} from './gesture_interface.js'; +import {LogStore} from './logging/log_store.js'; import {Output} from './output/output.js'; import {OutputEventType} from './output/output_types.js'; import {PhoneticData} from './phonetic_data.js';
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/console_tts.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/console_tts.js index f929b44..b32e501 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/console_tts.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/console_tts.js
@@ -5,6 +5,7 @@ /** * @fileoverview A TTS engine that writes to window.console. */ +import {LogStore} from './logging/log_store.js'; import {ChromeVoxPrefs} from './prefs.js'; /**
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/earcons.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/earcons.js index a427065..75a6ca6b 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/earcons.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/earcons.js
@@ -9,6 +9,7 @@ import {ChromeVoxState} from './chromevox_state.js'; import {EarconEngine} from './earcon_engine.js'; +import {LogStore} from './logging/log_store.js'; export class Earcons extends AbstractEarcons { constructor() {
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/loader.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/loader.js index d2926bc..61ebedd 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/loader.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/loader.js
@@ -16,17 +16,18 @@ goog.require('AutomationPredicate'); goog.require('AutomationTreeWalker'); goog.require('AutomationUtil'); +goog.require('BaseLog'); goog.require('BrailleDisplayState'); goog.require('BrailleInterface'); goog.require('BrailleKeyCommand'); goog.require('BrailleKeyEvent'); goog.require('BridgeHelper'); goog.require('ChromeVox'); +goog.require('EventLog'); goog.require('JaPhoneticData'); goog.require('KeyCode'); goog.require('LibLouis'); goog.require('LibLouis.FormType'); -goog.require('LogStore'); goog.require('LogType'); goog.require('NavBraille'); goog.require('PanelNodeMenuData'); @@ -37,6 +38,7 @@ goog.require('SpeechLog'); goog.require('TextLog'); goog.require('TreeDumper'); +goog.require('TreeLog'); goog.require('TreePathRecoveryStrategy'); goog.require('TtsCategory'); goog.require('TtsInterface');
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/logging/event_stream_logger.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/logging/event_stream_logger.js index bc2bbcac..15b3e90 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/logging/event_stream_logger.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/logging/event_stream_logger.js
@@ -6,6 +6,8 @@ * @fileoverview Creates event stream logger. */ +import {LogStore} from './log_store.js'; + const AutomationEvent = chrome.automation.AutomationEvent; const AutomationNode = chrome.automation.AutomationNode; const EventType = chrome.automation.EventType;
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/logging/log_store.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/logging/log_store.js index 71dc266..5b5e7c3 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/logging/log_store.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/logging/log_store.js
@@ -6,17 +6,7 @@ * @fileoverview Store ChromeVox log. */ -goog.provide('LogStore'); - -goog.require('TreeDumper'); -goog.require('BaseLog'); -goog.require('EventLog'); -goog.require('LogType'); -goog.require('SpeechLog'); -goog.require('TextLog'); -goog.require('TreeLog'); - -LogStore = class { +export class LogStore { constructor() { /** * Ring buffer of size this.LOG_LIMIT @@ -145,7 +135,7 @@ } return LogStore.instance; } -}; +} /** * @const
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/logging/log_store_test.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/logging/log_store_test.js index a1093e3..16176c18 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/logging/log_store_test.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/logging/log_store_test.js
@@ -8,8 +8,14 @@ /** * Test fixture for automation_util.js. */ -ChromeVoxLogStoreTest = class extends ChromeVoxNextE2ETest {}; - +ChromeVoxLogStoreTest = class extends ChromeVoxNextE2ETest { + /** @override */ + async setUpDeferred() { + await super.setUpDeferred(); + await importModule( + 'LogStore', '/chromevox/background/logging/log_store.js'); + } +}; AX_TEST_F('ChromeVoxLogStoreTest', 'ShortLogs', function() { const logStore = new LogStore();
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/logging/log_url_watcher.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/logging/log_url_watcher.js index 88c103ba..99d098e 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/logging/log_url_watcher.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/logging/log_url_watcher.js
@@ -8,6 +8,8 @@ */ import {ChromeVoxState, ChromeVoxStateObserver} from '../chromevox_state.js'; +import {LogStore} from './log_store.js'; + /** @implements {ChromeVoxStateObserver} */ export class LogUrlWatcher { static create() {
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/output/output.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/output/output.js index 68a35a6..ce0ebb1 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/output/output.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/output/output.js
@@ -13,6 +13,7 @@ import {ValueSelectionSpan, ValueSpan} from '../braille/spans.js'; import {EventSourceState} from '../event_source.js'; import {FocusBounds} from '../focus_bounds.js'; +import {LogStore} from '../logging/log_store.js'; import {PhoneticData} from '../phonetic_data.js'; import {OutputAncestryInfo} from './output_ancestry_info.js';
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/log_page/log_loader.js b/chrome/browser/resources/chromeos/accessibility/chromevox/log_page/log_loader.js index 73db1f7..e019f8bb 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/log_page/log_loader.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/log_page/log_loader.js
@@ -8,6 +8,10 @@ */ goog.require('BackgroundBridge'); -goog.require('LogStore'); +goog.require('BaseLog'); +goog.require('EventLog'); goog.require('LogType'); +goog.require('SpeechLog'); +goog.require('TextLog'); +goog.require('TreeDumper'); goog.require('TreeLog');
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/panel/panel_loader.js b/chrome/browser/resources/chromeos/accessibility/chromevox/panel/panel_loader.js index d9583a0a..f04d507 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/panel/panel_loader.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/panel/panel_loader.js
@@ -11,17 +11,22 @@ goog.require('AutomationTreeWalker'); goog.require('AutomationUtil'); goog.require('BackgroundBridge'); +goog.require('BaseLog'); goog.require('BridgeHelper'); goog.require('EarconDescription'); +goog.require('EventLog'); goog.require('KeyCode'); -goog.require('LogStore'); +goog.require('LogType'); goog.require('NavBraille'); goog.require('PanelNodeMenuData'); goog.require('PanelNodeMenuItemData'); goog.require('QueueMode'); goog.require('RecoveryStrategy'); goog.require('Spannable'); +goog.require('SpeechLog'); goog.require('TextLog'); +goog.require('TreeDumper'); +goog.require('TreeLog'); goog.require('TtsCategory'); goog.require('constants');
diff --git a/chrome/browser/resources/chromeos/notification_tester/form_constants.js b/chrome/browser/resources/chromeos/notification_tester/form_constants.js index 13ad29c..344f7e4 100644 --- a/chrome/browser/resources/chromeos/notification_tester/form_constants.js +++ b/chrome/browser/resources/chromeos/notification_tester/form_constants.js
@@ -9,6 +9,17 @@ */ /* + Matches SystemNotificationWarningLevel in + ui/message_center/public/cpp/notification.h + @enum {number} +*/ +export const SystemNotificationWarningLevel = { + NORMAL: 0, + WARNING: 1, + CRITICAL_WARNING: 2, +}; + +/* Matches NotificationPriority in ui/message_center/public/cpp/notification_types.h @enum {number} @@ -134,7 +145,7 @@ {displayText: 'URL (Right-to-Left)', value: 'https://اختبار.النهاي'}, {displayText: 'Empty', value: ''}, ], - SOURCE_OPTIONS: [ + DISPLAY_SOURCE_OPTIONS: [ { displayText: 'Short Sentence (Left-to-Right)', value: 'Sample Display Source', @@ -206,6 +217,14 @@ {displayText: 'Group B', value: 'group_b'}, {displayText: 'Group C', value: 'group_c'}, ], + WARNING_LEVEL_OPTIONS: [ + {displayText: 'Normal', value: SystemNotificationWarningLevel.NORMAL}, + {displayText: 'Warning', value: SystemNotificationWarningLevel.WARNING}, + { + displayText: 'Critical Warning', + value: SystemNotificationWarningLevel.CRITICAL_WARNING, + }, + ], }; // Constant notification objects based on the notification spec:
diff --git a/chrome/browser/resources/chromeos/notification_tester/notification_tester.html b/chrome/browser/resources/chromeos/notification_tester/notification_tester.html index 66065fc..0960d35 100644 --- a/chrome/browser/resources/chromeos/notification_tester/notification_tester.html +++ b/chrome/browser/resources/chromeos/notification_tester/notification_tester.html
@@ -159,16 +159,20 @@ select-elements="[[iconSelectList]]" selectid="icon" no-custom-input="true"></select-custom> - <template is="dom-if" if="[[showDisplaySource]]"> - <select-custom select-value="{{notifMetadata.displaySource}}" - display-label="Source" select-elements="[[sourceSelectList]]" - selectid="source"></select-custom> - </template> + <select-custom select-value="{{notifMetadata.displaySource}}" + display-label="Display Source" + select-elements="[[displaySourceSelectList]]" selectid="source"> + </select-custom> - <template is="dom-if" if="[[showOriginURL]]"> - <select-custom select-value="{{notifMetadata.originURL}}" - display-label="Origin URL" select-elements="[[originURLSelectList]]" - selectid="origin-url"></select-custom> + <select-custom select-value="{{notifMetadata.originURL}}" + display-label="Origin URL" select-elements="[[originURLSelectList]]" + selectid="origin-url"></select-custom> + + <template is="dom-if" if="[[isSystemNotification]]"> + <select-custom select-value="{{notifMetadata.warningLevel}}" + display-label="Warning Level" + select-elements="[[warningLevelSelectList]]" selectid="warning-level" + no-custom-input="true"></select-custom> </template> </div> <div class="config-form">
diff --git a/chrome/browser/resources/chromeos/notification_tester/notification_tester.js b/chrome/browser/resources/chromeos/notification_tester/notification_tester.js index c4b02e6..53e02f5 100644 --- a/chrome/browser/resources/chromeos/notification_tester/notification_tester.js +++ b/chrome/browser/resources/chromeos/notification_tester/notification_tester.js
@@ -11,7 +11,7 @@ import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; -import {FormSelectOptions, NOTIFICATION_VIEW_TYPES, NotificationPriority, NotificationType, NotifierType} from './form_constants.js'; +import {FormSelectOptions, NOTIFICATION_VIEW_TYPES, NotificationPriority, NotificationType, NotifierType, SystemNotificationWarningLevel} from './form_constants.js'; import {Notification} from './types.js'; // Web component housing the form for chrome://notification-tester. @@ -61,11 +61,11 @@ /* @type {boolean} */ - showDisplaySource: {type: Boolean}, + isSystemNotification: {type: Boolean}, /* @type {boolean} */ - showOriginURL: {type: Boolean}, + isWebNotification: {type: Boolean}, /* @type {boolean} */ @@ -120,9 +120,9 @@ /* * @private */ - sourceSelectList: { + displaySourceSelectList: { type: Array, - value: FormSelectOptions.SOURCE_OPTIONS, + value: FormSelectOptions.DISPLAY_SOURCE_OPTIONS, }, /* * @private @@ -159,6 +159,13 @@ type: Array, value: FormSelectOptions.NOTIFICATION_ID_OPTIONS, }, + /* + * @private + */ + warningLevelSelectList: { + type: Array, + value: FormSelectOptions.WARNING_LEVEL_OPTIONS, + }, }; } @@ -218,6 +225,8 @@ 'notifMetadata.notificationType', NotificationType.NOTIFICATION_TYPE_SIMPLE); this.set('notifMetadata.notifierType', 'System'); + this.set( + 'notifMetadata.warningLevel', SystemNotificationWarningLevel.NORMAL); this.set('notifMetadata.richDataImage', 'none'); this.set('notifMetadata.richDataSmallImage', 'kProductIcon'); this.set('notifMetadata.richDataNeverTimeout', false); @@ -247,8 +256,8 @@ // notifier as a string. notifierTypeChanged_(notifierType) { // notifierType is guaranteed to be 'System' or 'Web'. - this.showDisplaySource = notifierType == 'System'; - this.showOriginURL = notifierType == 'Web'; + this.isSystemNotification = notifierType == 'System'; + this.isWebNotification = notifierType == 'Web'; if (notifierType == 'System') { this.notifMetadata.notifierType = NotifierType.SYSTEM_COMPONENT; return;
diff --git a/chrome/browser/resources/chromeos/notification_tester/types.js b/chrome/browser/resources/chromeos/notification_tester/types.js index 87f00f9..a6822a5 100644 --- a/chrome/browser/resources/chromeos/notification_tester/types.js +++ b/chrome/browser/resources/chromeos/notification_tester/types.js
@@ -15,6 +15,7 @@ * originURL: string, * notificationType: number, * notifierType: number, + * warningLevel: number, * richDataImage: string, * richDataSmallImage: string, * richDataNeverTimeout: boolean,
diff --git a/chrome/browser/resources/new_tab_page/modules/cart/module.ts b/chrome/browser/resources/new_tab_page/modules/cart/module.ts index 2f3c88a..c1a5a56 100644 --- a/chrome/browser/resources/new_tab_page/modules/cart/module.ts +++ b/chrome/browser/resources/new_tab_page/modules/cart/module.ts
@@ -555,7 +555,15 @@ element.headerChipText = loadTimeData.getString('modulesNewTagLabel'); element.headerDescriptionText = loadTimeData.getString('modulesCartWarmWelcome'); + } else { + for (let i = 0; i < carts.length; i++) { + const images = carts[i].productImageUrls; + chrome.metricsPrivate.recordSmallCount( + 'NewTabPage.Carts.CartImageCount', + images === undefined ? 0 : images.length); + } } + element.cartItems = carts; element.showDiscountConsent = consentVisible; element.discountConsentVisible = consentVisible;
diff --git a/chrome/browser/resources/settings/basic_page/basic_page.html b/chrome/browser/resources/settings/basic_page/basic_page.html index 1b918904..931f845 100644 --- a/chrome/browser/resources/settings/basic_page/basic_page.html +++ b/chrome/browser/resources/settings/basic_page/basic_page.html
@@ -122,7 +122,13 @@ language-helper="{{languageHelper}}"> </settings-languages> </if> - <settings-section page-title="$i18n{languagesPageTitle}" + <settings-section +<if expr="not chromeos_ash"> + page-title="$i18n{languagesCardTitle}" +</if> +<if expr="chromeos_ash"> + page-title="$i18n{languagesPageTitle}" +</if> section="languages"> <if expr="chromeos_ash"> <cr-link-row id="openChromeOSLanguagesSettings"
diff --git a/chrome/browser/resources/settings/chromeos/BUILD.gn b/chrome/browser/resources/settings/chromeos/BUILD.gn index 5738066..39f3ea6b 100644 --- a/chrome/browser/resources/settings/chromeos/BUILD.gn +++ b/chrome/browser/resources/settings/chromeos/BUILD.gn
@@ -69,6 +69,7 @@ "chrome://resources/js/cr.m.js", "chrome://resources/mojo/ash/services/cellular_setup/public/mojom/cellular_setup.mojom-lite.js", "chrome://resources/mojo/ash/services/cellular_setup/public/mojom/esim_manager.mojom-lite.js", + "chrome://resources/mojo/chromeos/ash/auth_factor_config/public/mojom/auth_factor_config.mojom-webui.js", "chrome://resources/mojo/chromeos/services/bluetooth_config/public/mojom/cros_bluetooth_config.mojom-webui.js", "chrome://resources/mojo/chromeos/services/network_config/public/mojom/cros_network_config.mojom-lite.js", "chrome://resources/mojo/chromeos/services/network_config/public/mojom/cros_network_config.mojom-webui.js",
diff --git a/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_subpage.html b/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_subpage.html index 7b4c047e..f1b95ee 100644 --- a/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_subpage.html +++ b/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_subpage.html
@@ -114,7 +114,7 @@ <template is="dom-if" if="[[isPhoneHubCameraRollSetupRequired(pageContentData)]]" restamp> - <cr-button on-click="handlePhoneHubSetupClick_" + <cr-button on-click="handleCameraRollSetupClicked_" slot="feature-controller" disabled="[[isPhoneHubDisabled_(pageContentData)]]"> $i18n{multideviceSetupButton} @@ -135,7 +135,7 @@ <template is="dom-if" if="[[isPhoneHubNotificationsSetupRequired(pageContentData)]]" restamp> - <cr-button on-click="handlePhoneHubSetupClick_" + <cr-button on-click="handleNotificationSetupClicked_" slot="feature-controller" disabled="[[isPhoneHubDisabled_(pageContentData)]]"> $i18n{multideviceSetupButton} @@ -156,7 +156,7 @@ <template is="dom-if" if="[[isPhoneHubAppsSetupRequired(pageContentData)]]" restamp> - <cr-button on-click="handlePhoneHubSetupClick_" + <cr-button on-click="handleMessagingAppSetupClicked_" slot="feature-controller" disabled="[[isPhoneHubDisabled_(pageContentData)]]"> $i18n{multideviceSetupButton}
diff --git a/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_subpage.js b/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_subpage.js index 4cf42b1..8b9594f 100644 --- a/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_subpage.js +++ b/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_subpage.js
@@ -308,20 +308,29 @@ } /** @private */ - handlePhoneHubSetupClick_() { + handleNotificationSetupClicked_() { + this.handlePhoneHubSetupClick( + PhoneHubPermissionsSetupFeatureCombination.NOTIFICATION); + } + + /** @private */ + handleCameraRollSetupClicked_() { + this.handlePhoneHubSetupClick( + PhoneHubPermissionsSetupFeatureCombination.CAMERA_ROLL); + } + + /** @private */ + handleMessagingAppSetupClicked_() { + this.handlePhoneHubSetupClick( + PhoneHubPermissionsSetupFeatureCombination.MESSAGING_APP); + } + + /** @param {!PhoneHubPermissionsSetupFeatureCombination} setupMode */ + /** @private */ + handlePhoneHubSetupClick(setupMode) { const permissionSetupRequestedEvent = new CustomEvent( 'permission-setup-requested', {bubbles: true, composed: true}); this.dispatchEvent(permissionSetupRequestedEvent); - let setupMode = PhoneHubPermissionsSetupFeatureCombination.NONE; - if (this.shouldShowPhoneHubCameraRollItem_()) { - setupMode = PhoneHubPermissionsSetupFeatureCombination.CAMERA_ROLL; - } - if (this.shouldShowPhoneHubNotificationsItem_()) { - setupMode = PhoneHubPermissionsSetupFeatureCombination.NOTIFICATION; - } - if (this.shouldShowPhoneHubAppsItem_()) { - setupMode = PhoneHubPermissionsSetupFeatureCombination.MESSAGING_APP; - } this.browserProxy_.logPhoneHubPermissionSetUpButtonClicked(setupMode); }
diff --git a/chrome/browser/resources/settings/chromeos/os_people_page/BUILD.gn b/chrome/browser/resources/settings/chromeos/os_people_page/BUILD.gn index d588d0ce..1ab36ab 100644 --- a/chrome/browser/resources/settings/chromeos/os_people_page/BUILD.gn +++ b/chrome/browser/resources/settings/chromeos/os_people_page/BUILD.gn
@@ -7,7 +7,7 @@ import("../os_settings.gni") js_type_check("closure_compile_module") { - closure_flags = os_settings_closure_flags + closure_flags = os_settings_closure_flags + mojom_js_args is_polymer3 = true deps = [ ":account_manager", @@ -88,6 +88,7 @@ "..:route_observer_behavior", "../..:router", "../multidevice_page:multidevice_smartlock_item", + "//chromeos/ash/services/auth_factor_config/public/mojom:mojom_webui_js", "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", "//ui/webui/resources/cr_components/chromeos/quick_unlock:lock_screen_constants.m", "//ui/webui/resources/js:assert.m",
diff --git a/chrome/browser/resources/settings/chromeos/os_people_page/lock_state_behavior.js b/chrome/browser/resources/settings/chromeos/os_people_page/lock_state_behavior.js index a65ab56..7885df89 100644 --- a/chrome/browser/resources/settings/chromeos/os_people_page/lock_state_behavior.js +++ b/chrome/browser/resources/settings/chromeos/os_people_page/lock_state_behavior.js
@@ -4,6 +4,7 @@ import {I18nBehavior, I18nBehaviorInterface} from 'chrome://resources/js/i18n_behavior.m.js'; import {WebUIListenerBehavior, WebUIListenerBehaviorInterface} from 'chrome://resources/js/web_ui_listener_behavior.m.js'; +import {AuthFactorConfig, RecoveryFactorEditor} from 'chrome://resources/mojo/chromeos/ash/services/auth_factor_config/public/mojom/auth_factor_config.mojom-webui.js'; /** * @fileoverview @@ -62,6 +63,21 @@ * @type {QuickUnlockPrivate} */ quickUnlockPrivate: {type: Object, value: chrome.quickUnlockPrivate}, + + /** + * Interface for calls to the ash AuthFactorConfig service. May be + * overridden by tests. + * @type {AuthFactorConfigInterface} + */ + authFactorConfig: {type: Object, value: AuthFactorConfig.getRemote()}, + + /** + * Interface for calls to the ash RecoveryFactorEditor service. May be + * overridden by tests. + * @type {RecoveryFactorEditorInterface} + */ + recoveryFactorEditor: + {type: Object, value: RecoveryFactorEditor.getRemote()}, }, /** @override */
diff --git a/chrome/browser/resources/settings/privacy_page/security_page.html b/chrome/browser/resources/settings/privacy_page/security_page.html index 00fc437..31c656e9 100644 --- a/chrome/browser/resources/settings/privacy_page/security_page.html +++ b/chrome/browser/resources/settings/privacy_page/security_page.html
@@ -193,7 +193,7 @@ </template> </if> -<if expr="use_nss_certs or is_win or is_macosx"> +<if expr="(use_nss_certs or is_win or is_macosx) and not chrome_root_store_supported"> <cr-link-row id="manageCertificates" class="hr" <if expr="not use_nss_certs"> @@ -206,6 +206,34 @@ sub-label="$i18n{manageCertificatesDescription}" on-click="onManageCertificatesClick_"></cr-link-row> </if> + +<if expr="chrome_root_store_supported"> + <template is="dom-if" if="[[!showChromeRootStoreCertificates_]]"> + <cr-link-row id="manageCertificates" + class="hr" + external + label="$i18n{manageCertificates}" + sub-label="$i18n{manageCertificatesDescription}" + on-click="onManageCertificatesClick_"></cr-link-row> + </template> + + <template is="dom-if" if="[[showChromeRootStoreCertificates_]]"> + <cr-link-row id="manageCertificates" + class="hr" + external + label="$i18n{manageDeviceCertificates}" + sub-label="$i18n{manageDeviceCertificatesDescription}" + on-click="onManageCertificatesClick_"></cr-link-row> + + <cr-link-row id="chromeCertificates" + class="hr" + external + label="$i18n{chromeCertificates}" + sub-label="$i18n{chromeCertificatesDescription}" + on-click="onChromeCertificatesClick_"></cr-link-row> + </template> +</if> + <cr-link-row id="advanced-protection-program-link" class="hr" label="$i18n{advancedProtectionProgramTitle}"
diff --git a/chrome/browser/resources/settings/privacy_page/security_page.ts b/chrome/browser/resources/settings/privacy_page/security_page.ts index a281ce7..01e2c06 100644 --- a/chrome/browser/resources/settings/privacy_page/security_page.ts +++ b/chrome/browser/resources/settings/privacy_page/security_page.ts
@@ -24,7 +24,7 @@ import {FocusConfig} from '../focus_config.js'; import {loadTimeData} from '../i18n_setup.js'; import {MetricsBrowserProxy, MetricsBrowserProxyImpl, PrivacyElementInteractions, SafeBrowsingInteractions} from '../metrics_browser_proxy.js'; -// <if expr="chromeos_ash or chromeos_lacros"> +// <if expr="chromeos_ash or chromeos_lacros or chrome_root_store_supported"> import {OpenWindowProxyImpl} from '../open_window_proxy.js'; // </if> @@ -85,6 +85,20 @@ notify: true, }, + // <if expr="chrome_root_store_supported"> + /** + * Whether we should adjust Manage Certificates links to indicate + * support for Chrome Root Store. + */ + showChromeRootStoreCertificates_: { + type: Boolean, + readOnly: true, + value: function() { + return loadTimeData.getBoolean('showChromeRootStoreCertificates'); + }, + }, + // </if> + /** * Whether the HTTPS-Only Mode setting should be displayed. */ @@ -157,7 +171,9 @@ showDisableSafebrowsingDialog_: Boolean, }; } - + // <if expr="chrome_root_store_supported"> + private showChromeRootStoreCertificates_: boolean; + // </if> private showHttpsOnlyModeSetting_: boolean; private showSecureDnsSetting_: boolean; @@ -288,6 +304,13 @@ PrivacyElementInteractions.MANAGE_CERTIFICATES); } + // <if expr="chrome_root_store_supported"> + private onChromeCertificatesClick_() { + OpenWindowProxyImpl.getInstance().openURL( + loadTimeData.getString('chromeRootStoreHelpCenterURL')); + } + // </if> + private onAdvancedProtectionProgramLinkClick_() { window.open(loadTimeData.getString('advancedProtectionURL')); }
diff --git a/chrome/browser/serial/serial_chooser_context.cc b/chrome/browser/serial/serial_chooser_context.cc index ce0459f..da15edf 100644 --- a/chrome/browser/serial/serial_chooser_context.cc +++ b/chrome/browser/serial/serial_chooser_context.cc
@@ -71,55 +71,55 @@ } base::Value PortInfoToValue(const device::mojom::SerialPortInfo& port) { - base::Value value(base::Value::Type::DICTIONARY); + base::Value::Dict value; if (port.display_name && !port.display_name->empty()) - value.SetStringKey(kPortNameKey, *port.display_name); + value.Set(kPortNameKey, *port.display_name); else - value.SetStringKey(kPortNameKey, port.path.LossyDisplayName()); + value.Set(kPortNameKey, port.path.LossyDisplayName()); if (!SerialChooserContext::CanStorePersistentEntry(port)) { - value.SetStringKey(kTokenKey, EncodeToken(port.token)); - return value; + value.Set(kTokenKey, EncodeToken(port.token)); + return base::Value(std::move(value)); } #if BUILDFLAG(IS_WIN) // Windows provides a handy device identifier which we can rely on to be // sufficiently stable for identifying devices across restarts. - value.SetStringKey(kDeviceInstanceIdKey, port.device_instance_id); + value.Set(kDeviceInstanceIdKey, port.device_instance_id); #else DCHECK(port.has_vendor_id); - value.SetIntKey(kVendorIdKey, port.vendor_id); + value.Set(kVendorIdKey, port.vendor_id); DCHECK(port.has_product_id); - value.SetIntKey(kProductIdKey, port.product_id); + value.Set(kProductIdKey, port.product_id); DCHECK(port.serial_number); - value.SetStringKey(kSerialNumberKey, *port.serial_number); + value.Set(kSerialNumberKey, *port.serial_number); #if BUILDFLAG(IS_MAC) DCHECK(port.usb_driver_name && !port.usb_driver_name->empty()); - value.SetStringKey(kUsbDriverKey, *port.usb_driver_name); + value.Set(kUsbDriverKey, *port.usb_driver_name); #endif // BUILDFLAG(IS_MAC) #endif // BUILDFLAG(IS_WIN) - return value; + return base::Value(std::move(value)); } base::Value VendorAndProductIdsToValue(uint16_t vendor_id, uint16_t product_id) { - base::Value object(base::Value::Type::DICTIONARY); + base::Value::Dict object; const char* product_name = device::UsbIds::GetProductName(vendor_id, product_id); if (product_name) { - object.SetStringKey(kPortNameKey, product_name); + object.Set(kPortNameKey, product_name); } else { const char* vendor_name = device::UsbIds::GetVendorName(vendor_id); if (vendor_name) { - object.SetStringKey( + object.Set( kPortNameKey, l10n_util::GetStringFUTF16( IDS_SERIAL_POLICY_DESCRIPTION_FOR_USB_PRODUCT_ID_AND_VENDOR_NAME, base::ASCIIToUTF16(base::StringPrintf("%04X", product_id)), base::UTF8ToUTF16(vendor_name))); } else { - object.SetStringKey( + object.Set( kPortNameKey, l10n_util::GetStringFUTF16( IDS_SERIAL_POLICY_DESCRIPTION_FOR_USB_PRODUCT_ID_AND_VENDOR_ID, @@ -127,25 +127,24 @@ base::ASCIIToUTF16(base::StringPrintf("%04X", vendor_id)))); } } - return object; + return base::Value(std::move(object)); } base::Value VendorIdToValue(uint16_t vendor_id) { - base::Value object(base::Value::Type::DICTIONARY); + base::Value::Dict object; const char* vendor_name = device::UsbIds::GetVendorName(vendor_id); if (vendor_name) { - object.SetStringKey(kPortNameKey, - l10n_util::GetStringFUTF16( - IDS_SERIAL_POLICY_DESCRIPTION_FOR_USB_VENDOR_NAME, - base::UTF8ToUTF16(vendor_name))); + object.Set(kPortNameKey, + l10n_util::GetStringFUTF16( + IDS_SERIAL_POLICY_DESCRIPTION_FOR_USB_VENDOR_NAME, + base::UTF8ToUTF16(vendor_name))); } else { - object.SetStringKey( - kPortNameKey, - l10n_util::GetStringFUTF16( - IDS_SERIAL_POLICY_DESCRIPTION_FOR_USB_VENDOR_ID, - base::ASCIIToUTF16(base::StringPrintf("%04X", vendor_id)))); + object.Set(kPortNameKey, + l10n_util::GetStringFUTF16( + IDS_SERIAL_POLICY_DESCRIPTION_FOR_USB_VENDOR_ID, + base::ASCIIToUTF16(base::StringPrintf("%04X", vendor_id)))); } - return object; + return base::Value(std::move(object)); } void RecordPermissionRevocation(SerialPermissionRevoked type) { @@ -267,13 +266,12 @@ } if (base::Contains(policy->all_ports_policy(), origin)) { - base::Value object(base::Value::Type::DICTIONARY); - object.SetStringKey(kPortNameKey, - l10n_util::GetStringUTF16( - IDS_SERIAL_POLICY_DESCRIPTION_FOR_ANY_PORT)); + base::Value::Dict object; + object.Set(kPortNameKey, l10n_util::GetStringUTF16( + IDS_SERIAL_POLICY_DESCRIPTION_FOR_ANY_PORT)); objects.push_back(std::make_unique<ObjectPermissionContextBase::Object>( - origin, std::move(object), content_settings::SETTING_SOURCE_POLICY, - IsOffTheRecord())); + origin, base::Value(std::move(object)), + content_settings::SETTING_SOURCE_POLICY, IsOffTheRecord())); } } @@ -325,14 +323,13 @@ } } - base::Value object(base::Value::Type::DICTIONARY); - object.SetStringKey( - kPortNameKey, - l10n_util::GetStringUTF16(IDS_SERIAL_POLICY_DESCRIPTION_FOR_ANY_PORT)); + base::Value::Dict object; + object.Set(kPortNameKey, l10n_util::GetStringUTF16( + IDS_SERIAL_POLICY_DESCRIPTION_FOR_ANY_PORT)); for (const auto& origin : policy->all_ports_policy()) { objects.push_back(std::make_unique<ObjectPermissionContextBase::Object>( - origin, object.Clone(), content_settings::SETTING_SOURCE_POLICY, - IsOffTheRecord())); + origin, base::Value(object.Clone()), + content_settings::SETTING_SOURCE_POLICY, IsOffTheRecord())); } }
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/OmniboxSuggestionUiType.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/OmniboxSuggestionUiType.java index 0340ee0e..7dd9810 100644 --- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/OmniboxSuggestionUiType.java +++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/OmniboxSuggestionUiType.java
@@ -9,12 +9,24 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -/** The different types of view that a suggestion can be. */ +/** + * The different types of view that a suggestion can be. + * + * When modifying this list, please also update the + * - OmniboxSuggestionsDropdown#HistogramRecordingRecycledViewPool, + * - OmniboxSuggestionUiType histogram enum + * to reflect the expected/anticipated volume of views that may be reused and appropriate + * histogram details. + * + * Please note that the types below are also being recorded in a separate histogram, see: + * - SuggestionsMetrics#recordSuggestionsViewCreatedType() + * - SuggestionsMetrics#recordSuggestionsViewReusedType(). + */ @IntDef({OmniboxSuggestionUiType.DEFAULT, OmniboxSuggestionUiType.EDIT_URL_SUGGESTION, OmniboxSuggestionUiType.ANSWER_SUGGESTION, OmniboxSuggestionUiType.ENTITY_SUGGESTION, OmniboxSuggestionUiType.TAIL_SUGGESTION, OmniboxSuggestionUiType.CLIPBOARD_SUGGESTION, OmniboxSuggestionUiType.HEADER, OmniboxSuggestionUiType.TILE_NAVSUGGEST, - OmniboxSuggestionUiType.PEDAL_SUGGESTION}) + OmniboxSuggestionUiType.PEDAL_SUGGESTION, OmniboxSuggestionUiType.COUNT}) @Retention(RetentionPolicy.SOURCE) public @interface OmniboxSuggestionUiType { int DEFAULT = 0; @@ -26,4 +38,6 @@ int HEADER = 6; int TILE_NAVSUGGEST = 7; int PEDAL_SUGGESTION = 8; + + int COUNT = 9; }
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/OmniboxSuggestionsDropdown.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/OmniboxSuggestionsDropdown.java index b531509..1754fba4 100644 --- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/OmniboxSuggestionsDropdown.java +++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/OmniboxSuggestionsDropdown.java
@@ -156,6 +156,11 @@ public ViewHolder getRecycledView(int viewType) { ViewHolder result = super.getRecycledView(viewType); SuggestionsMetrics.recordSuggestionViewReused(result != null); + if (result == null) { + SuggestionsMetrics.recordSuggestionsViewCreatedType(viewType); + } else { + SuggestionsMetrics.recordSuggestionsViewReusedType(viewType); + } return result; } }
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/SuggestionsMetrics.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/SuggestionsMetrics.java index e1fd80db..48bc177e 100644 --- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/SuggestionsMetrics.java +++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/SuggestionsMetrics.java
@@ -70,6 +70,31 @@ } /** + * Record the type of the suggestion view that had to be constructed. + * Recorded view type could not be retrieved from the Recycled View Pool and had to + * be re-created. + * Relevant for Omnibox recycler view improvements. + * + * @param type The type of view that needed to be recreated. + */ + static final void recordSuggestionsViewCreatedType(@OmniboxSuggestionUiType int type) { + RecordHistogram.recordEnumeratedHistogram( + "Android.Omnibox.SuggestionView.CreatedType", type, OmniboxSuggestionUiType.COUNT); + } + + /** + * Record the type of the suggestion view that was re-used. + * Recorded view type was retrieved from the Recycled View Pool. + * Relevant for Omnibox recycler view improvements. + * + * @param type The type of view that was reused from pool. + */ + static final void recordSuggestionsViewReusedType(@OmniboxSuggestionUiType int type) { + RecordHistogram.recordEnumeratedHistogram( + "Android.Omnibox.SuggestionView.ReusedType", type, OmniboxSuggestionUiType.COUNT); + } + + /** * Record whether the interaction with the Omnibox resulted with a navigation (true) or user * leaving the omnibox and suggestions list. *
diff --git a/chrome/browser/ui/ash/app_access_notifier.cc b/chrome/browser/ui/ash/app_access_notifier.cc index 10d74764..1b805584 100644 --- a/chrome/browser/ui/ash/app_access_notifier.cc +++ b/chrome/browser/ui/ash/app_access_notifier.cc
@@ -6,6 +6,8 @@ #include <string> +#include "ash/constants/ash_features.h" +#include "ash/system/privacy/privacy_indicators_controller.h" #include "base/check.h" #include "base/containers/cxx20_erase.h" #include "base/strings/string_util.h" @@ -101,7 +103,16 @@ const apps::CapabilityAccessUpdate& update) { base::Erase(mic_using_app_ids[active_user_account_id_], update.AppId()); - if (update.Microphone() == apps::mojom::OptionalBool::kTrue) { + bool microphone_is_used = + update.Microphone() == apps::mojom::OptionalBool::kTrue; + bool camera_is_used = update.Camera() == apps::mojom::OptionalBool::kTrue; + + if (ash::features::IsPrivacyIndicatorsEnabled()) { + ash::ModifyPrivacyIndicatorsNotification(update.AppId(), camera_is_used, + microphone_is_used); + } + + if (microphone_is_used) { mic_using_app_ids[active_user_account_id_].push_front(update.AppId()); } }
diff --git a/chrome/browser/ui/ash/app_access_notifier_unittest.cc b/chrome/browser/ui/ash/app_access_notifier_unittest.cc index 64b77e1e..59b5f75 100644 --- a/chrome/browser/ui/ash/app_access_notifier_unittest.cc +++ b/chrome/browser/ui/ash/app_access_notifier_unittest.cc
@@ -6,7 +6,9 @@ #include <memory> +#include "ash/constants/ash_features.h" #include "base/strings/utf_string_conversions.h" +#include "base/test/scoped_feature_list.h" #include "components/account_id/account_id.h" #include "components/services/app_service/public/cpp/app_capability_access_cache.h" #include "components/services/app_service/public/cpp/app_capability_access_cache_wrapper.h" @@ -18,6 +20,9 @@ #include "components/user_manager/fake_user_manager.h" #include "components/user_manager/scoped_user_manager.h" #include "testing/gtest/include/gtest/gtest.h" +#include "ui/message_center/message_center.h" + +const char kPrivacyIndicatorsNotificationIdPrefix[] = "privacy-indicators"; class TestAppAccessNotifier : public AppAccessNotifier { public: @@ -37,7 +42,8 @@ AccountId user_account_id_ = EmptyAccountId(); }; -class AppAccessNotifierTest : public testing::Test { +class AppAccessNotifierTest : public testing::Test, + public testing::WithParamInterface<bool> { public: AppAccessNotifierTest() = default; AppAccessNotifierTest(const AppAccessNotifierTest&) = delete; @@ -46,6 +52,10 @@ void SetUp() override { testing::Test::SetUp(); + message_center::MessageCenter::Initialize(); + + scoped_feature_list_.InitWithFeatureState( + ash::features::kPrivacyIndicators, IsPrivacyIndicatorsFeatureEnabled()); auto fake_user_manager = std::make_unique<user_manager::FakeUserManager>(); fake_user_manager_ = fake_user_manager.get(); @@ -60,9 +70,12 @@ void TearDown() override { microphone_mute_notification_delegate_.reset(); + message_center::MessageCenter::Shutdown(); testing::Test::TearDown(); } + bool IsPrivacyIndicatorsFeatureEnabled() const { return GetParam(); } + void SetupPrimaryUser() { registry_cache_primary_user_.SetAccountId(account_id_primary_user_); apps::AppRegistryCacheWrapper::Get().AddAppRegistryCache( @@ -102,7 +115,7 @@ cap_cache, reg_cache); } - static apps::AppPtr MakeApp(const char* app_id, const char* name) { + static apps::AppPtr MakeApp(const std::string app_id, const char* name) { apps::AppPtr app = std::make_unique<apps::App>(apps::AppType::kChromeApp, app_id); app->name = name; @@ -111,19 +124,21 @@ } static apps::mojom::CapabilityAccessPtr MakeCapabilityAccess( - const char* app_id, + const std::string app_id, + apps::mojom::OptionalBool camera, apps::mojom::OptionalBool microphone) { apps::mojom::CapabilityAccessPtr access = apps::mojom::CapabilityAccess::New(); access->app_id = app_id; - access->camera = apps::mojom::OptionalBool::kFalse; + access->camera = camera; access->microphone = microphone; return access; } - void LaunchAppUsingMicrophone(const char* id, - const char* name, - bool use_microphone) { + void LaunchAppUsingCameraOrMicrophone(const std::string id, + const char* name, + bool use_camera, + bool use_microphone) { bool is_primary_user = (microphone_mute_notification_delegate_->GetActiveUserAccountId() == account_id_primary_user_); @@ -149,8 +164,11 @@ std::vector<apps::mojom::CapabilityAccessPtr> capability_access_deltas; capability_access_deltas.push_back(MakeCapabilityAccess( - id, use_microphone ? apps::mojom::OptionalBool::kTrue - : apps::mojom::OptionalBool::kFalse)); + id, + use_camera ? apps::mojom::OptionalBool::kTrue + : apps::mojom::OptionalBool::kFalse, + use_microphone ? apps::mojom::OptionalBool::kTrue + : apps::mojom::OptionalBool::kFalse)); cap_cache->OnCapabilityAccesses(std::move(capability_access_deltas)); } @@ -174,24 +192,33 @@ user_manager::FakeUserManager* fake_user_manager_ = nullptr; std::unique_ptr<user_manager::ScopedUserManager> scoped_user_manager_; + + base::test::ScopedFeatureList scoped_feature_list_; }; -TEST_F(AppAccessNotifierTest, NoAppsLaunched) { +INSTANTIATE_TEST_SUITE_P( + All, + AppAccessNotifierTest, + /*IsPrivacyIndicatorsFeatureEnabled()=*/::testing::Bool()); + +TEST_P(AppAccessNotifierTest, NoAppsLaunched) { // Should return a completely value-free app_name. absl::optional<std::u16string> app_name = GetAppAccessingMicrophone(); EXPECT_FALSE(app_name.has_value()); } -TEST_F(AppAccessNotifierTest, AppLaunchedNotUsingMicrophone) { - LaunchAppUsingMicrophone("id_rose", "name_rose", false); +TEST_P(AppAccessNotifierTest, AppLaunchedNotUsingMicrophone) { + LaunchAppUsingCameraOrMicrophone("id_rose", "name_rose", /*use_camera=*/false, + /*use_microphone=*/false); // Should return a completely value-free app_name. absl::optional<std::u16string> app_name = GetAppAccessingMicrophone(); EXPECT_FALSE(app_name.has_value()); } -TEST_F(AppAccessNotifierTest, AppLaunchedUsingMicrophone) { - LaunchAppUsingMicrophone("id_rose", "name_rose", true); +TEST_P(AppAccessNotifierTest, AppLaunchedUsingMicrophone) { + LaunchAppUsingCameraOrMicrophone("id_rose", "name_rose", /*use_camera=*/false, + /*use_microphone=*/true); // Should return the name of our app. absl::optional<std::u16string> app_name = GetAppAccessingMicrophone(); @@ -199,11 +226,15 @@ EXPECT_EQ(app_name, u"name_rose"); } -TEST_F(AppAccessNotifierTest, MultipleAppsLaunchedUsingMicrophone) { - LaunchAppUsingMicrophone("id_rose", "name_rose", true); - LaunchAppUsingMicrophone("id_mars", "name_mars", true); - LaunchAppUsingMicrophone("id_zara", "name_zara", true); - LaunchAppUsingMicrophone("id_oscar", "name_oscar", false); +TEST_P(AppAccessNotifierTest, MultipleAppsLaunchedUsingMicrophone) { + LaunchAppUsingCameraOrMicrophone("id_rose", "name_rose", /*use_camera=*/false, + /*use_microphone=*/true); + LaunchAppUsingCameraOrMicrophone("id_mars", "name_mars", /*use_camera=*/false, + /*use_microphone=*/true); + LaunchAppUsingCameraOrMicrophone("id_zara", "name_zara", /*use_camera=*/false, + /*use_microphone=*/true); + LaunchAppUsingCameraOrMicrophone( + "id_oscar", "name_oscar", /*use_camera=*/false, /*use_microphone=*/false); // Most recently launched mic-using app should be the one we use for the // notification. @@ -212,20 +243,22 @@ EXPECT_EQ(app_name, u"name_zara"); // Oscar starts using the mic, Oscar shows up in the notification. - LaunchAppUsingMicrophone("id_oscar", "name_oscar", true); + LaunchAppUsingCameraOrMicrophone( + "id_oscar", "name_oscar", /*use_camera=*/false, /*use_microphone=*/true); app_name = GetAppAccessingMicrophone(); EXPECT_TRUE(app_name.has_value()); EXPECT_EQ(app_name, u"name_oscar"); // If we "kill" Oscar (set to no longer be using the mic or camera), // the notification shows Zara again. - LaunchAppUsingMicrophone("id_oscar", "name_oscar", false); + LaunchAppUsingCameraOrMicrophone( + "id_oscar", "name_oscar", /*use_camera=*/false, /*use_microphone=*/false); app_name = GetAppAccessingMicrophone(); EXPECT_TRUE(app_name.has_value()); EXPECT_EQ(app_name, u"name_zara"); } -TEST_F(AppAccessNotifierTest, MultipleUsers) { +TEST_P(AppAccessNotifierTest, MultipleUsers) { // Prepare the secondary user. SetupSecondaryUser(); @@ -233,7 +266,9 @@ SetActiveUserAccountId(account_id_primary_user_); // Primary user launches a mic-using app. - LaunchAppUsingMicrophone("id_primary_user", "name_primary_user", true); + LaunchAppUsingCameraOrMicrophone("id_primary_user", "name_primary_user", + /*use_camera=*/false, + /*use_microphone=*/true); // App we just launched should show up in the notification. absl::optional<std::u16string> app_name = GetAppAccessingMicrophone(); @@ -244,7 +279,9 @@ SetActiveUserAccountId(account_id_secondary_user_); // Secondary user launches a mic-using app. - LaunchAppUsingMicrophone("id_secondary_user", "name_secondary_user", true); + LaunchAppUsingCameraOrMicrophone("id_secondary_user", "name_secondary_user", + /*use_camera=*/false, + /*use_microphone=*/true); // App we just launched should show up in the notification. app_name = GetAppAccessingMicrophone(); @@ -254,7 +291,9 @@ // Switch back to the primary user and "kill" the app it was running, no app // name to show. SetActiveUserAccountId(account_id_primary_user_); - LaunchAppUsingMicrophone("id_primary_user", "name_primary_user", false); + LaunchAppUsingCameraOrMicrophone("id_primary_user", "name_primary_user", + /*use_camera=*/false, + /*use_microphone=*/false); app_name = GetAppAccessingMicrophone(); EXPECT_FALSE(app_name.has_value()); @@ -267,12 +306,14 @@ // Now "kill" our secondary user's app and verify that there's no name to // show. - LaunchAppUsingMicrophone("id_secondary_user", "name_secondary_user", false); + LaunchAppUsingCameraOrMicrophone("id_secondary_user", "name_secondary_user", + /*use_camera=*/false, + /*use_microphone=*/false); app_name = GetAppAccessingMicrophone(); EXPECT_FALSE(app_name.has_value()); } -TEST_F(AppAccessNotifierTest, MultipleUsersMultipleApps) { +TEST_P(AppAccessNotifierTest, MultipleUsersMultipleApps) { // Prepare the secondary user. SetupSecondaryUser(); @@ -280,7 +321,9 @@ SetActiveUserAccountId(account_id_primary_user_); // Primary user launches a mic-using app. - LaunchAppUsingMicrophone("id_primary_user", "name_primary_user", true); + LaunchAppUsingCameraOrMicrophone("id_primary_user", "name_primary_user", + /*use_camera=*/false, + /*use_microphone=*/true); // App we just launched should show up in the notification. absl::optional<std::u16string> app_name = GetAppAccessingMicrophone(); @@ -288,8 +331,9 @@ EXPECT_EQ(app_name, u"name_primary_user"); // Primary user launches a second mic-using app. - LaunchAppUsingMicrophone("id_primary_user", "name_primary_user_another_app", - true); + LaunchAppUsingCameraOrMicrophone( + "id_primary_user", "name_primary_user_another_app", /*use_camera=*/false, + /*use_microphone=*/true); // App we just launched should show up in the notification. app_name = GetAppAccessingMicrophone(); @@ -300,7 +344,9 @@ SetActiveUserAccountId(account_id_secondary_user_); // Secondary user launches a mic-using app. - LaunchAppUsingMicrophone("id_secondary_user", "name_secondary_user", true); + LaunchAppUsingCameraOrMicrophone("id_secondary_user", "name_secondary_user", + /*use_camera=*/false, + /*use_microphone=*/true); // App we just launched should show up in the notification. app_name = GetAppAccessingMicrophone(); @@ -308,8 +354,9 @@ EXPECT_EQ(app_name, u"name_secondary_user"); // Secondary user launches a second mic-using app. - LaunchAppUsingMicrophone("id_secondary_user", - "name_secondary_user_another_app", true); + LaunchAppUsingCameraOrMicrophone( + "id_secondary_user", "name_secondary_user_another_app", + /*use_camera=*/false, /*use_microphone=*/true); // App we just launched should show up in the notification. app_name = GetAppAccessingMicrophone(); @@ -324,3 +371,36 @@ EXPECT_TRUE(app_name.has_value()); EXPECT_EQ(app_name, u"name_primary_user_another_app"); } + +TEST_P(AppAccessNotifierTest, AppAccessNotification) { + if (!IsPrivacyIndicatorsFeatureEnabled()) + return; + + // Test that notifications get created/removed when an app is accessing camera + // or microphone. + const std::string id1 = "test_app_id_1"; + const std::string id2 = "test_app_id_2"; + + LaunchAppUsingCameraOrMicrophone(id1, "test_app_name", /*use_camera=*/false, + /*use_microphone=*/true); + LaunchAppUsingCameraOrMicrophone(id2, "test_app_name", /*use_camera=*/true, + /*use_microphone=*/false); + EXPECT_TRUE(message_center::MessageCenter::Get()->FindNotificationById( + kPrivacyIndicatorsNotificationIdPrefix + id1)); + EXPECT_TRUE(message_center::MessageCenter::Get()->FindNotificationById( + kPrivacyIndicatorsNotificationIdPrefix + id2)); + + LaunchAppUsingCameraOrMicrophone(id1, "test_app_name", /*use_camera=*/false, + /*use_microphone=*/false); + LaunchAppUsingCameraOrMicrophone(id2, "test_app_name", /*use_camera=*/false, + /*use_microphone=*/false); + EXPECT_FALSE(message_center::MessageCenter::Get()->FindNotificationById( + kPrivacyIndicatorsNotificationIdPrefix + id1)); + EXPECT_FALSE(message_center::MessageCenter::Get()->FindNotificationById( + kPrivacyIndicatorsNotificationIdPrefix + id2)); + + LaunchAppUsingCameraOrMicrophone(id1, "test_app_name", /*use_camera=*/true, + /*use_microphone=*/true); + EXPECT_TRUE(message_center::MessageCenter::Get()->FindNotificationById( + kPrivacyIndicatorsNotificationIdPrefix + id1)); +}
diff --git a/chrome/browser/ui/ash/chrome_shell_delegate.cc b/chrome/browser/ui/ash/chrome_shell_delegate.cc index c39ef789..f24edfdc 100644 --- a/chrome/browser/ui/ash/chrome_shell_delegate.cc +++ b/chrome/browser/ui/ash/chrome_shell_delegate.cc
@@ -54,6 +54,8 @@ #include "chrome/common/chrome_switches.h" #include "components/ui_devtools/devtools_server.h" #include "components/user_manager/user_manager.h" +#include "components/version_info/channel.h" +#include "components/version_info/version_info.h" #include "content/public/browser/device_service.h" #include "content/public/browser/media_session_service.h" #include "content/public/browser/render_widget_host.h" @@ -342,3 +344,7 @@ version_info::Channel ChromeShellDelegate::GetChannel() { return chrome::GetChannel(); } + +std::string ChromeShellDelegate::GetVersionString() { + return version_info::GetVersionNumber(); +}
diff --git a/chrome/browser/ui/ash/chrome_shell_delegate.h b/chrome/browser/ui/ash/chrome_shell_delegate.h index 97714bb..67f9a3e0 100644 --- a/chrome/browser/ui/ash/chrome_shell_delegate.h +++ b/chrome/browser/ui/ash/chrome_shell_delegate.h
@@ -6,6 +6,7 @@ #define CHROME_BROWSER_UI_ASH_CHROME_SHELL_DELEGATE_H_ #include <memory> +#include <string> #include "ash/shell_delegate.h" #include "base/callback_forward.h" @@ -63,6 +64,7 @@ static void ResetDisableLoggingRedirectForTesting(); const GURL& GetLastCommittedURLForWindowIfAny(aura::Window* window) override; version_info::Channel GetChannel() override; + std::string GetVersionString() override; }; #endif // CHROME_BROWSER_UI_ASH_CHROME_SHELL_DELEGATE_H_
diff --git a/chrome/browser/ui/ash/clipboard_history_browsertest.cc b/chrome/browser/ui/ash/clipboard_history_browsertest.cc index 6c70652..e066bd9 100644 --- a/chrome/browser/ui/ash/clipboard_history_browsertest.cc +++ b/chrome/browser/ui/ash/clipboard_history_browsertest.cc
@@ -40,6 +40,7 @@ #include "content/public/test/browser_test.h" #include "content/public/test/browser_test_utils.h" #include "net/dns/mock_host_resolver.h" +#include "ui/aura/client/capture_client_observer.h" #include "ui/base/clipboard/clipboard_data.h" #include "ui/base/clipboard/clipboard_monitor.h" #include "ui/base/clipboard/clipboard_non_backed.h" @@ -52,6 +53,7 @@ #include "ui/views/controls/menu/menu_item_view.h" #include "ui/views/controls/textfield/textfield.h" #include "ui/views/widget/widget.h" +#include "ui/wm/core/capture_controller.h" namespace { @@ -1221,12 +1223,40 @@ } }; +class MockCaptureChangeObserver : public aura::client::CaptureClientObserver { + public: + explicit MockCaptureChangeObserver(const std::string& msg) : message_(msg) { + wm::CaptureController::Get()->AddObserver(this); + } + MockCaptureChangeObserver(const MockCaptureChangeObserver&) = delete; + MockCaptureChangeObserver& operator=(const MockCaptureChangeObserver&) = + default; + ~MockCaptureChangeObserver() override { + wm::CaptureController::Get()->RemoveObserver(this); + } + + // aura::client::CaptureClientObserver: + void OnCaptureChanged(aura::Window* lost_capture, + aura::Window* gained_capture) override { + ADD_FAILURE() << "MockCaptureChangeObserver::OnCaptureChanged: " << message_ + << " " + << (lost_capture ? lost_capture->GetName() + : "null-lost_capture") + << " " + << (gained_capture ? gained_capture->GetName() + : "nullptr-gained_capture"); + } + + private: + const std::string message_; +}; + // Verifies that the images rendered from the copied web contents should // show in the clipboard history menu. Switching the auto resize mode is covered // in this test case. // Flaky: crbug/1224777 IN_PROC_BROWSER_TEST_F(ClipboardHistoryWebContentsBrowserTest, - DISABLED_VerifyHTMLRendering) { + VerifyHTMLRendering) { // Load the web page which contains images and text. ASSERT_TRUE(ui_test_utils::NavigateToURL( browser(), embedded_test_server()->GetURL("/image-and-text.html"))); @@ -1253,6 +1283,9 @@ ash::Shell::GetPrimaryRootWindow()); event_generator->PressAndReleaseKey(ui::VKEY_V, ui::EF_COMMAND_DOWN); + absl::optional<MockCaptureChangeObserver> observer; + observer.emplace("first"); + // Render HTML with auto-resize mode enabled. Wait until the rendering // finishes. ImageModelRequestTestParams test_params(/*callback=*/base::NullCallback(), @@ -1270,6 +1303,8 @@ ClipboardImageModelRequest::RequestStopReason::kFulfilled), 1); + observer.reset(); + // Verify that the clipboard history menu shows. Then close the menu. EXPECT_TRUE(GetClipboardHistoryController()->IsMenuShowing()); event_generator->PressAndReleaseKey(ui::VKEY_ESCAPE, ui::EF_NONE); @@ -1290,6 +1325,8 @@ // Show the clipboard history menu. event_generator->PressAndReleaseKey(ui::VKEY_V, ui::EF_COMMAND_DOWN); + observer.emplace("second"); + // Render HTML with auto-resize mode disabled. Wait until the rendering // finishes. test_params.enforce_auto_resize = false; @@ -1306,6 +1343,8 @@ ClipboardImageModelRequest::RequestStopReason::kFulfilled), 2); + observer.reset(); + // Verify that the clipboard history menu's status. EXPECT_TRUE(GetClipboardHistoryController()->IsMenuShowing()); ASSERT_EQ(2, GetContextMenu()->GetMenuItemsCount());
diff --git a/chrome/browser/ui/ash/shelf/chrome_shelf_controller_util.cc b/chrome/browser/ui/ash/shelf/chrome_shelf_controller_util.cc index 28a3a20..4a9daea 100644 --- a/chrome/browser/ui/ash/shelf/chrome_shelf_controller_util.cc +++ b/chrome/browser/ui/ash/shelf/chrome_shelf_controller_util.cc
@@ -184,21 +184,21 @@ return ChromeShelfController::instance()->shelf_model()->IsAppPinned(app_id); } -apps::mojom::LaunchSource ShelfLaunchSourceToAppsLaunchSource( +apps::LaunchSource ShelfLaunchSourceToAppsLaunchSource( ash::ShelfLaunchSource source) { switch (source) { case ash::LAUNCH_FROM_UNKNOWN: - return apps::mojom::LaunchSource::kUnknown; + return apps::LaunchSource::kUnknown; case ash::LAUNCH_FROM_INTERNAL: - return apps::mojom::LaunchSource::kFromChromeInternal; + return apps::LaunchSource::kFromChromeInternal; case ash::LAUNCH_FROM_APP_LIST: - return apps::mojom::LaunchSource::kFromAppListGrid; + return apps::LaunchSource::kFromAppListGrid; case ash::LAUNCH_FROM_APP_LIST_SEARCH: - return apps::mojom::LaunchSource::kFromAppListQuery; + return apps::LaunchSource::kFromAppListQuery; case ash::LAUNCH_FROM_APP_LIST_RECOMMENDATION: - return apps::mojom::LaunchSource::kFromAppListRecommendation; + return apps::LaunchSource::kFromAppListRecommendation; case ash::LAUNCH_FROM_SHELF: - return apps::mojom::LaunchSource::kFromShelf; + return apps::LaunchSource::kFromShelf; } }
diff --git a/chrome/browser/ui/ash/shelf/chrome_shelf_controller_util.h b/chrome/browser/ui/ash/shelf/chrome_shelf_controller_util.h index 27176bf..55267e4a 100644 --- a/chrome/browser/ui/ash/shelf/chrome_shelf_controller_util.h +++ b/chrome/browser/ui/ash/shelf/chrome_shelf_controller_util.h
@@ -9,7 +9,7 @@ #include "ash/public/cpp/shelf_types.h" #include "chrome/browser/ui/app_list/app_list_controller_delegate.h" -#include "components/services/app_service/public/mojom/types.mojom.h" +#include "components/services/app_service/public/cpp/app_launch_util.h" class Browser; @@ -51,7 +51,7 @@ // Returns whether the app with `app_id` has been pinned to the shelf. bool IsAppWithIDPinnedToShelf(const std::string& app_id); -apps::mojom::LaunchSource ShelfLaunchSourceToAppsLaunchSource( +apps::LaunchSource ShelfLaunchSourceToAppsLaunchSource( ash::ShelfLaunchSource source); // Checks if |BrowserAppShelfController| and |BrowserAppShelfItemController| can
diff --git a/chrome/browser/ui/ash/shelf/shelf_controller_helper.cc b/chrome/browser/ui/ash/shelf/shelf_controller_helper.cc index 7774b11a..ad1bc8d 100644 --- a/chrome/browser/ui/ash/shelf/shelf_controller_helper.cc +++ b/chrome/browser/ui/ash/shelf/shelf_controller_helper.cc
@@ -35,6 +35,7 @@ #include "chrome/common/extensions/manifest_handlers/app_launch_info.h" #include "components/services/app_service/public/cpp/app_launch_util.h" #include "components/services/app_service/public/cpp/app_types.h" +#include "components/services/app_service/public/cpp/features.h" #include "components/services/app_service/public/cpp/types_util.h" #include "content/public/browser/navigation_entry.h" #include "net/base/url_util.h" @@ -164,9 +165,16 @@ // Launch apps with AppServiceProxy.Launch. if (proxy->AppRegistryCache().GetAppType(app_id) != apps::AppType::kUnknown) { - proxy->Launch(app_id, event_flags, - ShelfLaunchSourceToAppsLaunchSource(source), - apps::MakeWindowInfo(display_id)); + if (base::FeatureList::IsEnabled(apps::kAppServiceLaunchWithoutMojom)) { + proxy->Launch(app_id, event_flags, + ShelfLaunchSourceToAppsLaunchSource(source), + std::make_unique<apps::WindowInfo>(display_id)); + } else { + proxy->Launch(app_id, event_flags, + apps::ConvertLaunchSourceToMojomLaunchSource( + ShelfLaunchSourceToAppsLaunchSource(source)), + apps::MakeWindowInfo(display_id)); + } return; } @@ -192,9 +200,7 @@ apps::AppLaunchParams params = CreateAppLaunchParamsWithEventFlags( profile_, extension, event_flags, - apps::ConvertMojomLaunchSourceToLaunchSource( - ShelfLaunchSourceToAppsLaunchSource(source)), - display_id); + ShelfLaunchSourceToAppsLaunchSource(source), display_id); if ((source == ash::LAUNCH_FROM_APP_LIST || source == ash::LAUNCH_FROM_APP_LIST_SEARCH) && app_id == extensions::kWebStoreAppId) {
diff --git a/chrome/browser/ui/ash/shelf/standalone_browser_extension_app_shelf_item_controller.cc b/chrome/browser/ui/ash/shelf/standalone_browser_extension_app_shelf_item_controller.cc index e60daf8..ac08746 100644 --- a/chrome/browser/ui/ash/shelf/standalone_browser_extension_app_shelf_item_controller.cc +++ b/chrome/browser/ui/ash/shelf/standalone_browser_extension_app_shelf_item_controller.cc
@@ -24,6 +24,7 @@ #include "chrome/browser/ui/ash/shelf/chrome_shelf_controller_util.h" #include "chrome/browser/ui/ash/shelf/standalone_browser_extension_app_context_menu.h" #include "components/services/app_service/public/cpp/app_types.h" +#include "components/services/app_service/public/cpp/features.h" #include "components/services/app_service/public/cpp/instance_registry.h" #include "ui/base/models/simple_menu_model.h" #include "ui/views/widget/widget.h" @@ -103,9 +104,17 @@ if (filtered_windows.size() == 0) { apps::AppServiceProxy* proxy = apps::AppServiceProxyFactory::GetForProfile( ProfileManager::GetPrimaryUserProfile()); - proxy->Launch(app_id(), event->flags(), - ShelfLaunchSourceToAppsLaunchSource(source), - /*window_info=*/nullptr); + if (base::FeatureList::IsEnabled(apps::kAppServiceLaunchWithoutMojom)) { + proxy->Launch(app_id(), event->flags(), + ShelfLaunchSourceToAppsLaunchSource(source), + /*window_info=*/nullptr); + } else { + proxy->Launch(app_id(), event->flags(), + apps::ConvertLaunchSourceToMojomLaunchSource( + ShelfLaunchSourceToAppsLaunchSource(source)), + /*window_info=*/nullptr); + } + std::move(callback).Run(ash::SHELF_ACTION_NEW_WINDOW_CREATED, {}); return; }
diff --git a/chrome/browser/ui/ash/system_tray_client_impl.cc b/chrome/browser/ui/ash/system_tray_client_impl.cc index 834396b..e609b057d 100644 --- a/chrome/browser/ui/ash/system_tray_client_impl.cc +++ b/chrome/browser/ui/ash/system_tray_client_impl.cc
@@ -751,6 +751,15 @@ opened_pwa = true; } +void SystemTrayClientImpl::ShowChannelInfoAdditionalDetails() { + ShowSettingsSubPageForActiveUser( + std::string(chromeos::settings::mojom::kDetailedBuildInfoSubpagePath)); +} + +void SystemTrayClientImpl::ShowChannelInfoGiveFeedback() { + ash::NewWindowDelegate::GetInstance()->OpenFeedbackPage(); +} + SystemTrayClientImpl::SystemTrayClientImpl(SystemTrayClientImpl* mock_instance) : system_tray_(nullptr) { DCHECK(!g_system_tray_client_instance);
diff --git a/chrome/browser/ui/ash/system_tray_client_impl.h b/chrome/browser/ui/ash/system_tray_client_impl.h index fedf44e9..a54724e 100644 --- a/chrome/browser/ui/ash/system_tray_client_impl.h +++ b/chrome/browser/ui/ash/system_tray_client_impl.h
@@ -104,6 +104,8 @@ const base::Time& date, bool& opened_pwa, GURL& finalized_event_url) override; + void ShowChannelInfoAdditionalDetails() override; + void ShowChannelInfoGiveFeedback() override; protected: // Used by mocks in tests.
diff --git a/chrome/browser/ui/views/download/bubble/download_bubble_row_view.cc b/chrome/browser/ui/views/download/bubble/download_bubble_row_view.cc index 0f970f8..d78854fe 100644 --- a/chrome/browser/ui/views/download/bubble/download_bubble_row_view.cc +++ b/chrome/browser/ui/views/download/bubble/download_bubble_row_view.cc
@@ -136,6 +136,7 @@ LoadIcon(); UpdateButtons(); } + RecordDownloadDisplayed(); UpdateLabels(); UpdateProgressBar(); } @@ -576,6 +577,15 @@ } } +void DownloadBubbleRowView::RecordDownloadDisplayed() { + if (!model_->GetEphemeralWarningUiShownTime().has_value() && + model_->IsEphemeralWarning()) { + model_->SetEphemeralWarningUiShownTime(base::Time::Now()); + bubble_controller_->ScheduleCancelForEphemeralWarning( + model_->GetDownloadItem()->GetGuid()); + } +} + void DownloadBubbleRowView::OnDownloadUpdated() { UpdateRow(/*initial_setup=*/false); }
diff --git a/chrome/browser/ui/views/download/bubble/download_bubble_row_view.h b/chrome/browser/ui/views/download/bubble/download_bubble_row_view.h index dfeb79f..6b34b6d 100644 --- a/chrome/browser/ui/views/download/bubble/download_bubble_row_view.h +++ b/chrome/browser/ui/views/download/bubble/download_bubble_row_view.h
@@ -100,6 +100,7 @@ void UpdateProgressBar(); void UpdateLabels(); void RecordMetricsOnUpdate(); + void RecordDownloadDisplayed(); // Load the icon, from the cache or from IconManager::LoadIcon. void LoadIcon();
diff --git a/chrome/browser/ui/web_applications/test/web_app_browsertest_util.h b/chrome/browser/ui/web_applications/test/web_app_browsertest_util.h index 7efe369..4068aef 100644 --- a/chrome/browser/ui/web_applications/test/web_app_browsertest_util.h +++ b/chrome/browser/ui/web_applications/test/web_app_browsertest_util.h
@@ -135,7 +135,9 @@ raw_ptr<Browser> added_browser_ = nullptr; base::RunLoop removed_run_loop_; - raw_ptr<Browser> removed_browser_ = nullptr; + // TODO(crbug.com/1298696): browser_tests breaks with MTECheckedPtr + // enabled. Triage. + raw_ptr<Browser, DegradeToNoOpWhenMTE> removed_browser_ = nullptr; }; class UpdateAwaiter : public WebAppInstallManagerObserver {
diff --git a/chrome/browser/ui/webui/chromeos/notification_tester/notification_tester_handler.cc b/chrome/browser/ui/webui/chromeos/notification_tester/notification_tester_handler.cc index 9ae1c8d..80c8090 100644 --- a/chrome/browser/ui/webui/chromeos/notification_tester/notification_tester_handler.cc +++ b/chrome/browser/ui/webui/chromeos/notification_tester/notification_tester_handler.cc
@@ -72,6 +72,12 @@ DCHECK(origin_url_str); GURL origin_url(*origin_url_str); + absl::optional<int> warning_level_int = notifObj->FindInt("warningLevel"); + DCHECK(warning_level_int); + auto warning_level = + static_cast<message_center::SystemNotificationWarningLevel>( + warning_level_int.value()); + absl::optional<int> notification_type_int = notifObj->FindInt("notificationType"); DCHECK(notification_type_int); @@ -109,6 +115,8 @@ base::UTF8ToUTF16(*display_source), origin_url, notifier_id, optional_fields, delegate); + notification->set_system_notification_warning_level(warning_level); + message_center::MessageCenter::Get()->AddNotification( std::move(notification)); }
diff --git a/chrome/browser/ui/webui/settings/chromeos/os_settings_ui.cc b/chrome/browser/ui/webui/settings/chromeos/os_settings_ui.cc index c037fc6a..6314a8b 100644 --- a/chrome/browser/ui/webui/settings/chromeos/os_settings_ui.cc +++ b/chrome/browser/ui/webui/settings/chromeos/os_settings_ui.cc
@@ -34,6 +34,7 @@ #include "chrome/common/webui_url_constants.h" #include "chrome/grit/os_settings_resources.h" #include "chrome/grit/os_settings_resources_map.h" +#include "chromeos/ash/services/auth_factor_config/in_process_instances.h" #include "components/pref_registry/pref_registry_syncable.h" #include "components/prefs/pref_service.h" #include "content/public/browser/web_contents.h" @@ -221,6 +222,16 @@ ash::GetBluetoothConfigService(std::move(receiver)); } +void OSSettingsUI::BindInterface( + mojo::PendingReceiver<ash::auth::mojom::AuthFactorConfig> receiver) { + ash::auth::BindToAuthFactorConfig(std::move(receiver)); +} + +void OSSettingsUI::BindInterface( + mojo::PendingReceiver<ash::auth::mojom::RecoveryFactorEditor> receiver) { + ash::auth::BindToRecoveryFactorEditor(std::move(receiver)); +} + WEB_UI_CONTROLLER_TYPE_IMPL(OSSettingsUI) } // namespace settings
diff --git a/chrome/browser/ui/webui/settings/chromeos/os_settings_ui.h b/chrome/browser/ui/webui/settings/chromeos/os_settings_ui.h index 63ef73e..41a569c 100644 --- a/chrome/browser/ui/webui/settings/chromeos/os_settings_ui.h +++ b/chrome/browser/ui/webui/settings/chromeos/os_settings_ui.h
@@ -18,6 +18,7 @@ #include "chrome/browser/ui/webui/settings/ash/os_apps_page/mojom/app_notification_handler.mojom-forward.h" #include "chrome/browser/ui/webui/settings/ash/search/user_action_recorder.mojom-forward.h" #include "chrome/browser/ui/webui/webui_load_timer.h" +#include "chromeos/ash/services/auth_factor_config/public/mojom/auth_factor_config.mojom-forward.h" #include "chromeos/services/bluetooth_config/public/mojom/cros_bluetooth_config.mojom-forward.h" #include "chromeos/services/network_config/public/mojom/cros_network_config.mojom-forward.h" #include "mojo/public/cpp/bindings/pending_receiver.h" @@ -110,6 +111,12 @@ mojo::PendingReceiver<bluetooth_config::mojom::CrosBluetoothConfig> receiver); + // Binds to the cros authentication factor editing services. + void BindInterface( + mojo::PendingReceiver<ash::auth::mojom::AuthFactorConfig> receiver); + void BindInterface( + mojo::PendingReceiver<ash::auth::mojom::RecoveryFactorEditor> receiver); + private: base::TimeTicks time_when_opened_;
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 bcb4ee4..94cdaf0 100644 --- a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc +++ b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
@@ -84,6 +84,7 @@ #include "device/fido/features.h" #include "media/base/media_switches.h" #include "net/base/url_util.h" +#include "net/net_buildflags.h" #include "services/device/public/cpp/device_features.h" #include "ui/accessibility/accessibility_switches.h" #include "ui/base/accelerators/accelerator.h" @@ -141,6 +142,10 @@ #include "ui/ozone/public/ozone_platform.h" #endif +#if BUILDFLAG(CHROME_ROOT_STORE_SUPPORTED) +#include "net/base/features.h" +#endif + namespace settings { namespace { @@ -741,9 +746,10 @@ void AddLanguagesStrings(content::WebUIDataSource* html_source, Profile* profile) { -#if !BUILDFLAG(IS_CHROMEOS_ASH) static constexpr webui::LocalizedString kLocalizedStrings[] = { {"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}, @@ -802,15 +808,14 @@ {"languagesDictionaryDownloadErrorHelp", IDS_SETTINGS_LANGUAGES_DICTIONARY_DOWNLOAD_FAILED_HELP}, #endif - }; - html_source->AddLocalizedStrings(kLocalizedStrings); #endif // !BUILDFLAG(IS_CHROMEOS_ASH) #if BUILDFLAG(IS_CHROMEOS_ASH) - html_source->AddLocalizedString("languagesPageTitle", - IDS_SETTINGS_LANGUAGES_PAGE_TITLE); - html_source->AddLocalizedString( - "openChromeOSLanguagesSettingsLabel", - IDS_SETTINGS_LANGUAGES_OPEN_CHROME_OS_SETTINGS_LABEL); + {"openChromeOSLanguagesSettingsLabel", + IDS_SETTINGS_LANGUAGES_OPEN_CHROME_OS_SETTINGS_LABEL}, +#endif + }; + html_source->AddLocalizedStrings(kLocalizedStrings); +#if BUILDFLAG(IS_CHROMEOS_ASH) html_source->AddString( "chromeOSLanguagesSettingsPath", chromeos::settings::mojom::kLanguagesAndInputSectionPath); @@ -1534,6 +1539,14 @@ {"openChromeOSSecureDnsSettingsLabel", IDS_SETTINGS_SECURE_DNS_OPEN_CHROME_OS_SETTINGS_LABEL}, #endif +#if BUILDFLAG(CHROME_ROOT_STORE_SUPPORTED) + {"manageDeviceCertificates", IDS_SETTINGS_MANAGE_DEVICE_CERTIFICATES}, + {"manageDeviceCertificatesDescription", + IDS_SETTINGS_MANAGE_DEVICE_CERTIFICATES_DESCRIPTION}, + {"chromeCertificates", IDS_SETTINGS_CHROME_CERTIFICATES}, + {"chromeCertificatesDescription", + IDS_SETTINGS_CHROME_CERTIFICATES_DESCRIPTION}, +#endif }; html_source->AddLocalizedStrings(kLocalizedStrings); @@ -1587,6 +1600,26 @@ "showHttpsOnlyModeSetting", base::FeatureList::IsEnabled(features::kHttpsOnlyMode)); +#if BUILDFLAG(CHROME_ROOT_STORE_SUPPORTED) + bool chrome_root_store_used = + base::FeatureList::IsEnabled(net::features::kChromeRootStoreUsed); +#if BUILDFLAG(CHROME_ROOT_STORE_POLICY_SUPPORTED) + const PrefService::Preference* chrome_root_store_enabled_pref = + g_browser_process->local_state()->FindPreference( + prefs::kChromeRootStoreEnabled); + if (chrome_root_store_enabled_pref && + chrome_root_store_enabled_pref->IsManaged()) + chrome_root_store_used &= + chrome_root_store_enabled_pref->GetValue()->GetBool(); +#endif // BUILDFLAG(CHROME_ROOT_STORE_POLICY_SUPPORTED) + + html_source->AddBoolean("showChromeRootStoreCertificates", + chrome_root_store_used); + + html_source->AddString("chromeRootStoreHelpCenterURL", + chrome::kChromeRootStoreSettingsHelpCenterURL); +#endif // BUILDFLAG(CHROME_ROOT_STORE_SUPPORTED) + // The link to the Advanced Protection Program landing page, with a referrer // from Chrome settings. GURL advanced_protection_url(
diff --git a/chrome/browser/web_applications/test/test_web_app_url_loader.h b/chrome/browser/web_applications/test/test_web_app_url_loader.h index f68e0ab..7a0cdcd6 100644 --- a/chrome/browser/web_applications/test/test_web_app_url_loader.h +++ b/chrome/browser/web_applications/test/test_web_app_url_loader.h
@@ -9,6 +9,7 @@ #include <queue> #include <vector> +#include "base/callback.h" #include "base/containers/queue.h" #include "base/memory/raw_ptr.h" #include "chrome/browser/web_applications/web_app_url_loader.h"
diff --git a/chrome/browser/web_applications/web_app_url_loader.cc b/chrome/browser/web_applications/web_app_url_loader.cc index 8a7825b..2d49d28 100644 --- a/chrome/browser/web_applications/web_app_url_loader.cc +++ b/chrome/browser/web_applications/web_app_url_loader.cc
@@ -7,19 +7,23 @@ #include <memory> #include <utility> +#include "base/bind.h" +#include "base/callback.h" +#include "base/check.h" +#include "base/logging.h" #include "base/memory/weak_ptr.h" #include "base/metrics/histogram_functions.h" #include "base/threading/thread_task_runner_handle.h" #include "base/timer/timer.h" #include "content/public/browser/navigation_controller.h" +#include "content/public/browser/render_frame_host.h" #include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents_observer.h" #include "content/public/common/url_constants.h" +#include "ui/base/page_transition_types.h" +#include "url/gurl.h" namespace web_app { - -constexpr base::TimeDelta WebAppUrlLoader::kSecondsToWaitForWebContentsLoad; - namespace { using UrlComparison = WebAppUrlLoader::UrlComparison; @@ -50,6 +54,8 @@ LoaderTask() = default; LoaderTask(const LoaderTask&) = delete; LoaderTask& operator=(const LoaderTask&) = delete; + LoaderTask(LoaderTask&&) = delete; + LoaderTask& operator=(LoaderTask&&) = delete; ~LoaderTask() override = default; void LoadUrl(const GURL& url, @@ -79,8 +85,7 @@ // TODO(ortuno): Use DidStopLoading instead. void DidFinishLoad(content::RenderFrameHost* render_frame_host, const GURL& validated_url) override { - // Ignore subframe loads. - if (web_contents()->GetPrimaryMainFrame() != render_frame_host) { + if (IsSubframeLoad(render_frame_host)) { return; } @@ -104,16 +109,19 @@ PostResultTask(WebAppUrlLoader::Result::kUrlLoaded); return; } - LOG(ERROR) << "Error loading " << url_; - LOG(ERROR) << " page redirected to " << validated_url; + LOG(ERROR) << "Error loading " << url_ << " page redirected to " + << validated_url; PostResultTask(WebAppUrlLoader::Result::kRedirectedUrlLoaded); } + bool IsSubframeLoad(content::RenderFrameHost* render_frame_host) const { + return web_contents()->GetPrimaryMainFrame() != render_frame_host; + } + void DidFailLoad(content::RenderFrameHost* render_frame_host, const GURL& validated_url, int error_code) override { - // Ignore subframe loads. - if (web_contents()->GetPrimaryMainFrame() != render_frame_host) { + if (IsSubframeLoad(render_frame_host)) { return; } @@ -192,18 +200,19 @@ } const char* ConvertUrlLoaderResultToString(WebAppUrlLoader::Result result) { + using Result = WebAppUrlLoader::Result; switch (result) { - case WebAppUrlLoader::Result::kUrlLoaded: + case Result::kUrlLoaded: return "UrlLoaded"; - case WebAppUrlLoader::Result::kRedirectedUrlLoaded: + case Result::kRedirectedUrlLoaded: return "RedirectedUrlLoaded"; - case WebAppUrlLoader::Result::kFailedUnknownReason: + case Result::kFailedUnknownReason: return "FailedUnknownReason"; - case WebAppUrlLoader::Result::kFailedPageTookTooLong: + case Result::kFailedPageTookTooLong: return "FailedPageTookTooLong"; - case WebAppUrlLoader::Result::kFailedWebContentsDestroyed: + case Result::kFailedWebContentsDestroyed: return "FailedWebContentsDestroyed"; - case WebAppUrlLoader::Result::kFailedErrorPageLoaded: + case Result::kFailedErrorPageLoaded: return "FailedErrorPageLoaded"; } }
diff --git a/chrome/browser/web_applications/web_app_url_loader.h b/chrome/browser/web_applications/web_app_url_loader.h index 588dcad..2360b44 100644 --- a/chrome/browser/web_applications/web_app_url_loader.h +++ b/chrome/browser/web_applications/web_app_url_loader.h
@@ -5,7 +5,7 @@ #ifndef CHROME_BROWSER_WEB_APPLICATIONS_WEB_APP_URL_LOADER_H_ #define CHROME_BROWSER_WEB_APPLICATIONS_WEB_APP_URL_LOADER_H_ -#include "base/callback.h" +#include "base/callback_forward.h" #include "base/time/time.h" class GURL;
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt index 0c59dfc1..1f9590f9 100644 --- a/chrome/build/mac.pgo.txt +++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@ -chrome-mac-main-1658231914-464345953cd8932bd04d164edebb7741fc2497e0.profdata +chrome-mac-main-1658253580-0cfbc9da92202afad2ce2255c11cccf318842bba.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt index 5dc4c90..a168756 100644 --- a/chrome/build/win32.pgo.txt +++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@ -chrome-win32-main-1658242050-75ad9a7af7fb23f6cad89c99f181bac6f662d8fe.profdata +chrome-win32-main-1658253580-83a90686a348174944d53c05dfddc7bec4465d2f.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt index 8c0c674..940ee16 100644 --- a/chrome/build/win64.pgo.txt +++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@ -chrome-win64-main-1658242050-a72bae39e2079165c2922fe76f5dae7067297f8e.profdata +chrome-win64-main-1658264363-f911d35b4c407ea497ee31466d63db4d0706fd22.profdata
diff --git a/chrome/common/features.gni b/chrome/common/features.gni index 07378bea..5b7eaf6a 100644 --- a/chrome/common/features.gni +++ b/chrome/common/features.gni
@@ -89,6 +89,7 @@ # Every grit target in //chrome should apply these defines so that the # proper build flags can be set. chrome_grit_defines = [ + "chrome_root_store_supported=$chrome_root_store_supported", "enable_arcore=$enable_arcore", "enable_background_mode=$enable_background_mode", "enable_background_contents=$enable_background_contents",
diff --git a/chrome/common/url_constants.cc b/chrome/common/url_constants.cc index 94f969f5..70720bb 100644 --- a/chrome/common/url_constants.cc +++ b/chrome/common/url_constants.cc
@@ -485,4 +485,11 @@ "https://support.google.com/chrome/?p=chrome_app_deprecation"; #endif +#if BUILDFLAG(CHROME_ROOT_STORE_SUPPORTED) +// TODO(b/1339340): add help center link when help center link is created. +const char kChromeRootStoreSettingsHelpCenterURL[] = + "https://chromium.googlesource.com/chromium/src/+/main/net/data/ssl/" + "chrome_root_store/root_store.md"; +#endif + } // namespace chrome
diff --git a/chrome/common/url_constants.h b/chrome/common/url_constants.h index 0a85da2..f951ffc2 100644 --- a/chrome/common/url_constants.h +++ b/chrome/common/url_constants.h
@@ -23,6 +23,7 @@ #include "chrome/common/buildflags.h" #include "chrome/common/webui_url_constants.h" #include "content/public/common/url_constants.h" +#include "net/net_buildflags.h" #include "ppapi/buildflags/buildflags.h" namespace chrome { @@ -457,6 +458,10 @@ extern const char kChromeAppsDeprecationLearnMoreURL[]; #endif +#if BUILDFLAG(CHROME_ROOT_STORE_SUPPORTED) +extern const char kChromeRootStoreSettingsHelpCenterURL[]; +#endif + // Please do not append entries here. See the comments at the top of the file. } // namespace chrome
diff --git a/chrome/services/file_util/public/cpp/sandboxed_rar_analyzer_unittest.cc b/chrome/services/file_util/public/cpp/sandboxed_rar_analyzer_unittest.cc index 1969cee..61d730bd 100644 --- a/chrome/services/file_util/public/cpp/sandboxed_rar_analyzer_unittest.cc +++ b/chrome/services/file_util/public/cpp/sandboxed_rar_analyzer_unittest.cc
@@ -197,13 +197,34 @@ ASSERT_TRUE(results.success); EXPECT_FALSE(results.has_executable); - EXPECT_EQ(results.archived_binary.size(), 1); + ASSERT_EQ(results.archived_binary.size(), 1); EXPECT_EQ(results.archived_binary[0].file_basename(), "file1.txt"); EXPECT_FALSE(results.archived_binary[0].is_executable()); EXPECT_FALSE(results.archived_binary[0].is_archive()); EXPECT_TRUE(results.archived_archive_filenames.empty()); } +TEST_F(SandboxedRarAnalyzerTest, AnalyzeRarWithPasswordMultipleFiles) { + // Can list files inside an archive that has password protected data. + // passwd_two_fiels.rar contains 2 files: file1.txt and file2.txt + base::FilePath path; + ASSERT_NO_FATAL_FAILURE(path = GetFilePath("passwd_two_files.rar")); + + safe_browsing::ArchiveAnalyzerResults results; + AnalyzeFile(path, &results); + + ASSERT_TRUE(results.success); + EXPECT_FALSE(results.has_executable); + ASSERT_EQ(results.archived_binary.size(), 2); + EXPECT_EQ(results.archived_binary[0].file_basename(), "file1.txt"); + EXPECT_FALSE(results.archived_binary[0].is_executable()); + EXPECT_FALSE(results.archived_binary[0].is_archive()); + EXPECT_EQ(results.archived_binary[1].file_basename(), "file2.txt"); + EXPECT_FALSE(results.archived_binary[1].is_executable()); + EXPECT_FALSE(results.archived_binary[1].is_archive()); + EXPECT_TRUE(results.archived_archive_filenames.empty()); +} + TEST_F(SandboxedRarAnalyzerTest, AnalyzeRarContainingExecutable) { // Can detect when .rar contains executable files. // has_exe.rar contains 1 file: signed.exe @@ -327,5 +348,21 @@ EXPECT_TRUE(results.archived_archive_filenames.empty()); } +TEST_F(SandboxedRarAnalyzerTest, + AnalyzeMultipartRarContainingMultipleExecutables) { + base::FilePath path; + // Contains one part of two different exe files. + ASSERT_NO_FATAL_FAILURE( + path = GetFilePath("multipart_multiple_file.part0002.rar")); + + safe_browsing::ArchiveAnalyzerResults results; + AnalyzeFile(path, &results); + + ASSERT_TRUE(results.success); + ASSERT_TRUE(results.has_executable); + EXPECT_EQ(2, results.archived_binary.size()); + EXPECT_TRUE(results.archived_archive_filenames.empty()); +} + } // namespace } // namespace safe_browsing
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 9f12989..74c81a5 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -7167,7 +7167,7 @@ "../browser/ui/ash/accessibility/accessibility_controller_client_unittest.cc", "../browser/ui/ash/accessibility/ax_tree_source_aura_unittest.cc", "../browser/ui/ash/ambient/ambient_client_impl_unittest.cc", - "../browser/ui/ash/app_access_notifier.cc", + "../browser/ui/ash/app_access_notifier_unittest.cc", "../browser/ui/ash/app_icon_color_cache_unittest.cc", "../browser/ui/ash/assistant/assistant_state_client_unittest.cc", "../browser/ui/ash/assistant/device_actions_unittest.cc",
diff --git a/chrome/test/data/safe_browsing/rar/multipart_multiple_file.part0001.rar b/chrome/test/data/safe_browsing/rar/multipart_multiple_file.part0001.rar new file mode 100644 index 0000000..6e94cc8 --- /dev/null +++ b/chrome/test/data/safe_browsing/rar/multipart_multiple_file.part0001.rar Binary files differ
diff --git a/chrome/test/data/safe_browsing/rar/multipart_multiple_file.part0002.rar b/chrome/test/data/safe_browsing/rar/multipart_multiple_file.part0002.rar new file mode 100644 index 0000000..21151da4 --- /dev/null +++ b/chrome/test/data/safe_browsing/rar/multipart_multiple_file.part0002.rar Binary files differ
diff --git a/chrome/test/data/safe_browsing/rar/multipart_multiple_file.part0003.rar b/chrome/test/data/safe_browsing/rar/multipart_multiple_file.part0003.rar new file mode 100644 index 0000000..1ad685b --- /dev/null +++ b/chrome/test/data/safe_browsing/rar/multipart_multiple_file.part0003.rar Binary files differ
diff --git a/chrome/test/data/safe_browsing/rar/passwd_two_files.rar b/chrome/test/data/safe_browsing/rar/passwd_two_files.rar new file mode 100644 index 0000000..8dc2261 --- /dev/null +++ b/chrome/test/data/safe_browsing/rar/passwd_two_files.rar Binary files differ
diff --git a/chrome/test/data/webrtc/region_capture_helpers.js b/chrome/test/data/webrtc/region_capture_helpers.js index 2ccdcd1..3335b3e2 100644 --- a/chrome/test/data/webrtc/region_capture_helpers.js +++ b/chrome/test/data/webrtc/region_capture_helpers.js
@@ -33,34 +33,37 @@ } else if (type == "crop-to") { cropTo(event.data.cropTarget, event.data.targetFrame, event.data.targetTrackStr); - } else if (type == "create-new-div-element") { - createNewDivElement(event.data.targetFrame, event.data.divId); - } else if (type == "start-second-capture") { + } else if (type == 'create-new-element') { + createNewElement(event.data.targetFrame, event.data.tag, event.data.id); + } else if (type == 'start-second-capture') { startSecondCapture(event.data.targetFrame); - } else if (type == "stop-capture") { + } else if (type == 'stop-capture') { stopCapture(event.data.targetFrame, event.data.targetTrack); } }); } -// Allows creating new div-elements for which new crop-targets may be created. -async function createNewDivElement(targetFrame, divId) { +// Allows creating new elements for which new crop-targets may be created. +function createNewElement(targetFrame, tag, id) { if (role == targetFrame) { - const newDiv = document.createElement("div"); - newDiv.id = divId; - document.body.appendChild(newDiv); - window.domAutomationController.send(`${role}-new-div-success`); + const newElement = document.createElement(tag); + newElement.id = id; + document.body.appendChild(newElement); + window.domAutomationController.send(`${role}-new-element-success`); } else { if (role != "top-level") { - window.domAutomationController.send(`${role}-new-div-error`) + window.domAutomationController.send(`${role}-new-element-error`) return; } const embedded_frame = document.getElementById("embedded_frame"); - embedded_frame.contentWindow.postMessage({ - messageType: "create-new-div-element", + embedded_frame.contentWindow.postMessage( + { + messageType: 'create-new-element', targetFrame: targetFrame, - divId: divId - }, "*"); + tag: tag, + id: id + }, + '*'); // window.domAutomationController.send() called by embedded page. } } @@ -178,12 +181,14 @@ } const embedded_frame = document.getElementById("embedded_frame"); - embedded_frame.contentWindow.postMessage({ - messageType: "crop-to", + embedded_frame.contentWindow.postMessage( + { + messageType: 'crop-to', cropTarget: cropTarget, targetFrame: targetFrame, targetTrackStr: targetTrackStr - }, "*"); + }, + '*'); // window.domAutomationController.send() called by embedded page. return; }
diff --git a/chrome/test/data/webui/new_tab_page/modules/cart/module_test.ts b/chrome/test/data/webui/new_tab_page/modules/cart/module_test.ts index 3663990..8ef04ba 100644 --- a/chrome/test/data/webui/new_tab_page/modules/cart/module_test.ts +++ b/chrome/test/data/webui/new_tab_page/modules/cart/module_test.ts
@@ -103,6 +103,10 @@ assertEquals(4, cartItems.length); assertEquals(220, moduleElement.offsetHeight); assertEquals(1, metrics.count('NewTabPage.Carts.CartCount', 4)); + assertEquals(1, metrics.count('NewTabPage.Carts.CartImageCount', 3)); + assertEquals(1, metrics.count('NewTabPage.Carts.CartImageCount', 2)); + assertEquals(1, metrics.count('NewTabPage.Carts.CartImageCount', 0)); + assertEquals(1, metrics.count('NewTabPage.Carts.CartImageCount', 4)); assertEquals('https://amazon.com/', cartItems[0]!.href); assertEquals( @@ -193,6 +197,7 @@ loadTimeData.getString('modulesCartWarmWelcome'), headerDescription!.innerText); assertEquals(227, moduleElement.offsetHeight); + assertEquals(0, metrics.count('NewTabPage.Carts.CartImageCount', 0)); }); test(
diff --git a/chrome/test/data/webui/settings/BUILD.gn b/chrome/test/data/webui/settings/BUILD.gn index 35a52db..3a0fb47 100644 --- a/chrome/test/data/webui/settings/BUILD.gn +++ b/chrome/test/data/webui/settings/BUILD.gn
@@ -2,6 +2,7 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("//chrome/common/features.gni") import("//tools/grit/preprocess_if_expr.gni") import("//tools/typescript/ts_library.gni") import("//ui/webui/resources/tools/generate_grd.gni") @@ -176,6 +177,7 @@ preprocessed_folder = "$target_gen_dir/preprocessed" preprocess_if_expr("preprocess") { + defines = chrome_grit_defines in_folder = "./" out_folder = preprocessed_folder in_files = preprocessed_files
diff --git a/chrome/test/data/webui/settings/security_page_test.ts b/chrome/test/data/webui/settings/security_page_test.ts index a4b2189..3201daec 100644 --- a/chrome/test/data/webui/settings/security_page_test.ts +++ b/chrome/test/data/webui/settings/security_page_test.ts
@@ -7,10 +7,16 @@ import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {SafeBrowsingSetting, SettingsSecurityPageElement} from 'chrome://settings/lazy_load.js'; import {MetricsBrowserProxyImpl, PrivacyElementInteractions, PrivacyPageBrowserProxyImpl, Router, routes, SafeBrowsingInteractions, SecureDnsMode} from 'chrome://settings/settings.js'; +// <if expr="chrome_root_store_supported"> +import {OpenWindowProxyImpl} from 'chrome://settings/settings.js'; +// </if> import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js'; import {flushTasks, isChildVisible} from 'chrome://webui-test/test_util.js'; import {TestMetricsBrowserProxy} from './test_metrics_browser_proxy.js'; +// <if expr="chrome_root_store_supported"> +import {TestOpenWindowProxy} from './test_open_window_proxy.js'; +// </if> import {TestPrivacyPageBrowserProxy} from './test_privacy_page_browser_proxy.js'; // clang-format on @@ -38,11 +44,15 @@ let testMetricsBrowserProxy: TestMetricsBrowserProxy; let testPrivacyBrowserProxy: TestPrivacyPageBrowserProxy; let page: SettingsSecurityPageElement; + // <if expr="chrome_root_store_supported"> + let openWindowProxy: TestOpenWindowProxy; + // </if> suiteSetup(function() { loadTimeData.overrideValues({ enableSecurityKeysSubpage: true, showHttpsOnlyModeSetting: true, + showChromeRootStoreCertificates: true, }); }); @@ -51,6 +61,10 @@ MetricsBrowserProxyImpl.setInstance(testMetricsBrowserProxy); testPrivacyBrowserProxy = new TestPrivacyPageBrowserProxy(); PrivacyPageBrowserProxyImpl.setInstance(testPrivacyBrowserProxy); + // <if expr="chrome_root_store_supported"> + openWindowProxy = new TestOpenWindowProxy(); + OpenWindowProxyImpl.setInstance(openWindowProxy); + // </if> document.body.innerHTML = ''; page = document.createElement('settings-security-page'); page.prefs = pagePrefs(); @@ -72,6 +86,17 @@ }); // </if> + // <if expr="chrome_root_store_supported"> + test('ChromeRootStorePage', async function() { + const row = + page.shadowRoot!.querySelector<HTMLElement>('#chromeCertificates'); + assertTrue(!!row); + row.click(); + const url = await openWindowProxy.whenCalled('openURL'); + assertEquals(url, loadTimeData.getString('chromeRootStoreHelpCenterURL')); + }); + // </if> + // Initially specified pref option should be expanded test('SafeBrowsingRadio_InitialPrefOptionIsExpanded', function() { assertFalse(page.$.safeBrowsingEnhanced.expanded);
diff --git a/chromecast/app/cast_main_delegate.cc b/chromecast/app/cast_main_delegate.cc index 92e88ea3f..de40c3e 100644 --- a/chromecast/app/cast_main_delegate.cc +++ b/chromecast/app/cast_main_delegate.cc
@@ -72,7 +72,7 @@ CastMainDelegate::~CastMainDelegate() {} -bool CastMainDelegate::BasicStartupComplete(int* exit_code) { +absl::optional<int> CastMainDelegate::BasicStartupComplete() { RegisterPathProvider(); logging::LoggingSettings settings; @@ -160,7 +160,7 @@ if (settings.logging_dest & logging::LOG_TO_FILE) { LOG(INFO) << "Logging to file: " << settings.log_file_path; } - return false; + return absl::nullopt; } void CastMainDelegate::PreSandboxStartup() { @@ -237,10 +237,11 @@ return absl::holds_alternative<InvokedInChildProcess>(invoked_in); } -void CastMainDelegate::PostEarlyInitialization(InvokedIn invoked_in) { +absl::optional<int> CastMainDelegate::PostEarlyInitialization( + InvokedIn invoked_in) { if (ShouldCreateFeatureList(invoked_in)) { // content is handling the feature list. - return; + return absl::nullopt; } DCHECK(cast_feature_list_creator_); @@ -282,6 +283,8 @@ ProcessType process_type = use_browser_config ? ProcessType::kCastBrowser : ProcessType::kCastService; cast_feature_list_creator_->CreatePrefServiceAndFeatureList(process_type); + + return absl::nullopt; } void CastMainDelegate::InitializeResourceBundle() {
diff --git a/chromecast/app/cast_main_delegate.h b/chromecast/app/cast_main_delegate.h index 14411db..3f6bc47 100644 --- a/chromecast/app/cast_main_delegate.h +++ b/chromecast/app/cast_main_delegate.h
@@ -10,6 +10,7 @@ #include "build/build_config.h" #include "chromecast/common/cast_content_client.h" #include "content/public/app/content_main_delegate.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace content { class BrowserMainRunner; @@ -37,7 +38,7 @@ ~CastMainDelegate() override; // content::ContentMainDelegate implementation: - bool BasicStartupComplete(int* exit_code) override; + absl::optional<int> BasicStartupComplete() override; void PreSandboxStartup() override; absl::variant<int, content::MainFunctionParams> RunProcess( const std::string& process_type, @@ -46,7 +47,7 @@ void ZygoteForked() override; #endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) bool ShouldCreateFeatureList(InvokedIn invoked_in) override; - void PostEarlyInitialization(InvokedIn invoked_in) override; + absl::optional<int> PostEarlyInitialization(InvokedIn invoked_in) override; content::ContentClient* CreateContentClient() override; content::ContentBrowserClient* CreateContentBrowserClient() override; content::ContentGpuClient* CreateContentGpuClient() override;
diff --git a/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWebContentsScopes.java b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWebContentsScopes.java index 9365af0..9f316919 100644 --- a/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWebContentsScopes.java +++ b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWebContentsScopes.java
@@ -51,7 +51,7 @@ layout.setBackgroundColor(backgroundColor); return onLayoutInternal(context, layout, () -> new WindowAndroid(context) { @Override - protected IBinder getWindowToken() { + public IBinder getWindowToken() { return windowTokenProvider.provideWindowToken(); } }, backgroundColor);
diff --git a/chromecast/renderer/media/key_systems_cast.cc b/chromecast/renderer/media/key_systems_cast.cc index 1d160d3..0cd8120 100644 --- a/chromecast/renderer/media/key_systems_cast.cc +++ b/chromecast/renderer/media/key_systems_cast.cc
@@ -16,6 +16,7 @@ #include "media/base/eme_constants.h" #include "media/base/key_system_properties.h" #include "media/media_buildflags.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/widevine/cdm/buildflags.h" #if BUILDFLAG(ENABLE_WIDEVINE) @@ -24,6 +25,7 @@ using ::media::CdmSessionType; using ::media::EmeConfigRule; +using ::media::EmeConfigRuleState; using ::media::EmeFeatureSupport; using ::media::EmeInitDataType; using ::media::EmeMediaType; @@ -65,7 +67,7 @@ } #endif // BUILDFLAG(IS_ANDROID) - EmeConfigRule GetRobustnessConfigRule( + absl::optional<EmeConfigRule> GetRobustnessConfigRule( const std::string& key_system, EmeMediaType media_type, const std::string& requested_robustness, @@ -77,20 +79,24 @@ // in KeySystemConfigSelector: crbug.com/1204284 if (requested_robustness.empty()) { #if BUILDFLAG(IS_ANDROID) - return EmeConfigRule::HW_SECURE_CODECS_REQUIRED; + return EmeConfigRule{.hw_secure_codecs = EmeConfigRuleState::kRequired}; #else - return EmeConfigRule::SUPPORTED; + return EmeConfigRule(); #endif // BUILDFLAG(IS_ANDROID) } // Cast-specific PlayReady implementation does not currently recognize or // support non-empty robustness strings. - return EmeConfigRule::NOT_SUPPORTED; + return absl::nullopt; } - EmeConfigRule GetPersistentLicenseSessionSupport() const override { - return persistent_license_support_ ? EmeConfigRule::SUPPORTED - : EmeConfigRule::NOT_SUPPORTED; + absl::optional<EmeConfigRule> GetPersistentLicenseSessionSupport() + const override { + if (persistent_license_support_) { + return EmeConfigRule(); + } else { + return absl::nullopt; + } } EmeFeatureSupport GetPersistentStateSupport() const override { @@ -100,11 +106,13 @@ return EmeFeatureSupport::ALWAYS_ENABLED; } - EmeConfigRule GetEncryptionSchemeConfigRule( + absl::optional<EmeConfigRule> GetEncryptionSchemeConfigRule( EncryptionScheme encryption_scheme) const override { - if (encryption_scheme == EncryptionScheme::kCenc) - return EmeConfigRule::SUPPORTED; - return EmeConfigRule::NOT_SUPPORTED; + if (encryption_scheme == EncryptionScheme::kCenc) { + return EmeConfigRule(); + } else { + return absl::nullopt; + } } private:
diff --git a/chromeos/components/quick_answers/result_loader.cc b/chromeos/components/quick_answers/result_loader.cc index 9ac0302..ca370fc58 100644 --- a/chromeos/components/quick_answers/result_loader.cc +++ b/chromeos/components/quick_answers/result_loader.cc
@@ -26,17 +26,30 @@ sender: "ChromeOS Quick Answers" description: "ChromeOS requests quick answers based on the currently selected " - "text." + "text to look up a translation, dictionary definition, " + "or unit conversion." trigger: "Right click to trigger context menu." + data: "Currently selected text, device language and " + "source language of the selected text " + "is sent to Google API only for translation." destination: GOOGLE_OWNED_SERVICE } policy: { cookies_allowed: YES + cookies_store: "system" setting: "Quick Answers can be enabled/disabled in Chrome Settings and is " "subject to eligibility requirements. The user may also " "separately opt out of sharing screen context with Assistant." + chrome_policy { + QuickAnswersEnabled { + QuickAnswersEnabled: false + } + QuickAnswersTranslationEnabled { + QuickAnswersTranslationEnabled: true + } + } })"); } // namespace
diff --git a/chromeos/profiles/atom.afdo.newest.txt b/chromeos/profiles/atom.afdo.newest.txt index e34d76e..b546e6c 100644 --- a/chromeos/profiles/atom.afdo.newest.txt +++ b/chromeos/profiles/atom.afdo.newest.txt
@@ -1 +1 @@ -chromeos-chrome-amd64-atom-105-5161.0-1658138909-benchmark-105.0.5187.0-r1-redacted.afdo.xz +chromeos-chrome-amd64-atom-105-5161.0-1658138909-benchmark-105.0.5188.0-r2-redacted.afdo.xz
diff --git a/chromeos/resources/BUILD.gn b/chromeos/resources/BUILD.gn index f7f5687..3e33073 100644 --- a/chromeos/resources/BUILD.gn +++ b/chromeos/resources/BUILD.gn
@@ -23,6 +23,7 @@ ] deps = [ + "//chromeos/ash/services/auth_factor_config/public/mojom:mojom_js", "//chromeos/language/public/mojom:mojom_js", "//chromeos/services/bluetooth_config/public/mojom:mojom_js",
diff --git a/chromeos/resources/auth_factor_config_resources.grdp b/chromeos/resources/auth_factor_config_resources.grdp new file mode 100644 index 0000000..87a7663 --- /dev/null +++ b/chromeos/resources/auth_factor_config_resources.grdp
@@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="utf-8"?> +<grit-part> + <include name="IDR_AUTH_FACTOR_CONFIG_MOJOM_WEBUI_JS" + file="${root_gen_dir}/mojom-webui/chromeos/ash/services/auth_factor_config/public/mojom/auth_factor_config.mojom-webui.js" + resource_path="mojo/chromeos/ash/services/auth_factor_config/public/mojom/auth_factor_config.mojom-webui.js" + use_base_dir="false" + type="BINDATA" /> +</grit-part>
diff --git a/chromeos/resources/chromeos_resources.grd b/chromeos/resources/chromeos_resources.grd index 4ab026e..681c7da 100644 --- a/chromeos/resources/chromeos_resources.grd +++ b/chromeos/resources/chromeos_resources.grd
@@ -12,6 +12,7 @@ </outputs> <release seq="1"> <includes> + <part file="auth_factor_config_resources.grdp" /> <part file="cros_bluetooth_config_resources.grdp" /> <part file="cros_network_config_resources.grdp" /> <part file="network_health_resources.grdp" />
diff --git a/components/cdm/renderer/android_key_systems.cc b/components/cdm/renderer/android_key_systems.cc index d028edbc..d5a17359 100644 --- a/components/cdm/renderer/android_key_systems.cc +++ b/components/cdm/renderer/android_key_systems.cc
@@ -16,11 +16,13 @@ #include "media/media_buildflags.h" #if BUILDFLAG(ENABLE_WIDEVINE) #include "components/cdm/renderer/widevine_key_system_properties.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/widevine/cdm/widevine_cdm_common.h" // nogncheck #endif // BUILDFLAG(ENABLE_WIDEVINE) using media::CdmSessionType; using media::EmeConfigRule; +using media::EmeConfigRuleState; using media::EmeFeatureSupport; using media::EmeInitDataType; using media::EncryptionScheme; @@ -62,18 +64,20 @@ return false; } - EmeConfigRule GetEncryptionSchemeConfigRule( + absl::optional<EmeConfigRule> GetEncryptionSchemeConfigRule( EncryptionScheme encryption_scheme) const override { - return encryption_scheme == EncryptionScheme::kCenc - ? EmeConfigRule::SUPPORTED - : EmeConfigRule::NOT_SUPPORTED; + if (encryption_scheme == EncryptionScheme::kCenc) { + return EmeConfigRule(); + } else { + return absl::nullopt; + } } SupportedCodecs GetSupportedCodecs() const override { return supported_codecs_; } - EmeConfigRule GetRobustnessConfigRule( + absl::optional<EmeConfigRule> GetRobustnessConfigRule( const std::string& key_system, media::EmeMediaType media_type, const std::string& requested_robustness, @@ -83,12 +87,16 @@ // not need to account for it here because if it does introduce an // incompatibility at this point, it will still be caught by the rule logic // in KeySystemConfigSelector: crbug.com/1204284 - return requested_robustness.empty() ? EmeConfigRule::SUPPORTED - : EmeConfigRule::NOT_SUPPORTED; + if (requested_robustness.empty()) { + return EmeConfigRule(); + } else { + return absl::nullopt; + } } - EmeConfigRule GetPersistentLicenseSessionSupport() const override { - return EmeConfigRule::NOT_SUPPORTED; + absl::optional<EmeConfigRule> GetPersistentLicenseSessionSupport() + const override { + return absl::nullopt; } EmeFeatureSupport GetPersistentStateSupport() const override { return EmeFeatureSupport::ALWAYS_ENABLED;
diff --git a/components/cdm/renderer/external_clear_key_key_system_properties.cc b/components/cdm/renderer/external_clear_key_key_system_properties.cc index 8b18263..f2a9612 100644 --- a/components/cdm/renderer/external_clear_key_key_system_properties.cc +++ b/components/cdm/renderer/external_clear_key_key_system_properties.cc
@@ -47,36 +47,41 @@ return false; } -media::EmeConfigRule ExternalClearKeyProperties::GetEncryptionSchemeConfigRule( +absl::optional<media::EmeConfigRule> +ExternalClearKeyProperties::GetEncryptionSchemeConfigRule( media::EncryptionScheme encryption_scheme) const { switch (encryption_scheme) { case media::EncryptionScheme::kCenc: case media::EncryptionScheme::kCbcs: - return media::EmeConfigRule::SUPPORTED; + return media::EmeConfigRule(); case media::EncryptionScheme::kUnencrypted: break; } NOTREACHED(); - return media::EmeConfigRule::NOT_SUPPORTED; + return absl::nullopt; } media::SupportedCodecs ExternalClearKeyProperties::GetSupportedCodecs() const { return media::EME_CODEC_MP4_ALL | media::EME_CODEC_WEBM_ALL; } -media::EmeConfigRule ExternalClearKeyProperties::GetRobustnessConfigRule( +absl::optional<media::EmeConfigRule> +ExternalClearKeyProperties::GetRobustnessConfigRule( const std::string& key_system, media::EmeMediaType media_type, const std::string& requested_robustness, const bool* /*hw_secure_requirement*/) const { - return requested_robustness.empty() ? media::EmeConfigRule::SUPPORTED - : media::EmeConfigRule::NOT_SUPPORTED; + if (requested_robustness.empty()) { + return media::EmeConfigRule(); + } else { + return absl::nullopt; + } } // Persistent license sessions are faked. -media::EmeConfigRule +absl::optional<media::EmeConfigRule> ExternalClearKeyProperties::GetPersistentLicenseSessionSupport() const { - return media::EmeConfigRule::SUPPORTED; + return media::EmeConfigRule(); } media::EmeFeatureSupport ExternalClearKeyProperties::GetPersistentStateSupport()
diff --git a/components/cdm/renderer/external_clear_key_key_system_properties.h b/components/cdm/renderer/external_clear_key_key_system_properties.h index 80c9583..50575b6 100644 --- a/components/cdm/renderer/external_clear_key_key_system_properties.h +++ b/components/cdm/renderer/external_clear_key_key_system_properties.h
@@ -10,6 +10,7 @@ #include "build/build_config.h" #include "media/base/key_system_properties.h" #include "media/media_buildflags.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace cdm { @@ -23,15 +24,16 @@ bool IsSupportedKeySystem(const std::string& key_system) const override; bool IsSupportedInitDataType( media::EmeInitDataType init_data_type) const override; - media::EmeConfigRule GetEncryptionSchemeConfigRule( + absl::optional<media::EmeConfigRule> GetEncryptionSchemeConfigRule( media::EncryptionScheme encryption_scheme) const override; media::SupportedCodecs GetSupportedCodecs() const override; - media::EmeConfigRule GetRobustnessConfigRule( + absl::optional<media::EmeConfigRule> GetRobustnessConfigRule( const std::string& key_system, media::EmeMediaType media_type, const std::string& requested_robustness, const bool* hw_secure_requirement) const override; - media::EmeConfigRule GetPersistentLicenseSessionSupport() const override; + absl::optional<media::EmeConfigRule> GetPersistentLicenseSessionSupport() + const override; media::EmeFeatureSupport GetPersistentStateSupport() const override; media::EmeFeatureSupport GetDistinctiveIdentifierSupport() const override; };
diff --git a/components/cdm/renderer/widevine_key_system_properties.cc b/components/cdm/renderer/widevine_key_system_properties.cc index a1a5164b..185adda7 100644 --- a/components/cdm/renderer/widevine_key_system_properties.cc +++ b/components/cdm/renderer/widevine_key_system_properties.cc
@@ -19,6 +19,7 @@ using media::CdmSessionType; using media::EmeConfigRule; +using media::EmeConfigRuleState; using media::EmeFeatureSupport; using media::EmeInitDataType; using media::EmeMediaType; @@ -116,20 +117,21 @@ return false; } -EmeConfigRule WidevineKeySystemProperties::GetEncryptionSchemeConfigRule( +absl::optional<EmeConfigRule> +WidevineKeySystemProperties::GetEncryptionSchemeConfigRule( EncryptionScheme encryption_scheme) const { bool is_supported = encryption_schemes_.contains(encryption_scheme); bool is_hw_secure_supported = hw_secure_encryption_schemes_.contains(encryption_scheme); - - if (is_supported && is_hw_secure_supported) - return EmeConfigRule::SUPPORTED; - else if (is_supported && !is_hw_secure_supported) - return EmeConfigRule::HW_SECURE_CODECS_NOT_ALLOWED; - else if (!is_supported && is_hw_secure_supported) - return EmeConfigRule::HW_SECURE_CODECS_REQUIRED; - else - return EmeConfigRule::NOT_SUPPORTED; + if (is_supported && is_hw_secure_supported) { + return EmeConfigRule(); + } else if (is_supported && !is_hw_secure_supported) { + return EmeConfigRule{.hw_secure_codecs = EmeConfigRuleState::kNotAllowed}; + } else if (!is_supported && is_hw_secure_supported) { + return EmeConfigRule{.hw_secure_codecs = EmeConfigRuleState::kRequired}; + } else { + return absl::nullopt; + } } SupportedCodecs WidevineKeySystemProperties::GetSupportedCodecs() const { @@ -141,14 +143,16 @@ return hw_secure_codecs_; } -EmeConfigRule WidevineKeySystemProperties::GetRobustnessConfigRule( +absl::optional<EmeConfigRule> +WidevineKeySystemProperties::GetRobustnessConfigRule( const std::string& key_system, EmeMediaType media_type, const std::string& requested_robustness, const bool* hw_secure_requirement) const { Robustness robustness = ConvertRobustness(requested_robustness); - if (robustness == Robustness::INVALID) - return EmeConfigRule::NOT_SUPPORTED; + if (robustness == Robustness::INVALID) { + return absl::nullopt; + } Robustness max_robustness = Robustness::INVALID; switch (media_type) { @@ -168,7 +172,7 @@ (max_robustness == Robustness::SW_SECURE_DECODE && robustness == Robustness::HW_SECURE_CRYPTO) || robustness > max_robustness) { - return EmeConfigRule::NOT_SUPPORTED; + return absl::nullopt; } [[maybe_unused]] bool hw_secure_codecs_required = @@ -182,12 +186,13 @@ #if BUILDFLAG(IS_CHROMEOS_LACROS) if (!base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kLacrosUseChromeosProtectedMedia)) { - return EmeConfigRule::IDENTIFIER_REQUIRED; + return EmeConfigRule{.identifier = EmeConfigRuleState::kRequired}; } #endif // BUILDFLAG(IS_CHROMEOS_LACROS) - return EmeConfigRule::IDENTIFIER_AND_HW_SECURE_CODECS_REQUIRED; + return EmeConfigRule{.identifier = EmeConfigRuleState::kRequired, + .hw_secure_codecs = EmeConfigRuleState::kRequired}; #else - return EmeConfigRule::IDENTIFIER_REQUIRED; + return EmeConfigRule{.identifier = EmeConfigRuleState::kRequired}; #endif } @@ -198,38 +203,46 @@ // available for the requested codecs. if (media_type == EmeMediaType::VIDEO && max_robustness == Robustness::HW_SECURE_ALL) { - return EmeConfigRule::IDENTIFIER_RECOMMENDED; + return EmeConfigRule{.identifier = EmeConfigRuleState::kRecommended}; } #elif BUILDFLAG(IS_ANDROID) // On Android, require hardware secure codecs for SW_SECURE_DECODE and above. - if (robustness >= Robustness::SW_SECURE_DECODE || hw_secure_codecs_required) - return EmeConfigRule::HW_SECURE_CODECS_REQUIRED; + if (robustness >= Robustness::SW_SECURE_DECODE || hw_secure_codecs_required) { + return EmeConfigRule{.hw_secure_codecs = EmeConfigRuleState::kRequired}; + } + #elif BUILDFLAG(IS_WIN) if (robustness >= Robustness::HW_SECURE_CRYPTO) { // On Windows, hardware security uses MediaFoundation-based CDM which // requires identifier and persistent state. - return IsHardwareSecurityEnabledForKeySystem(key_system) - ? EmeConfigRule:: - IDENTIFIER_PERSISTENCE_AND_HW_SECURE_CODECS_REQUIRED - : EmeConfigRule::NOT_SUPPORTED; + + if (IsHardwareSecurityEnabledForKeySystem(key_system)) { + return EmeConfigRule{.identifier = EmeConfigRuleState::kRequired, + .persistence = EmeConfigRuleState::kRequired, + .hw_secure_codecs = EmeConfigRuleState::kRequired}; + } else { + return absl::nullopt; + } } else if (robustness < Robustness::HW_SECURE_CRYPTO) { // On Windows, when software security is queried, explicitly not allow // hardware secure codecs to prevent robustness level upgrade, for stability // and compatibility reasons. See https://crbug.com/1327043. - return EmeConfigRule::HW_SECURE_CODECS_NOT_ALLOWED; + return EmeConfigRule{.hw_secure_codecs = EmeConfigRuleState::kNotAllowed}; } #else // On other platforms, require hardware secure codecs for HW_SECURE_CRYPTO and // above. - if (robustness >= Robustness::HW_SECURE_CRYPTO) - return EmeConfigRule::HW_SECURE_CODECS_REQUIRED; + if (robustness >= Robustness::HW_SECURE_CRYPTO) { + return EmeConfigRule{.hw_secure_codecs = EmeConfigRuleState::kRequired}; + } + #endif // BUILDFLAG(IS_CHROMEOS) - return EmeConfigRule::SUPPORTED; + return EmeConfigRule(); } -EmeConfigRule WidevineKeySystemProperties::GetPersistentLicenseSessionSupport() - const { +absl::optional<EmeConfigRule> +WidevineKeySystemProperties::GetPersistentLicenseSessionSupport() const { bool is_supported = session_types_.contains(CdmSessionType::kPersistentLicense); @@ -240,8 +253,13 @@ // Note: On ChromeOS, platform verification (similar to CDM host verification) // is required for persistent license support, which requires identifier. // TODO(crbug.com/1324262): Fix the logic after refactoring EmeConfigRule. - return is_supported ? EmeConfigRule::IDENTIFIER_AND_PERSISTENCE_REQUIRED - : EmeConfigRule::NOT_SUPPORTED; + if (is_supported) { + return EmeConfigRule{.identifier = EmeConfigRuleState::kRequired, + .persistence = EmeConfigRuleState::kRequired}; + + } else { + return absl::nullopt; + } #else // BUILDFLAG(IS_CHROMEOS) bool is_hw_secure_supported = hw_secure_session_types_.contains(CdmSessionType::kPersistentLicense); @@ -250,13 +268,13 @@ // the PERSISTENCE requirement here, which is implicitly assumed and enforced // by `KeySystemConfigSelector`. if (is_supported && is_hw_secure_supported) { - return EmeConfigRule::SUPPORTED; + return EmeConfigRule(); } else if (is_supported && !is_hw_secure_supported) { - return EmeConfigRule::HW_SECURE_CODECS_NOT_ALLOWED; + return EmeConfigRule{.hw_secure_codecs = EmeConfigRuleState::kNotAllowed}; } else if (!is_supported && is_hw_secure_supported) { - return EmeConfigRule::HW_SECURE_CODECS_REQUIRED; + return EmeConfigRule{.hw_secure_codecs = EmeConfigRuleState::kRequired}; } else { - return EmeConfigRule::NOT_SUPPORTED; + return absl::nullopt; } #endif // BUILDFLAG(IS_CHROMEOS) }
diff --git a/components/cdm/renderer/widevine_key_system_properties.h b/components/cdm/renderer/widevine_key_system_properties.h index fec5708c..0b970c01 100644 --- a/components/cdm/renderer/widevine_key_system_properties.h +++ b/components/cdm/renderer/widevine_key_system_properties.h
@@ -10,6 +10,7 @@ #include "base/containers/flat_set.h" #include "media/base/content_decryption_module.h" #include "media/base/key_system_properties.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace cdm { @@ -46,16 +47,17 @@ bool ShouldUseBaseKeySystemName() const override; bool IsSupportedInitDataType( media::EmeInitDataType init_data_type) const override; - media::EmeConfigRule GetEncryptionSchemeConfigRule( + absl::optional<media::EmeConfigRule> GetEncryptionSchemeConfigRule( media::EncryptionScheme encryption_scheme) const override; media::SupportedCodecs GetSupportedCodecs() const override; media::SupportedCodecs GetSupportedHwSecureCodecs() const override; - media::EmeConfigRule GetRobustnessConfigRule( + absl::optional<media::EmeConfigRule> GetRobustnessConfigRule( const std::string& key_system, media::EmeMediaType media_type, const std::string& requested_robustness, const bool* hw_secure_requirement) const override; - media::EmeConfigRule GetPersistentLicenseSessionSupport() const override; + absl::optional<media::EmeConfigRule> GetPersistentLicenseSessionSupport() + const override; media::EmeFeatureSupport GetPersistentStateSupport() const override; media::EmeFeatureSupport GetDistinctiveIdentifierSupport() const override;
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 e5c329e..10e6a7ec 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
@@ -730,6 +730,8 @@ private boolean redirectShouldStayInApp(ExternalNavigationParams params, boolean isExternalProtocol, Intent targetIntent, QueryIntentActivitiesSupplier resolvingInfos) { + if (RedirectHandler.isRefactoringEnabled()) return false; + RedirectHandler handler = params.getRedirectHandler(); if (handler == null) return false; boolean shouldStayInApp = handler.shouldStayInApp(isExternalProtocol, @@ -946,6 +948,7 @@ * page to redirect to an app. */ private boolean isNavigationChainExpired(ExternalNavigationParams params) { + if (RedirectHandler.isRefactoringEnabled()) return false; if (params.getRedirectHandler() != null && params.getRedirectHandler().isNavigationChainExpired()) { if (DEBUG) { @@ -960,15 +963,70 @@ } /** - * If a navigation chain has used the history API to go back/forward external navigation is - * probably not expected or desirable. + * @return whether something along the navigation chain prevents the current navigation from + * leaving Chrome. */ - private boolean navigationChainUsedBackOrForward(ExternalNavigationParams params) { - if (params.getRedirectHandler() != null - && params.getRedirectHandler().navigationChainUsedBackOrForward()) { + private boolean navigationChainBlocksExternalNavigation(ExternalNavigationParams params, + Intent targetIntent, QueryIntentActivitiesSupplier resolvingInfos, + boolean isExternalProtocol) { + if (!RedirectHandler.isRefactoringEnabled()) return false; + + RedirectHandler handler = params.getRedirectHandler(); + if (handler == null) return false; + RedirectHandler.InitialNavigationState initialState = handler.getInitialNavigationState(); + + // See RedirectHandler#NAVIGATION_CHAIN_TIMEOUT_MILLIS for details. We don't want an + // unattended page to redirect to an app. + if (handler.isNavigationChainExpired()) { + if (DEBUG) { + Log.i(TAG, + "Navigation chain expired " + + "(a page waited more than %d seconds to redirect).", + RedirectHandler.NAVIGATION_CHAIN_TIMEOUT_MILLIS); + } + return true; + } + + // If a navigation chain has used the history API to go back/forward external navigation is + // probably not expected or desirable. + if (handler.navigationChainUsedBackOrForward()) { if (DEBUG) Log.i(TAG, "Navigation chain used back or forward."); return true; } + + // Used to prevent things like chaining fallback URLs. + if (handler.shouldNotOverrideUrlLoading()) { + if (DEBUG) Log.i(TAG, "Navigation chain has blocked app launching."); + return true; + } + + // Tab Restores should definitely not launch apps, and refreshes launching apps would + // probably not be expected or desirable. + if (initialState.isFromReload) { + if (DEBUG) Log.i(TAG, "Navigation chain is from a tab restore or refresh."); + return true; + } + + // If the intent targets the calling app, we can bypass the gesture requirements and any + // signals from the initial intent that suggested the intent wanted to stay in Chrome. + if (mDelegate.isIntentForTrustedCallingApp(targetIntent, resolvingInfos)) return false; + + // If an intent targeted Chrome explicitly, we assume the app wanted to launch Chrome and + // not another app. + if (handler.intentPrefersToStayInChrome() && !isExternalProtocol) { + if (DEBUG) Log.i(TAG, "Launching intent explicitly targeted the browser."); + return true; + } + + // Ensure the navigation was started with a user gesture so that inactive pages can't launch + // apps unexpectedly, unless we trust the calling app for a CCT/TWA. + // TODO(https://crbug.com/839751): Remove gesture exception for form submits. + if (initialState.isRendererInitiated && !initialState.hasUserGesture + && !initialState.isFromFormSubmit) { + if (isExternalProtocol) handler.maybeLogExternalRedirectBlockedWithMissingGesture(); + if (DEBUG) Log.i(TAG, "Navigation chain started without a gesture."); + return true; + } return false; } @@ -1510,9 +1568,6 @@ if (isLinkFromChromeInternalPage(params)) return OverrideUrlLoadingResult.forNoOverride(); if (RedirectHandler.isRefactoringEnabled()) { - if (navigationChainUsedBackOrForward(params)) { - return OverrideUrlLoadingResult.forNoOverride(); - } if (isDirectFormSubmit(params, isExternalProtocol)) { return OverrideUrlLoadingResult.forNoOverride(); } @@ -1548,6 +1603,8 @@ boolean requiresPromptForExternalIntent = isNavigationChainExpired(params) || redirectShouldStayInApp(params, isExternalProtocol, targetIntent, resolvingInfos) + || navigationChainBlocksExternalNavigation( + params, targetIntent, resolvingInfos, isExternalProtocol) || !preferToShowIntentPicker(params, isExternalProtocol, incomingIntentRedirect, intentMatchesNonDefaultWebApk);
diff --git a/components/external_intents/android/java/src/org/chromium/components/external_intents/RedirectHandler.java b/components/external_intents/android/java/src/org/chromium/components/external_intents/RedirectHandler.java index ab073fc..87a55bc 100644 --- a/components/external_intents/android/java/src/org/chromium/components/external_intents/RedirectHandler.java +++ b/components/external_intents/android/java/src/org/chromium/components/external_intents/RedirectHandler.java
@@ -350,47 +350,20 @@ /** * @param hasExternalProtocol whether the destination URI has an external protocol or not. - * @return whether we should stay in Chrome or not. - */ - public boolean shouldStayInApp(boolean hasExternalProtocol) { - return shouldStayInApp(hasExternalProtocol, false); - } - - /** - * @param hasExternalProtocol whether the destination URI has an external protocol or not. * @param isForTrustedCallingApp whether the app we would launch to is trusted and what launched * Chrome. * @return whether we should stay in Chrome or not. */ - public boolean shouldStayInApp(boolean hasExternalProtocol, boolean isForTrustedCallingApp) { + /* package */ boolean shouldStayInApp( + boolean hasExternalProtocol, boolean isForTrustedCallingApp) { + assert !isRefactoringEnabled(); // http://crbug/424029 : Need to stay in Chrome for an intent heading explicitly to Chrome. // http://crbug/881740 : Relax stay in Chrome restriction for Custom Tabs. return (mIntentState != null && mIntentState.mPreferToStayInChrome && !hasExternalProtocol) || shouldNavigationTypeStayInApp(isForTrustedCallingApp); } - /** - * @return Whether the current navigation is of the type that should always stay in Chrome. - */ - public boolean shouldNavigationTypeStayInApp() { - return shouldNavigationTypeStayInApp(false); - } - private boolean shouldNavigationTypeStayInApp(boolean isForTrustedCallingApp) { - if (isRefactoringEnabled()) { - InitialNavigationState state = mNavigationChainState.getInitialNavigationState(); - // http://crbug.com/162106: Never leave Chrome from a refresh. - if (state.isFromReload) return true; - - // If the app we would navigate to is trusted and what launched Chrome, allow the - // navigation. - if (isForTrustedCallingApp) return false; - - // Otherwise allow navigation out of the app only with a user gesture. - // TODO(https://crbug.com/839751): Remove gesture exception for form submits. - return state.isRendererInitiated && !state.hasUserGesture && !state.isFromFormSubmit; - } - // http://crbug.com/162106: Never leave Chrome from a refresh. if (mNavigationChainState.getInitialNavigationType() == NAVIGATION_TYPE_FROM_RELOAD) { return true; @@ -514,6 +487,10 @@ return mNavigationChainState.getInitialNavigationState(); } + public boolean intentPrefersToStayInChrome() { + return mIntentState != null && mIntentState.mPreferToStayInChrome; + } + public void maybeLogExternalRedirectBlockedWithMissingGesture() { boolean shouldLog = false; if (isRefactoringEnabled()) {
diff --git a/components/external_intents/android/javatests/src/org/chromium/components/external_intents/ExternalNavigationHandlerTest.java b/components/external_intents/android/javatests/src/org/chromium/components/external_intents/ExternalNavigationHandlerTest.java index 17c88aa9..d2aaac4 100644 --- a/components/external_intents/android/javatests/src/org/chromium/components/external_intents/ExternalNavigationHandlerTest.java +++ b/components/external_intents/android/javatests/src/org/chromium/components/external_intents/ExternalNavigationHandlerTest.java
@@ -1866,8 +1866,7 @@ RedirectHandler redirectHandler = RedirectHandler.create(); - redirectHandler.updateNewUrlLoading( - PageTransition.RELOAD, false, false, 1, 0, false, false); + redirectHandler.updateNewUrlLoading(PageTransition.RELOAD, true, false, 1, 0, false, false); checkUrl(YOUTUBE_MOBILE_URL) .withRedirectHandler(redirectHandler) .expecting(OverrideUrlLoadingResultType.NO_OVERRIDE, IGNORE); @@ -1892,7 +1891,7 @@ RedirectHandler redirectHandler = RedirectHandler.create(); redirectHandler.updateNewUrlLoading( - PageTransition.FORM_SUBMIT | PageTransition.FORWARD_BACK, false, false, 1, 0, false, + PageTransition.FORM_SUBMIT | PageTransition.FORWARD_BACK, true, false, 1, 0, false, false); checkUrl(YOUTUBE_MOBILE_URL) .withRedirectHandler(redirectHandler) @@ -2698,6 +2697,41 @@ START_OTHER_ACTIVITY); } + @Test + @SmallTest + public void testIntentFromChrome() throws Exception { + mDelegate.add(new IntentActivity(YOUTUBE_MOBILE_URL, YOUTUBE_PACKAGE_NAME)); + RedirectHandler redirectHandler = RedirectHandler.create(); + Intent fooIntent = Intent.parseUri(YOUTUBE_URL, Intent.URI_INTENT_SCHEME); + // Set Chrome AppId for the Intent. + fooIntent.putExtra(Browser.EXTRA_APPLICATION_ID, SELF_PACKAGE_NAME); + redirectHandler.updateIntent( + fooIntent, !IS_CUSTOM_TAB_INTENT, !SEND_TO_EXTERNAL_APPS, !INTENT_STARTED_TASK); + + redirectHandler.updateNewUrlLoading( + PageTransition.LINK | PageTransition.FROM_API, false, false, 0, 0, false, false); + checkUrl(YOUTUBE_URL) + .withRedirectHandler(redirectHandler) + .expecting(OverrideUrlLoadingResultType.NO_OVERRIDE, IGNORE); + + // Redirects to URL with new handlers. + redirectHandler.updateNewUrlLoading( + PageTransition.LINK | PageTransition.FROM_API, true, false, 0, 0, false, false); + checkUrl(YOUTUBE_MOBILE_URL) + .withRedirectHandler(redirectHandler) + .expecting(OverrideUrlLoadingResultType.NO_OVERRIDE, IGNORE); + + // User clicks link. + redirectHandler.updateNewUrlLoading(PageTransition.LINK, false, true, + SystemClock.elapsedRealtime() + 1, 2, false, true); + checkUrl(YOUTUBE_MOBILE_URL) + .withRedirectHandler(redirectHandler) + .expecting(OverrideUrlLoadingResultType.OVERRIDE_WITH_EXTERNAL_INTENT, + START_OTHER_ACTIVITY); + Assert.assertEquals( + 2, redirectHandler.getLastCommittedEntryIndexBeforeStartingNavigation()); + } + private static List<ResolveInfo> makeResolveInfos(ResolveInfo... infos) { return Arrays.asList(infos); }
diff --git a/components/external_intents/android/javatests/src/org/chromium/components/external_intents/RedirectHandlerTest.java b/components/external_intents/android/javatests/src/org/chromium/components/external_intents/RedirectHandlerTest.java index be4529d7..f3425ce 100644 --- a/components/external_intents/android/javatests/src/org/chromium/components/external_intents/RedirectHandlerTest.java +++ b/components/external_intents/android/javatests/src/org/chromium/components/external_intents/RedirectHandlerTest.java
@@ -10,7 +10,6 @@ import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.os.SystemClock; -import android.provider.Browser; import android.test.mock.MockPackageManager; import androidx.test.filters.SmallTest; @@ -266,37 +265,6 @@ @Test @SmallTest @Feature({"IntentHandling"}) - public void testIntentFromChrome() { - RedirectHandler handler = RedirectHandler.create(); - Intent fooIntent = new Intent(sFooIntent); - fooIntent.putExtra(Browser.EXTRA_APPLICATION_ID, TEST_PACKAGE_NAME); - handler.updateIntent(fooIntent, false, false, false); - Assert.assertFalse(handler.isOnNavigation()); - - handler.updateNewUrlLoading( - TRANS_TYPE_OF_LINK_FROM_INTENT, false, false, 0, 0, false, false); - Assert.assertTrue(handler.shouldStayInApp(false)); - Assert.assertFalse(handler.shouldStayInApp(true)); - handler.updateNewUrlLoading(PageTransition.LINK, false, false, 0, 1, false, true); - Assert.assertTrue(handler.shouldStayInApp(false)); - Assert.assertFalse(handler.shouldStayInApp(true)); - - Assert.assertTrue(handler.isOnNavigation()); - Assert.assertEquals(0, handler.getLastCommittedEntryIndexBeforeStartingNavigation()); - - SystemClock.sleep(1); - handler.updateNewUrlLoading( - PageTransition.LINK, false, true, SystemClock.elapsedRealtime(), 2, false, true); - Assert.assertFalse(handler.shouldStayInApp(false)); - Assert.assertFalse(handler.shouldStayInApp(true)); - - Assert.assertTrue(handler.isOnNavigation()); - Assert.assertEquals(2, handler.getLastCommittedEntryIndexBeforeStartingNavigation()); - } - - @Test - @SmallTest - @Feature({"IntentHandling"}) public void testNavigationFromUserTyping() { RedirectHandler handler = RedirectHandler.create(); handler.updateIntent(sYtIntent, false, false, false); @@ -322,36 +290,6 @@ @Test @SmallTest @Feature({"IntentHandling"}) - public void testIntentHavingChromePackageName() { - RedirectHandler handler = RedirectHandler.create(); - Intent fooIntent = new Intent(sFooIntent); - fooIntent.setPackage(TEST_PACKAGE_NAME); - handler.updateIntent(fooIntent, false, false, false); - Assert.assertFalse(handler.isOnNavigation()); - - handler.updateNewUrlLoading( - TRANS_TYPE_OF_LINK_FROM_INTENT, false, false, 0, 0, false, false); - Assert.assertTrue(handler.shouldStayInApp(false)); - Assert.assertFalse(handler.shouldStayInApp(true)); - handler.updateNewUrlLoading(PageTransition.LINK, false, false, 0, 1, false, true); - Assert.assertTrue(handler.shouldStayInApp(false)); - Assert.assertFalse(handler.shouldStayInApp(true)); - - Assert.assertTrue(handler.isOnNavigation()); - Assert.assertEquals(0, handler.getLastCommittedEntryIndexBeforeStartingNavigation()); - - handler.updateNewUrlLoading(PageTransition.LINK, false, true, - SystemClock.elapsedRealtime() + 1, 2, false, true); - Assert.assertFalse(handler.shouldStayInApp(false)); - Assert.assertFalse(handler.shouldStayInApp(true)); - - Assert.assertTrue(handler.isOnNavigation()); - Assert.assertEquals(2, handler.getLastCommittedEntryIndexBeforeStartingNavigation()); - } - - @Test - @SmallTest - @Feature({"IntentHandling"}) public void testRedirectFromCurrentNavigationShouldNotOverrideUrlLoading() { ///////////////////////////////////////////////////// // 1. 3XX redirection should not override URL loading. @@ -395,113 +333,6 @@ @Test @SmallTest @Feature({"IntentHandling"}) - public void testNavigationFromLinkWithoutUserGesture() { - RedirectHandler handler = RedirectHandler.create(); - handler.updateIntent(sYtIntent, false, false, false); - Assert.assertFalse(handler.isOnNavigation()); - - long lastUserInteractionTime = SystemClock.elapsedRealtime(); - handler.updateNewUrlLoading( - PageTransition.LINK, false, false, lastUserInteractionTime, 0, false, true); - Assert.assertTrue(handler.shouldStayInApp(false)); - Assert.assertTrue(handler.shouldStayInApp(true)); - handler.updateNewUrlLoading( - PageTransition.LINK, false, false, lastUserInteractionTime, 1, false, true); - Assert.assertTrue(handler.shouldStayInApp(false)); - Assert.assertTrue(handler.shouldStayInApp(true)); - - Assert.assertTrue(handler.isOnNavigation()); - Assert.assertEquals(0, handler.getLastCommittedEntryIndexBeforeStartingNavigation()); - - SystemClock.sleep(1); - handler.updateNewUrlLoading( - PageTransition.LINK, false, true, SystemClock.elapsedRealtime(), 2, false, true); - Assert.assertFalse(handler.shouldStayInApp(false)); - Assert.assertFalse(handler.shouldStayInApp(true)); - - Assert.assertTrue(handler.isOnNavigation()); - Assert.assertEquals(2, handler.getLastCommittedEntryIndexBeforeStartingNavigation()); - } - - @Test - @SmallTest - @Feature({"IntentHandling"}) - public void testNavigationFromReload() { - RedirectHandler handler = RedirectHandler.create(); - handler.updateIntent(sYtIntent, false, false, false); - Assert.assertFalse(handler.isOnNavigation()); - - long lastUserInteractionTime = SystemClock.elapsedRealtime(); - handler.updateNewUrlLoading( - PageTransition.RELOAD, false, false, lastUserInteractionTime, 0, false, false); - Assert.assertTrue(handler.shouldStayInApp(false)); - Assert.assertTrue(handler.shouldStayInApp(true)); - handler.updateNewUrlLoading( - PageTransition.LINK, false, false, lastUserInteractionTime, 1, false, true); - Assert.assertTrue(handler.shouldStayInApp(false)); - Assert.assertTrue(handler.shouldStayInApp(true)); - - Assert.assertTrue(handler.isOnNavigation()); - Assert.assertEquals(0, handler.getLastCommittedEntryIndexBeforeStartingNavigation()); - - SystemClock.sleep(1); - handler.updateNewUrlLoading( - PageTransition.LINK, false, true, SystemClock.elapsedRealtime(), 2, false, true); - Assert.assertFalse(handler.shouldStayInApp(false)); - Assert.assertFalse(handler.shouldStayInApp(true)); - - Assert.assertTrue(handler.isOnNavigation()); - Assert.assertEquals(2, handler.getLastCommittedEntryIndexBeforeStartingNavigation()); - } - - @Test - @SmallTest - @Feature({"IntentHandling"}) - public void testNavigationWithForwardBack() { - RedirectHandler handler = RedirectHandler.create(); - handler.updateIntent(sYtIntent, false, false, false); - Assert.assertFalse(handler.isOnNavigation()); - - long lastUserInteractionTime = SystemClock.elapsedRealtime(); - handler.updateNewUrlLoading(PageTransition.FORM_SUBMIT | PageTransition.FORWARD_BACK, false, - true, lastUserInteractionTime, 0, false, false); - if (RedirectHandler.isRefactoringEnabled()) { - Assert.assertTrue(handler.navigationChainUsedBackOrForward()); - } else { - Assert.assertTrue(handler.shouldStayInApp(false)); - Assert.assertTrue(handler.shouldStayInApp(true)); - } - Assert.assertTrue(handler.hasUserStartedNonInitialNavigation()); - - handler.updateNewUrlLoading(PageTransition.LINK, false, false, lastUserInteractionTime, 1, - false /* isInitialNavigation */, true); - if (RedirectHandler.isRefactoringEnabled()) { - Assert.assertTrue(handler.navigationChainUsedBackOrForward()); - } else { - Assert.assertTrue(handler.shouldStayInApp(false)); - Assert.assertTrue(handler.shouldStayInApp(true)); - } - - Assert.assertTrue(handler.isOnNavigation()); - Assert.assertEquals(0, handler.getLastCommittedEntryIndexBeforeStartingNavigation()); - Assert.assertTrue(handler.hasUserStartedNonInitialNavigation()); - - handler.updateNewUrlLoading(PageTransition.LINK, false, true, - SystemClock.elapsedRealtime() + 1, 2, false /* isInitialNavigation */, true); - if (RedirectHandler.isRefactoringEnabled()) { - Assert.assertFalse(handler.navigationChainUsedBackOrForward()); - } - Assert.assertFalse(handler.shouldStayInApp(false)); - Assert.assertFalse(handler.shouldStayInApp(true)); - - Assert.assertTrue(handler.isOnNavigation()); - Assert.assertEquals(2, handler.getLastCommittedEntryIndexBeforeStartingNavigation()); - Assert.assertTrue(handler.hasUserStartedNonInitialNavigation()); - } - - @Test - @SmallTest - @Feature({"IntentHandling"}) public void testNavigationWithUninitializedUserInteractionTime() { // User interaction time could be uninitialized when a new document activity is opened after // clicking a link. In that case, the value is 0. @@ -518,36 +349,6 @@ Assert.assertFalse(handler.hasUserStartedNonInitialNavigation()); } - /** - * Tests that a client side redirect without a user gesture to an external application does - * cause us to leave Chrome, unless the app it would be launching is trusted. - */ - @Test - @SmallTest - @Feature({"IntentHandling"}) - public void testClientRedirectWithoutUserGesture() { - RedirectHandler handler = RedirectHandler.create(); - handler.updateIntent(sFooIntent, false, false, false); - Assert.assertFalse(handler.isOnNavigation()); - Assert.assertFalse(handler.hasUserStartedNonInitialNavigation()); - - // Navigation to a page that will trigger a client redirect. - handler.updateNewUrlLoading(PageTransition.LINK, false /* isRedirect */, - false /* hasUserGesture */, 0, 0, true /* isInitialNavigation */, - true /* isRendererInitiated */); - Assert.assertTrue(handler.shouldStayInApp(true)); - Assert.assertFalse(handler.shouldStayInApp(true, true)); - Assert.assertFalse(handler.hasUserStartedNonInitialNavigation()); - - // Client redirect navigation. - handler.updateNewUrlLoading(PageTransition.LINK | PageTransition.CLIENT_REDIRECT, - false /* isRedirect */, false /* hasUserGesture */, 0, 0, - false /* isInitialNavigation */, true /* isRendererInitiated */); - Assert.assertTrue(handler.shouldStayInApp(true)); - Assert.assertFalse(handler.shouldStayInApp(true, true)); - Assert.assertFalse(handler.hasUserStartedNonInitialNavigation()); - } - @Test @SmallTest @Feature({"IntentHandling"})
diff --git a/components/history_clusters/core/keyword_cluster_finalizer.cc b/components/history_clusters/core/keyword_cluster_finalizer.cc index a3aba01..3837936b 100644 --- a/components/history_clusters/core/keyword_cluster_finalizer.cc +++ b/components/history_clusters/core/keyword_cluster_finalizer.cc
@@ -61,7 +61,7 @@ left, const std::pair<std::u16string, const history::ClusterKeywordData*>& right) { - return std::fabs(left.second->score - right.second->type) > + return std::fabs(left.second->score - right.second->score) > kScoreEpsilon ? left.second->score > right.second->score : left.second->type > right.second->type;
diff --git a/components/language/content/browser/geo_language_provider_unittest.cc b/components/language/content/browser/geo_language_provider_unittest.cc index c6ecb2a..48eae5a 100644 --- a/components/language/content/browser/geo_language_provider_unittest.cc +++ b/components/language/content/browser/geo_language_provider_unittest.cc
@@ -76,10 +76,9 @@ const std::vector<std::string> GetCachedLanguages() { std::vector<std::string> languages; - const base::Value* const cached_languages_list = - local_state_.GetList(GeoLanguageProvider::kCachedGeoLanguagesPref); - for (const auto& language_value : - cached_languages_list->GetListDeprecated()) { + const base::Value::List& cached_languages_list = + local_state_.GetValueList(GeoLanguageProvider::kCachedGeoLanguagesPref); + for (const auto& language_value : cached_languages_list) { languages.push_back(language_value.GetString()); } return languages;
diff --git a/components/language/content/browser/ulp_language_code_locator/ulp_language_code_locator.cc b/components/language/content/browser/ulp_language_code_locator/ulp_language_code_locator.cc index 8cd8296b..f306f15 100644 --- a/components/language/content/browser/ulp_language_code_locator/ulp_language_code_locator.cc +++ b/components/language/content/browser/ulp_language_code_locator/ulp_language_code_locator.cc
@@ -55,14 +55,14 @@ std::vector<std::string> languages; ListPrefUpdate update(prefs_, kCachedGeoLanguagesPref); - base::Value* celllangs_cached = update.Get(); + base::Value::List& celllangs_cached = update->GetList(); for (size_t index = 0; index < serialized_langtrees_.size(); index++) { std::string language; bool is_cached = false; const base::Value* celllang_cached = nullptr; - if (index < celllangs_cached->GetListDeprecated().size()) { - celllang_cached = &celllangs_cached->GetListDeprecated()[index]; + if (index < celllangs_cached.size()) { + celllang_cached = &celllangs_cached[index]; is_cached = celllang_cached->is_dict(); } @@ -84,10 +84,10 @@ language = root.Get(cell, &level); if (level != -1) { if (is_cached) { - celllangs_cached->GetListDeprecated()[index] = + celllangs_cached[index] = GetCellLanguagePairValue(cell.parent(level), language); } else { - celllangs_cached->Append( + celllangs_cached.Append( GetCellLanguagePairValue(cell.parent(level), language)); } }
diff --git a/components/language/core/browser/language_prefs.cc b/components/language/core/browser/language_prefs.cc index 26f86d6..f37733e 100644 --- a/components/language/core/browser/language_prefs.cc +++ b/components/language/core/browser/language_prefs.cc
@@ -107,8 +107,8 @@ forced_languages_set_.clear(); // Add policy languages. - for (const auto& language : prefs_->GetList(language::prefs::kForcedLanguages) - ->GetListDeprecated()) { + for (const auto& language : + prefs_->GetValueList(language::prefs::kForcedLanguages)) { if (forced_languages_set_.find(language.GetString()) == forced_languages_set_.end()) { deduplicated_languages.emplace_back(language.GetString());
diff --git a/components/language/core/browser/language_prefs_test_util.cc b/components/language/core/browser/language_prefs_test_util.cc index 618448f6..e4db640 100644 --- a/components/language/core/browser/language_prefs_test_util.cc +++ b/components/language/core/browser/language_prefs_test_util.cc
@@ -72,14 +72,13 @@ void LanguagePrefTester::SetForcedLanguagePrefs( std::vector<std::string>&& languages) { - base::Value::ListStorage languages_list; + base::Value::List languages_list; for (std::string language : languages) { - languages_list.push_back(base::Value(std::move(language))); + languages_list.Append(std::move(language)); } - prefs_->Set(language::prefs::kForcedLanguages, - base::Value(std::move(languages_list))); + prefs_->SetList(language::prefs::kForcedLanguages, std::move(languages_list)); } } // namespace test
diff --git a/components/language/core/language_model/fluent_language_model_unittest.cc b/components/language/core/language_model/fluent_language_model_unittest.cc index 6da071f..ffeff29 100644 --- a/components/language/core/language_model/fluent_language_model_unittest.cc +++ b/components/language/core/language_model/fluent_language_model_unittest.cc
@@ -68,11 +68,12 @@ } TEST_F(FluentLanguageModelTest, ThreeBlockedLanguages) { - base::Value fluent_languages(base::Value::Type::LIST); + base::Value::List fluent_languages; fluent_languages.Append("fr"); fluent_languages.Append("ja"); fluent_languages.Append("en"); - prefs_->Set(translate::prefs::kBlockedLanguages, fluent_languages); + prefs_->SetList(translate::prefs::kBlockedLanguages, + std::move(fluent_languages)); FluentLanguageModel model(prefs_.get()); EXPECT_THAT(model.GetLanguages(), ElementsAre(EqualsLd(Ld("fr", 1.0f / 1)),
diff --git a/components/mirroring/service/BUILD.gn b/components/mirroring/service/BUILD.gn index 61add76..ea712e6 100644 --- a/components/mirroring/service/BUILD.gn +++ b/components/mirroring/service/BUILD.gn
@@ -68,6 +68,7 @@ "//third_party/jsoncpp", # Required by Open Screen API. "//third_party/libaom:libaom_buildflags", "//third_party/openscreen/src/cast/streaming:common", + "//third_party/openscreen/src/cast/streaming:sender", "//ui/base", "//ui/gfx", ] @@ -118,6 +119,7 @@ "//testing/gmock", "//testing/gtest", "//third_party/openscreen/src/cast/streaming:common", + "//third_party/openscreen/src/cast/streaming:sender", ] include_dirs = [ "//third_party/openscreen/src" ]
diff --git a/components/mirroring/service/remoting_sender.cc b/components/mirroring/service/remoting_sender.cc index 5500c51..44c0419 100644 --- a/components/mirroring/service/remoting_sender.cc +++ b/components/mirroring/service/remoting_sender.cc
@@ -12,9 +12,13 @@ #include "base/threading/thread_task_runner_handle.h" #include "base/time/default_tick_clock.h" #include "base/time/time.h" +#include "media/base/media_switches.h" +#include "media/cast/common/openscreen_conversion_helpers.h" #include "media/cast/common/sender_encoded_frame.h" #include "media/cast/constants.h" +#include "media/cast/sender/openscreen_frame_sender.h" #include "media/mojo/common/mojo_data_pipe_read_write.h" +#include "third_party/openscreen/src/cast/streaming/sender.h" namespace mirroring { @@ -25,10 +29,43 @@ mojo::ScopedDataPipeConsumerHandle pipe, mojo::PendingReceiver<media::mojom::RemotingDataStreamSender> stream_sender, base::OnceClosure error_callback) - : frame_sender_(media::cast::FrameSender::Create(cast_environment, - config, - transport, - this)), + : RemotingSender(cast_environment, + media::cast::FrameSender::Create(cast_environment, + config, + transport, + *this), + config, + std::move(pipe), + std::move(stream_sender), + std::move(error_callback)) {} + +RemotingSender::RemotingSender( + scoped_refptr<media::cast::CastEnvironment> cast_environment, + openscreen::cast::Sender* sender, + const media::cast::FrameSenderConfig& config, + mojo::ScopedDataPipeConsumerHandle pipe, + mojo::PendingReceiver<media::mojom::RemotingDataStreamSender> stream_sender, + base::OnceClosure error_callback) + : RemotingSender(cast_environment, + media::cast::FrameSender::Create(cast_environment, + config, + sender, + *this), + config, + std::move(pipe), + std::move(stream_sender), + std::move(error_callback)) { + DCHECK(base::FeatureList::IsEnabled(media::kOpenscreenCastStreamingSession)); +} + +RemotingSender::RemotingSender( + scoped_refptr<media::cast::CastEnvironment> cast_environment, + std::unique_ptr<media::cast::FrameSender> frame_sender, + const media::cast::FrameSenderConfig& config, + mojo::ScopedDataPipeConsumerHandle pipe, + mojo::PendingReceiver<media::mojom::RemotingDataStreamSender> stream_sender, + base::OnceClosure error_callback) + : frame_sender_(std::move(frame_sender)), clock_(cast_environment->Clock()), error_callback_(std::move(error_callback)), data_pipe_reader_(new media::MojoDataPipeReader(std::move(pipe))), @@ -160,7 +197,7 @@ remoting_frame->rtp_timestamp = last_frame_rtp_timestamp + std::max(media::cast::RtpTimeDelta::FromTicks(1), - media::cast::RtpTimeDelta::FromTimeDelta( + ToRtpTimeDelta( remoting_frame->reference_time - last_frame_reference_time, media::cast::kRemotingRtpTimebase)); remoting_frame->data.swap(next_frame_data_);
diff --git a/components/mirroring/service/remoting_sender.h b/components/mirroring/service/remoting_sender.h index 2328a8b..3669d69 100644 --- a/components/mirroring/service/remoting_sender.h +++ b/components/mirroring/service/remoting_sender.h
@@ -26,6 +26,10 @@ class MojoDataPipeReader; } // namespace media +namespace openscreen::cast { +class Sender; +} // namespace openscreen::cast + namespace mirroring { // RTP sender for a single Cast Remoting RTP stream. The client calls Send() to @@ -35,7 +39,10 @@ : public media::mojom::RemotingDataStreamSender, public media::cast::FrameSender::Client { public: - // |transport| is expected to outlive this class. + // Old way of instantiating using a cast transport. |transport| is expected to + // outlive this class. + // TODO(https://crbug.com/1316434): should be removed once libcast sender is + // successfully launched. RemotingSender(scoped_refptr<media::cast::CastEnvironment> cast_environment, media::cast::CastTransport* transport, const media::cast::FrameSenderConfig& config, @@ -44,12 +51,31 @@ stream_sender, base::OnceClosure error_callback); + // New way of instantiating using an openscreen::cast::Sender. Since the + // |Sender| instance is destroyed when renegotiation is complete, |this| + // is also invalid and should be immediately torn down. + RemotingSender(scoped_refptr<media::cast::CastEnvironment> cast_environment, + openscreen::cast::Sender* sender, + const media::cast::FrameSenderConfig& config, + mojo::ScopedDataPipeConsumerHandle pipe, + mojo::PendingReceiver<media::mojom::RemotingDataStreamSender> + stream_sender, + base::OnceClosure error_callback); + RemotingSender(const RemotingSender&) = delete; RemotingSender& operator=(const RemotingSender&) = delete; ~RemotingSender() override; private: + RemotingSender(scoped_refptr<media::cast::CastEnvironment> cast_environment, + std::unique_ptr<media::cast::FrameSender> sender, + const media::cast::FrameSenderConfig& config, + mojo::ScopedDataPipeConsumerHandle pipe, + mojo::PendingReceiver<media::mojom::RemotingDataStreamSender> + stream_sender, + base::OnceClosure error_callback); + // Friend class for unit tests. friend class RemotingSenderTest;
diff --git a/components/omnibox/browser/autocomplete_controller.cc b/components/omnibox/browser/autocomplete_controller.cc index 5de48e3..15b4119c 100644 --- a/components/omnibox/browser/autocomplete_controller.cc +++ b/components/omnibox/browser/autocomplete_controller.cc
@@ -443,6 +443,12 @@ TRACE_EVENT1("omnibox", "AutocompleteController::Start", "text", base::UTF16ToUTF8(input.text())); + // Providers assume synchronous inputs (`want_asynchronous_matches() == + // false`) have default focus type (`focus_type() == DEFAULT`). See + // crbug.com/1339425. + DCHECK(input.want_asynchronous_matches() || + input.focus_type() == OmniboxFocusType::DEFAULT); + // When input.want_asynchronous_matches() is false, the AutocompleteController // is being used for text classification, which should not notify observers. // TODO(manukh): This seems unnecessary; `AutocompleteClassifier` and @@ -503,8 +509,6 @@ base::TimeTicks provider_start_time = base::TimeTicks::Now(); provider->Start(input_, minimal_changes); - if (!input.want_asynchronous_matches()) - DCHECK(provider->done()); // `UmaHistogramTimes()` uses 1ms - 10s buckets, whereas this uses 1ms - 5s // buckets. // TODO(crbug.com/1340291|manukh): This isn't handled by `metrics_` yet. It @@ -1131,16 +1135,19 @@ } void AutocompleteController::CheckIfDone() { + bool all_providers_done = true; for (const auto& provider : providers_) { if (!ShouldRunProvider(provider.get())) continue; if (!provider->done()) { - done_ = false; - return; + all_providers_done = false; + break; } } - done_ = true; + // If asynchronous matches have been disallowed, all providers should be done. + DCHECK(input_.want_asynchronous_matches() || all_providers_done); + done_ = all_providers_done; } void AutocompleteController::StartExpireTimer() {
diff --git a/components/omnibox/browser/bookmark_provider.cc b/components/omnibox/browser/bookmark_provider.cc index e5716d7..4e8bbd7 100644 --- a/components/omnibox/browser/bookmark_provider.cc +++ b/components/omnibox/browser/bookmark_provider.cc
@@ -17,6 +17,7 @@ #include "components/bookmarks/browser/bookmark_model.h" #include "components/omnibox/browser/autocomplete_provider_client.h" #include "components/omnibox/browser/autocomplete_result.h" +#include "components/omnibox/browser/keyword_provider.h" #include "components/omnibox/browser/omnibox_field_trial.h" #include "components/omnibox/browser/omnibox_triggered_feature_service.h" #include "components/omnibox/browser/titled_url_match_utils.h" @@ -76,7 +77,13 @@ if (input.focus_type() != OmniboxFocusType::DEFAULT || input.text().empty()) return; - DoAutocomplete(input); + // Remove the keyword from input if we're in keyword mode for a starter pack + // engine. + const AutocompleteInput adjusted_input = + KeywordProvider::AdjustInputForStarterPackEngines( + input, client_->GetTemplateURLService()); + + DoAutocomplete(adjusted_input); } BookmarkProvider::~BookmarkProvider() {} @@ -186,8 +193,15 @@ query_parser::MatchingAlgorithm BookmarkProvider::GetMatchingAlgorithm( AutocompleteInput input) { - if (OmniboxFieldTrial::IsShortBookmarkSuggestionsEnabled()) + // TODO(yoangela): This might have to check whether we're in @bookmarks mode + // specifically, since we might still get bookmarks suggestions in + // non-bookmarks keyword mode. This is enough of an edge case it makes sense + // to just stick with simplicity for now. + if (OmniboxFieldTrial::IsShortBookmarkSuggestionsEnabled() || + (OmniboxFieldTrial::IsSiteSearchStarterPackEnabled() && + InKeywordMode(input))) { return query_parser::MatchingAlgorithm::ALWAYS_PREFIX_SEARCH; + } if (OmniboxFieldTrial:: IsShortBookmarkSuggestionsByTotalInputLengthEnabled() &&
diff --git a/components/omnibox/browser/bookmark_provider_unittest.cc b/components/omnibox/browser/bookmark_provider_unittest.cc index 535d61a4..94f92e69 100644 --- a/components/omnibox/browser/bookmark_provider_unittest.cc +++ b/components/omnibox/browser/bookmark_provider_unittest.cc
@@ -28,6 +28,9 @@ #include "components/omnibox/browser/titled_url_match_utils.h" #include "components/omnibox/common/omnibox_features.h" #include "components/search_engines/omnibox_focus_type.h" +#include "components/search_engines/template_url.h" +#include "components/search_engines/template_url_service.h" +#include "components/search_engines/template_url_starter_pack_data.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/abseil-cpp/absl/types/optional.h" @@ -79,6 +82,8 @@ {"", "http://emptytitle.com/"}, // For testing short bookmarks. {"testing short bookmarks", "https://zzz.com"}, + // For testing bookmarks search in keyword mode. + {"@bookmarks", "chrome://bookmarks"}, }; // Structures and functions supporting the BookmarkProviderTest.Positions @@ -205,6 +210,9 @@ EXPECT_CALL(*provider_client_, GetSchemeClassifier()) .WillRepeatedly(testing::ReturnRef(classifier_)); + provider_client_->set_template_url_service( + std::make_unique<TemplateURLService>(nullptr, 0)); + provider_ = new BookmarkProvider(provider_client_.get()); const BookmarkNode* other_node = model_->other_node(); for (size_t i = 0; i < std::size(bookmark_provider_test_data); ++i) { @@ -749,3 +757,59 @@ TestNumMatchesAndTriggeredFeature("carefully other", 1, trigger_feature); } } + +// Make sure that user input is trimmed correctly for starter pack keyword mode. +// In this mode, suggestions should be provided for only the user input after +// the keyword, i.e. "@bookmarks domain" should only match "domain". +TEST_F(BookmarkProviderTest, KeywordModeExtractUserInput) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature(omnibox::kSiteSearchStarterPack); + + // Populate template URL with starter pack entries + std::vector<std::unique_ptr<TemplateURLData>> turls = + TemplateURLStarterPackData::GetStarterPackEngines(); + for (auto& turl : turls) { + provider_client_->GetTemplateURLService()->Add( + std::make_unique<TemplateURL>(std::move(*turl))); + } + // Test result for user text "domain", we should get back a result for domain. + AutocompleteInput input(u"domain", metrics::OmniboxEventProto::OTHER, + TestSchemeClassifier()); + provider_->Start(input, false); + + ACMatches matches = provider_->matches(); + ASSERT_GT(matches.size(), 0u); + EXPECT_EQ(u"domain", matches[0].description); + + // Test result for "@bookmarks" and "@bookmarks domain" while NOT in keyword + // mode, we should get a result for the @bookmarks bookmark and not for the + // domain bookmark since we're searching for the whole input text including + // "@bookmarks". + AutocompleteInput input2(u"@bookmarks", metrics::OmniboxEventProto::OTHER, + TestSchemeClassifier()); + provider_->Start(input2, false); + + matches = provider_->matches(); + ASSERT_GT(matches.size(), 0u); + EXPECT_EQ(u"@bookmarks", matches[0].description); + + AutocompleteInput input3(u"@bookmarks domain", + metrics::OmniboxEventProto::OTHER, + TestSchemeClassifier()); + provider_->Start(input3, false); + + matches = provider_->matches(); + ASSERT_EQ(matches.size(), 0u); + + // Turn on keyword mode, test result again, we should only get back the result + // for the domain bookmark since we're searching only for the user text after + // the keyword. + input3.set_prefer_keyword(true); + input3.set_keyword_mode_entry_method( + metrics::OmniboxEventProto_KeywordModeEntryMethod_TAB); + provider_->Start(input3, false); + + matches = provider_->matches(); + ASSERT_EQ(matches.size(), 1u); + EXPECT_EQ(u"domain", matches[0].description); +}
diff --git a/components/omnibox/browser/history_quick_provider_unittest.cc b/components/omnibox/browser/history_quick_provider_unittest.cc index 19ac1a3f..a18331ac 100644 --- a/components/omnibox/browser/history_quick_provider_unittest.cc +++ b/components/omnibox/browser/history_quick_provider_unittest.cc
@@ -938,9 +938,9 @@ ASSERT_GT(matches.size(), 0u); EXPECT_EQ(GURL("http://www.google.com/"), matches[0].destination_url); - // Test result for "@history google" while NOT in keyword mode, - // we should not get a result for google since the we're - // searching for the whole input text including "@history". + // Test result for "@history google" while NOT in keyword mode, we should not + // get a result for google since we're searching for the whole input text + // including "@history". AutocompleteInput input2(u"@history google", metrics::OmniboxEventProto::OTHER, TestSchemeClassifier());
diff --git a/components/omnibox/browser/history_url_provider_unittest.cc b/components/omnibox/browser/history_url_provider_unittest.cc index c14f956..b4fc5c7 100644 --- a/components/omnibox/browser/history_url_provider_unittest.cc +++ b/components/omnibox/browser/history_url_provider_unittest.cc
@@ -1439,7 +1439,7 @@ EXPECT_EQ(GURL("http://www.google.com/"), matches_[0].destination_url); // Test result for "@history" and "@history google" while NOT in keyword mode, - // we should get a result for history.com and not for google since the we're + // we should get a result for history.com and not for google since we're // searching for the whole input text including "@history". AutocompleteInput input2(u"@history", metrics::OmniboxEventProto::OTHER, TestSchemeClassifier());
diff --git a/components/omnibox/browser/most_visited_sites_provider_unittest.cc b/components/omnibox/browser/most_visited_sites_provider_unittest.cc index b652507..76d5d8e 100644 --- a/components/omnibox/browser/most_visited_sites_provider_unittest.cc +++ b/components/omnibox/browser/most_visited_sites_provider_unittest.cc
@@ -379,6 +379,7 @@ // Assume that top sites list has not been loaded yet from the DB. ASSERT_FALSE(top_sites_->loaded()); auto input = BuildAutocompleteInputForWebOnFocus(); + input.set_focus_type(OmniboxFocusType::DEFAULT); input.set_want_asynchronous_matches(false); controller_->Start(input); EXPECT_TRUE(provider_->done());
diff --git a/components/omnibox/browser/open_tab_provider.cc b/components/omnibox/browser/open_tab_provider.cc index fe9687b..594c65ad 100644 --- a/components/omnibox/browser/open_tab_provider.cc +++ b/components/omnibox/browser/open_tab_provider.cc
@@ -7,7 +7,9 @@ #include "base/i18n/case_conversion.h" #include "base/strings/string_split.h" #include "base/strings/utf_string_conversions.h" +#include "components/omnibox/browser/autocomplete_input.h" #include "components/omnibox/browser/autocomplete_match_classification.h" +#include "components/omnibox/browser/keyword_provider.h" #include "components/omnibox/browser/tab_matcher.h" #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) @@ -27,11 +29,17 @@ return; } + // Remove the keyword from input if we're in keyword mode for a starter pack + // engine. + AutocompleteInput adjusted_input = + KeywordProvider::AdjustInputForStarterPackEngines( + input, client_->GetTemplateURLService()); + #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) // Preprocess the query into lowercase terms. std::vector<std::u16string> query_terms; for (const std::u16string& term : - base::SplitString(base::i18n::ToLower(input.text()), u" ", + base::SplitString(base::i18n::ToLower(adjusted_input.text()), u" ", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY)) { query_terms.push_back(term); } @@ -47,7 +55,7 @@ for (const std::u16string& query_term : query_terms) { if (title.find(query_term) != std::string::npos) { matches_.push_back( - CreateOpenTabMatch(input, web_contents->GetTitle(), url)); + CreateOpenTabMatch(adjusted_input, web_contents->GetTitle(), url)); break; } }
diff --git a/components/page_load_metrics/browser/observers/ad_metrics/ads_page_load_metrics_observer_unittest.cc b/components/page_load_metrics/browser/observers/ad_metrics/ads_page_load_metrics_observer_unittest.cc index eec35cc9b..2600db8 100644 --- a/components/page_load_metrics/browser/observers/ad_metrics/ads_page_load_metrics_observer_unittest.cc +++ b/components/page_load_metrics/browser/observers/ad_metrics/ads_page_load_metrics_observer_unittest.cc
@@ -350,7 +350,7 @@ ~ErrorPageWaiter() override = default; // content::WebContentsObserver: - void DidFinishNavigation(content::NavigationHandle* handle) override { + void ReadyToCommitNavigation(content::NavigationHandle* handle) override { if (handle->GetNetErrorCode() != net::ERR_BLOCKED_BY_CLIENT) { is_error_page_ = false; return; @@ -2258,7 +2258,6 @@ base::test::ScopedFeatureList feature_list; feature_list.InitAndEnableFeature( heavy_ad_intervention::features::kHeavyAdIntervention); - RenderFrameHost* main_frame = NavigateMainFrame(kNonAdUrl); RenderFrameHost* ad_frame = CreateAndNavigateSubFrame(kAdUrl, main_frame);
diff --git a/components/payments/content/payment_request_state_unittest.cc b/components/payments/content/payment_request_state_unittest.cc index 77c3033..91e605b 100644 --- a/components/payments/content/payment_request_state_unittest.cc +++ b/components/payments/content/payment_request_state_unittest.cc
@@ -12,10 +12,8 @@ #include "base/memory/raw_ptr.h" #include "base/memory/weak_ptr.h" #include "base/strings/utf_string_conversions.h" -#include "base/test/scoped_feature_list.h" #include "components/autofill/core/browser/autofill_test_utils.h" #include "components/autofill/core/browser/data_model/autofill_profile.h" -#include "components/autofill/core/browser/data_model/credit_card.h" #include "components/autofill/core/browser/test_personal_data_manager.h" #include "components/payments/content/payment_app_factory.h" #include "components/payments/content/payment_app_service.h" @@ -24,7 +22,6 @@ #include "components/payments/content/test_content_payment_request_delegate.h" #include "components/payments/core/journey_logger.h" #include "content/public/browser/web_contents.h" -#include "content/public/common/content_features.h" #include "content/public/test/browser_task_environment.h" #include "content/public/test/test_browser_context.h" #include "content/public/test/test_web_contents_factory.h" @@ -99,25 +96,26 @@ const std::string method_; }; -class PaymentRequestStateTestBase : public testing::Test, - public PaymentRequestState::Observer, - public PaymentRequestState::Delegate { +class PaymentRequestStateTest : public testing::Test, + public PaymentRequestState::Observer, + public PaymentRequestState::Delegate { protected: - PaymentRequestStateTestBase() + static constexpr char kMethodName[] = "https://www.chromium.org"; + + PaymentRequestStateTest() : num_on_selected_information_changed_called_(0), test_payment_request_delegate_(/*task_executor=*/nullptr, &test_personal_data_manager_), journey_logger_(test_payment_request_delegate_.IsOffTheRecord(), ukm::UkmRecorder::GetNewSourceID()), address_(autofill::test::GetFullProfile()) { - // Must be initialized after scoped_feature_list_ (crbug.com/1172599) web_contents_ = web_contents_factory_.CreateWebContents(&context_); test_personal_data_manager_.SetAutofillProfileEnabled(true); test_personal_data_manager_.SetAutofillWalletImportEnabled(true); test_personal_data_manager_.AddProfile(address_); } - ~PaymentRequestStateTestBase() override = default; + ~PaymentRequestStateTest() override = default; // PaymentRequestState::Observer: void OnGetAllPaymentAppsFinished() override {} @@ -158,499 +156,6 @@ state_->AddObserver(this); } - // Convenience method that returns a dummy PaymentDetails with a single - // shipping option. - mojom::PaymentDetailsPtr CreateDefaultDetails() { - std::vector<mojom::PaymentShippingOptionPtr> shipping_options; - mojom::PaymentShippingOptionPtr option = - mojom::PaymentShippingOption::New(); - option->id = "option:1"; - shipping_options.push_back(std::move(option)); - mojom::PaymentDetailsPtr details = mojom::PaymentDetails::New(); - details->shipping_options = std::move(shipping_options); - details->id = "test_id"; - return details; - } - - PaymentRequestState* state() { return state_.get(); } - PaymentRequestSpec* spec() { return spec_.get(); } - const mojom::PaymentResponsePtr& response() { return payment_response_; } - const mojom::PaymentAddressPtr& selected_shipping_address() { - return selected_shipping_address_; - } - int num_on_selected_information_changed_called() { - return num_on_selected_information_changed_called_; - } - - autofill::AutofillProfile* test_address() { return &address_; } - TestContentPaymentRequestDelegate* test_payment_request_delegate() { - return &test_payment_request_delegate_; - } - - content::BrowserTaskEnvironment task_environment_; - content::TestBrowserContext context_; - content::TestWebContentsFactory web_contents_factory_; - raw_ptr<content::WebContents> - web_contents_; // Owned by `web_contents_factory_`. - std::unique_ptr<PaymentRequestState> state_; - std::unique_ptr<PaymentRequestSpec> spec_; - int num_on_selected_information_changed_called_; - mojom::PaymentResponsePtr payment_response_; - mojom::PaymentAddressPtr selected_shipping_address_; - autofill::TestPersonalDataManager test_personal_data_manager_; - TestContentPaymentRequestDelegate test_payment_request_delegate_; - JourneyLogger journey_logger_; - - // Test data. - autofill::AutofillProfile address_; - base::WeakPtrFactory<PaymentRequestStateTestBase> weak_ptr_factory_{this}; -}; - -class PaymentRequestStateTest : public PaymentRequestStateTestBase { - protected: - PaymentRequestStateTest() - : credit_card_visa_(autofill::test::GetCreditCard()) { - scoped_feature_list_.InitWithFeatures( - {::features::kPaymentRequestBasicCard}, - {features::kServiceWorkerPaymentApps}); - - // Must be initialized after scoped_feature_list_ (crbug.com/1172599) - web_contents_ = web_contents_factory_.CreateWebContents(&context_); - - test_personal_data_manager_.SetAutofillCreditCardEnabled(true); - credit_card_visa_.set_billing_address_id(address_.guid()); - credit_card_visa_.set_use_count(5u); - test_personal_data_manager_.AddCreditCard(credit_card_visa_); - } - ~PaymentRequestStateTest() override = default; - - // Convenience method to create a PaymentRequestState with default details - // (one shipping option) and method data (only supports visa). - void RecreateStateWithOptions(mojom::PaymentOptionsPtr options) { - RecreateState(std::move(options), CreateDefaultDetails(), - GetMethodDataForVisa(), - std::make_unique<PaymentAppService>(&context_)); - } - - // Convenience method that returns MethodData that supports Visa. - std::vector<mojom::PaymentMethodDataPtr> GetMethodDataForVisa() { - std::vector<mojom::PaymentMethodDataPtr> method_data; - mojom::PaymentMethodDataPtr entry = mojom::PaymentMethodData::New(); - entry->supported_method = "basic-card"; - entry->supported_networks.push_back(mojom::BasicCardNetwork::VISA); - method_data.push_back(std::move(entry)); - return method_data; - } - - private: - base::test::ScopedFeatureList scoped_feature_list_; - // Test data. - autofill::CreditCard credit_card_visa_; -}; - -TEST_F(PaymentRequestStateTest, CanMakePayment) { - // Default options. - RecreateStateWithOptions(mojom::PaymentOptions::New()); - - state()->HasEnrolledInstrument( - base::BindOnce([](bool has_enrolled_instrument) { - EXPECT_TRUE(has_enrolled_instrument); - })); - - // CanMakePayment returns true because the requested method is supported. - state()->CanMakePayment(base::BindOnce( - [](bool can_make_payment) { EXPECT_TRUE(can_make_payment); })); -} - -TEST_F(PaymentRequestStateTest, CanMakePayment_NoEnrolledInstrument) { - // The method data requires MasterCard. - std::vector<mojom::PaymentMethodDataPtr> method_data; - mojom::PaymentMethodDataPtr entry = mojom::PaymentMethodData::New(); - entry->supported_method = "basic-card"; - entry->supported_networks.push_back(mojom::BasicCardNetwork::MASTERCARD); - method_data.push_back(std::move(entry)); - RecreateState(mojom::PaymentOptions::New(), mojom::PaymentDetails::New(), - std::move(method_data), - std::make_unique<PaymentAppService>(&context_)); - - state()->HasEnrolledInstrument( - base::BindOnce([](bool has_enrolled_instrument) { - EXPECT_FALSE(has_enrolled_instrument); - })); - - // CanMakePayment returns true because the requested method is supported, even - // though the payment app is not ready to pay. - state()->CanMakePayment(base::BindOnce( - [](bool can_make_payment) { EXPECT_TRUE(can_make_payment); })); -} - -TEST_F(PaymentRequestStateTest, CanMakePayment_UnsupportedPaymentMethod) { - std::vector<mojom::PaymentMethodDataPtr> method_data; - mojom::PaymentMethodDataPtr entry = mojom::PaymentMethodData::New(); - entry->supported_method = "unsupported_method"; - method_data.push_back(std::move(entry)); - RecreateState(mojom::PaymentOptions::New(), mojom::PaymentDetails::New(), - std::move(method_data), - std::make_unique<PaymentAppService>(&context_)); - - state()->HasEnrolledInstrument( - base::BindOnce([](bool has_enrolled_instrument) { - EXPECT_FALSE(has_enrolled_instrument); - })); - - // CanMakePayment returns true because the requested method is supported, even - // though the payment app is not ready to pay. - state()->CanMakePayment(base::BindOnce( - [](bool can_make_payment) { EXPECT_FALSE(can_make_payment); })); -} - -TEST_F(PaymentRequestStateTest, CanMakePayment_OnlyBasicCard) { - // The method data supports everything in basic-card. - mojom::PaymentMethodDataPtr entry = mojom::PaymentMethodData::New(); - entry->supported_method = "basic-card"; - std::vector<mojom::PaymentMethodDataPtr> method_data; - method_data.push_back(std::move(entry)); - RecreateState(mojom::PaymentOptions::New(), mojom::PaymentDetails::New(), - std::move(method_data), - std::make_unique<PaymentAppService>(&context_)); - - state()->HasEnrolledInstrument( - base::BindOnce([](bool has_enrolled_instrument) { - EXPECT_TRUE(has_enrolled_instrument); - })); - - // CanMakePayment returns true because the requested method is supported. - state()->CanMakePayment(base::BindOnce( - [](bool can_make_payment) { EXPECT_TRUE(can_make_payment); })); -} - -TEST_F(PaymentRequestStateTest, CanMakePayment_BasicCard_SpecificAvailable) { - // The method data supports visa through basic-card. - mojom::PaymentMethodDataPtr entry = mojom::PaymentMethodData::New(); - entry->supported_method = "basic-card"; - entry->supported_networks.push_back(mojom::BasicCardNetwork::VISA); - std::vector<mojom::PaymentMethodDataPtr> method_data; - method_data.push_back(std::move(entry)); - RecreateState(mojom::PaymentOptions::New(), mojom::PaymentDetails::New(), - std::move(method_data), - std::make_unique<PaymentAppService>(&context_)); - - state()->HasEnrolledInstrument( - base::BindOnce([](bool has_enrolled_instrument) { - EXPECT_TRUE(has_enrolled_instrument); - })); - - // CanMakePayment returns true because the requested method is supported. - state()->CanMakePayment(base::BindOnce( - [](bool can_make_payment) { EXPECT_TRUE(can_make_payment); })); -} - -TEST_F(PaymentRequestStateTest, - CanMakePayment_BasicCard_SpecificAvailableButInvalid) { - // The method data supports jcb through basic-card. - mojom::PaymentMethodDataPtr entry = mojom::PaymentMethodData::New(); - entry->supported_method = "basic-card"; - entry->supported_networks.push_back(mojom::BasicCardNetwork::JCB); - std::vector<mojom::PaymentMethodDataPtr> method_data; - method_data.push_back(std::move(entry)); - RecreateState(mojom::PaymentOptions::New(), mojom::PaymentDetails::New(), - std::move(method_data), - std::make_unique<PaymentAppService>(&context_)); - - state()->HasEnrolledInstrument( - base::BindOnce([](bool has_enrolled_instrument) { - EXPECT_FALSE(has_enrolled_instrument); - })); - - // CanMakePayment returns true because the requested method is supported, even - // though there is no enrolled instrument. - state()->CanMakePayment(base::BindOnce( - [](bool can_make_payment) { EXPECT_TRUE(can_make_payment); })); -} - -TEST_F(PaymentRequestStateTest, CanMakePayment_BasicCard_SpecificUnavailable) { - // The method data supports mastercard through basic-card. - mojom::PaymentMethodDataPtr entry = mojom::PaymentMethodData::New(); - entry->supported_method = "basic-card"; - entry->supported_networks.push_back(mojom::BasicCardNetwork::MASTERCARD); - std::vector<mojom::PaymentMethodDataPtr> method_data; - method_data.push_back(std::move(entry)); - RecreateState(mojom::PaymentOptions::New(), mojom::PaymentDetails::New(), - std::move(method_data), - std::make_unique<PaymentAppService>(&context_)); - - state()->HasEnrolledInstrument( - base::BindOnce([](bool has_enrolled_instrument) { - EXPECT_FALSE(has_enrolled_instrument); - })); - - // CanMakePayment returns true because the requested method is supported, even - // though there is no enrolled instrument. - state()->CanMakePayment(base::BindOnce( - [](bool can_make_payment) { EXPECT_TRUE(can_make_payment); })); -} - -TEST_F(PaymentRequestStateTest, ReadyToPay_DefaultSelections) { - mojom::PaymentOptionsPtr options = mojom::PaymentOptions::New(); - options->request_shipping = true; - options->request_payer_name = true; - options->request_payer_phone = true; - options->request_payer_email = true; - RecreateStateWithOptions(std::move(options)); - - // Because there are shipping options, no address is selected by default. - // Therefore we are not ready to pay. - EXPECT_FALSE(state()->is_ready_to_pay()); - - state()->SetSelectedShippingProfile(test_address()); - EXPECT_EQ(0, num_on_selected_information_changed_called()); - - // Simulate that the merchant has validated the shipping address change. - spec()->UpdateWith(CreateDefaultDetails()); - EXPECT_EQ(1, num_on_selected_information_changed_called()); - - // Not ready to pay since there's no selected shipping option. - EXPECT_FALSE(state()->is_ready_to_pay()); - - // Simulate that the website validates the shipping option. - state()->SetSelectedShippingOption("option:1"); - auto details = CreateDefaultDetails(); - (*details->shipping_options)[0]->selected = true; - spec()->UpdateWith(std::move(details)); - EXPECT_EQ(2, num_on_selected_information_changed_called()); - EXPECT_TRUE(state()->is_ready_to_pay()); -} - -// Testing that only supported instruments are shown. In this test the merchant -// only supports Visa. -TEST_F(PaymentRequestStateTest, UnsupportedCardAreNotAvailable) { - // Default options. - RecreateStateWithOptions(mojom::PaymentOptions::New()); - - // Ready to pay because the default app is selected and supported. - EXPECT_TRUE(state()->is_ready_to_pay()); - - // There's only one app available, even though there's an Amex in - // PersonalDataManager. - EXPECT_EQ(1u, state()->available_apps().size()); -} - -// Test selecting a contact info profile will make the user ready to pay. -TEST_F(PaymentRequestStateTest, ReadyToPay_ContactInfo) { - mojom::PaymentOptionsPtr options = mojom::PaymentOptions::New(); - options->request_payer_name = true; - options->request_payer_phone = true; - options->request_payer_email = true; - RecreateStateWithOptions(std::move(options)); - - // Ready to pay because of default selections. - EXPECT_TRUE(state()->is_ready_to_pay()); - - // Unselecting contact profile. - state()->SetSelectedContactProfile(/*profile=*/nullptr); - EXPECT_EQ(1, num_on_selected_information_changed_called()); - - EXPECT_FALSE(state()->is_ready_to_pay()); - - state()->SetSelectedContactProfile(test_address()); - EXPECT_EQ(2, num_on_selected_information_changed_called()); - - // Ready to pay! - EXPECT_TRUE(state()->is_ready_to_pay()); -} - -TEST_F(PaymentRequestStateTest, SelectedShippingAddressMessage_Normalized) { - mojom::PaymentOptionsPtr options = mojom::PaymentOptions::New(); - options->request_shipping = true; - RecreateStateWithOptions(std::move(options)); - - // Make the normalization not be instantaneous. - test_payment_request_delegate() - ->test_address_normalizer() - ->DelayNormalization(); - - EXPECT_EQ(0, num_on_selected_information_changed_called()); - - // Select an address, nothing should happen until the normalization is - // completed and the merchant has validated the address. - state()->SetSelectedShippingProfile(test_address()); - EXPECT_EQ(0, num_on_selected_information_changed_called()); - EXPECT_FALSE(state()->is_ready_to_pay()); - - // Complete the normalization. - test_payment_request_delegate() - ->test_address_normalizer() - ->CompleteAddressNormalization(); - EXPECT_EQ(0, num_on_selected_information_changed_called()); - EXPECT_FALSE(state()->is_ready_to_pay()); - - // Simulate that the merchant has validated the shipping address change. - spec()->UpdateWith(CreateDefaultDetails()); - EXPECT_EQ(1, num_on_selected_information_changed_called()); - // Not ready to pay because there's no selected shipping option. - EXPECT_FALSE(state()->is_ready_to_pay()); - - // Check that all the expected values were set for the shipping address. - EXPECT_EQ("US", selected_shipping_address()->country); - EXPECT_EQ("666 Erebus St.", selected_shipping_address()->address_line[0]); - EXPECT_EQ("Apt 8", selected_shipping_address()->address_line[1]); - EXPECT_EQ("CA", selected_shipping_address()->region); - EXPECT_EQ("Elysium", selected_shipping_address()->city); - EXPECT_EQ("", selected_shipping_address()->dependent_locality); - EXPECT_EQ("91111", selected_shipping_address()->postal_code); - EXPECT_EQ("", selected_shipping_address()->sorting_code); - EXPECT_EQ("Underworld", selected_shipping_address()->organization); - EXPECT_EQ("John H. Doe", selected_shipping_address()->recipient); - EXPECT_EQ("16502111111", selected_shipping_address()->phone); -} - -TEST_F(PaymentRequestStateTest, JaLatnShippingAddress) { - mojom::PaymentOptionsPtr options = mojom::PaymentOptions::New(); - options->request_shipping = true; - RecreateStateWithOptions(std::move(options)); - - // Make the normalization not be instantaneous. - test_payment_request_delegate() - ->test_address_normalizer() - ->DelayNormalization(); - - EXPECT_EQ(0, num_on_selected_information_changed_called()); - - // Select an address, nothing should happen until the normalization is - // completed and the merchant has validated the address. - autofill::AutofillProfile profile(base::GenerateGUID(), - "https://example.com"); - autofill::test::SetProfileInfo(&profile, "Jon", "V.", "Doe", - "jon.doe@exampl.com", "Example Inc", - "Roppongi", "6 Chrome-10-1", "Tokyo", "", - "106-6126", "JP", "+81363849000"); - - state()->SetSelectedShippingProfile(&profile); - EXPECT_EQ(0, num_on_selected_information_changed_called()); - EXPECT_FALSE(state()->is_ready_to_pay()); - - // Complete the normalization. - test_payment_request_delegate() - ->test_address_normalizer() - ->CompleteAddressNormalization(); - EXPECT_EQ(0, num_on_selected_information_changed_called()); - EXPECT_FALSE(state()->is_ready_to_pay()); - - // Simulate that the merchant has validated the shipping address change. - spec()->UpdateWith(CreateDefaultDetails()); - EXPECT_EQ(1, num_on_selected_information_changed_called()); - // Not ready to pay because there's no selected shipping option. - EXPECT_FALSE(state()->is_ready_to_pay()); - - // Check that all the expected values were set for the shipping address. - EXPECT_EQ("JP", selected_shipping_address()->country); - EXPECT_EQ("Roppongi", selected_shipping_address()->address_line[0]); - EXPECT_EQ("6 Chrome-10-1", selected_shipping_address()->address_line[1]); - EXPECT_EQ("", selected_shipping_address()->region); - EXPECT_EQ("Tokyo", selected_shipping_address()->city); - EXPECT_EQ("", selected_shipping_address()->dependent_locality); - EXPECT_EQ("106-6126", selected_shipping_address()->postal_code); - EXPECT_EQ("", selected_shipping_address()->sorting_code); - EXPECT_EQ("Example Inc", selected_shipping_address()->organization); - EXPECT_EQ("Jon V. Doe", selected_shipping_address()->recipient); - EXPECT_EQ("+81363849000", selected_shipping_address()->phone); -} - -TEST_F(PaymentRequestStateTest, RetryWithShippingAddressErrors) { - mojom::PaymentOptionsPtr options = mojom::PaymentOptions::New(); - options->request_shipping = true; - RecreateStateWithOptions(std::move(options)); - - // Because there are shipping options, no address is selected by default. - // Therefore we are not ready to pay. - EXPECT_FALSE(state()->is_ready_to_pay()); - - state()->SetSelectedShippingProfile(test_address()); - EXPECT_EQ(0, num_on_selected_information_changed_called()); - - // Simulate that the merchant has validated the shipping address change. - spec()->UpdateWith(CreateDefaultDetails()); - EXPECT_EQ(1, num_on_selected_information_changed_called()); - - // Not ready to pay since there's no selected shipping option. - EXPECT_FALSE(state()->is_ready_to_pay()); - - // Simulate that the website validates the shipping option. - state()->SetSelectedShippingOption("option:1"); - auto details = CreateDefaultDetails(); - (*details->shipping_options)[0]->selected = true; - spec()->UpdateWith(std::move(details)); - EXPECT_EQ(2, num_on_selected_information_changed_called()); - EXPECT_TRUE(state()->is_ready_to_pay()); - - EXPECT_TRUE(state()->selected_shipping_profile()); - EXPECT_FALSE(state()->invalid_shipping_profile()); - - mojom::AddressErrorsPtr shipping_address_errors = mojom::AddressErrors::New(); - shipping_address_errors->address_line = "Invalid address line"; - shipping_address_errors->city = "Invalid city"; - - mojom::PaymentValidationErrorsPtr errors = - mojom::PaymentValidationErrors::New(); - errors->shipping_address = std::move(shipping_address_errors); - spec()->Retry(std::move(errors)); - EXPECT_EQ(3, num_on_selected_information_changed_called()); - EXPECT_FALSE(state()->is_ready_to_pay()); - - EXPECT_FALSE(state()->selected_shipping_profile()); - EXPECT_TRUE(state()->invalid_shipping_profile()); -} - -TEST_F(PaymentRequestStateTest, RetryWithPayerErrors) { - mojom::PaymentOptionsPtr options = mojom::PaymentOptions::New(); - options->request_payer_name = true; - options->request_payer_phone = true; - options->request_payer_email = true; - RecreateStateWithOptions(std::move(options)); - - state()->SetSelectedContactProfile(test_address()); - EXPECT_EQ(1, num_on_selected_information_changed_called()); - EXPECT_TRUE(state()->is_ready_to_pay()); - - EXPECT_TRUE(state()->selected_contact_profile()); - EXPECT_FALSE(state()->invalid_contact_profile()); - - mojom::PayerErrorsPtr payer_errors = mojom::PayerErrors::New(); - payer_errors->email = "Invalid email"; - payer_errors->name = "Invalid name"; - payer_errors->phone = "Invalid phone"; - - mojom::PaymentValidationErrorsPtr errors = - mojom::PaymentValidationErrors::New(); - errors->payer = std::move(payer_errors); - spec()->Retry(std::move(errors)); - EXPECT_EQ(2, num_on_selected_information_changed_called()); - EXPECT_FALSE(state()->is_ready_to_pay()); - - EXPECT_FALSE(state()->selected_contact_profile()); - EXPECT_TRUE(state()->invalid_contact_profile()); -} - -// The tests in this class correspond to the tests of the same name in -// PaymentRequestStateTest, with the basic-card being disabled. Parameterized -// tests are not used because the test setup for both tests are too different. -class PaymentRequestStateBasicCardDisabledTest - : public PaymentRequestStateTestBase { - protected: - static constexpr char kMethodName[] = "https://www.chromium.org"; - - PaymentRequestStateBasicCardDisabledTest() { - scoped_feature_list_.InitAndDisableFeature( - ::features::kPaymentRequestBasicCard); - // Must be initialized after scoped_feature_list_ (crbug.com/1172599) - web_contents_ = web_contents_factory_.CreateWebContents(&context_); - - test_personal_data_manager_.SetAutofillProfileEnabled(true); - test_personal_data_manager_.SetAutofillWalletImportEnabled(true); - test_personal_data_manager_.AddProfile(address_); - } - ~PaymentRequestStateBasicCardDisabledTest() override = default; - // Convenience method to create a PaymentRequestState with default details // (one shipping option) and method data (only supports a url method). void RecreateStateWithOptions(mojom::PaymentOptionsPtr options) { @@ -683,10 +188,56 @@ return method_data; } + // Convenience method that returns a dummy PaymentDetails with a single + // shipping option. + mojom::PaymentDetailsPtr CreateDefaultDetails() { + std::vector<mojom::PaymentShippingOptionPtr> shipping_options; + mojom::PaymentShippingOptionPtr option = + mojom::PaymentShippingOption::New(); + option->id = "option:1"; + shipping_options.push_back(std::move(option)); + mojom::PaymentDetailsPtr details = mojom::PaymentDetails::New(); + details->shipping_options = std::move(shipping_options); + details->id = "test_id"; + return details; + } + + PaymentRequestState* state() { return state_.get(); } + PaymentRequestSpec* spec() { return spec_.get(); } + const mojom::PaymentResponsePtr& response() { return payment_response_; } + const mojom::PaymentAddressPtr& selected_shipping_address() { + return selected_shipping_address_; + } + int num_on_selected_information_changed_called() { + return num_on_selected_information_changed_called_; + } + + autofill::AutofillProfile* test_address() { return &address_; } + TestContentPaymentRequestDelegate* test_payment_request_delegate() { + return &test_payment_request_delegate_; + } + const std::string& installed_app_method() const { return installed_app_method_; } + content::BrowserTaskEnvironment task_environment_; + content::TestBrowserContext context_; + content::TestWebContentsFactory web_contents_factory_; + raw_ptr<content::WebContents> + web_contents_; // Owned by `web_contents_factory_`. + std::unique_ptr<PaymentRequestState> state_; + std::unique_ptr<PaymentRequestSpec> spec_; + int num_on_selected_information_changed_called_; + mojom::PaymentResponsePtr payment_response_; + mojom::PaymentAddressPtr selected_shipping_address_; + autofill::TestPersonalDataManager test_personal_data_manager_; + TestContentPaymentRequestDelegate test_payment_request_delegate_; + JourneyLogger journey_logger_; + + // Test data. + autofill::AutofillProfile address_; + private: static void OnMethodSupportResult(base::RepeatingClosure quit_closure, bool methods_supported, @@ -695,11 +246,11 @@ quit_closure.Run(); } - base::test::ScopedFeatureList scoped_feature_list_; const std::string installed_app_method_ = kMethodName; + base::WeakPtrFactory<PaymentRequestStateTest> weak_ptr_factory_{this}; }; -TEST_F(PaymentRequestStateBasicCardDisabledTest, CanMakePayment) { +TEST_F(PaymentRequestStateTest, CanMakePayment) { // Default options. RecreateStateWithOptions(mojom::PaymentOptions::New()); @@ -713,8 +264,7 @@ [](bool can_make_payment) { EXPECT_TRUE(can_make_payment); })); } -TEST_F(PaymentRequestStateBasicCardDisabledTest, - CanMakePayment_NoEnrolledInstrument) { +TEST_F(PaymentRequestStateTest, CanMakePayment_NoEnrolledInstrument) { std::vector<mojom::PaymentMethodDataPtr> method_data; mojom::PaymentMethodDataPtr entry = mojom::PaymentMethodData::New(); entry->supported_method = installed_app_method(); @@ -736,8 +286,7 @@ [](bool can_make_payment) { EXPECT_TRUE(can_make_payment); })); } -TEST_F(PaymentRequestStateBasicCardDisabledTest, - CanMakePayment_UnsupportedPaymentMethod) { +TEST_F(PaymentRequestStateTest, CanMakePayment_UnsupportedPaymentMethod) { std::vector<mojom::PaymentMethodDataPtr> method_data; mojom::PaymentMethodDataPtr entry = mojom::PaymentMethodData::New(); entry->supported_method = "unsupported_method"; @@ -758,7 +307,7 @@ } // Test selecting a contact info profile will make the user ready to pay. -TEST_F(PaymentRequestStateBasicCardDisabledTest, ReadyToPay_ContactInfo) { +TEST_F(PaymentRequestStateTest, ReadyToPay_ContactInfo) { mojom::PaymentOptionsPtr options = mojom::PaymentOptions::New(); options->request_payer_name = true; options->request_payer_phone = true; @@ -783,7 +332,7 @@ EXPECT_TRUE(state()->is_ready_to_pay()); } -TEST_F(PaymentRequestStateBasicCardDisabledTest, ReadyToPay_DefaultSelections) { +TEST_F(PaymentRequestStateTest, ReadyToPay_DefaultSelections) { mojom::PaymentOptionsPtr options = mojom::PaymentOptions::New(); options->request_shipping = true; options->request_payer_name = true; @@ -816,7 +365,7 @@ EXPECT_TRUE(state()->is_ready_to_pay()); } -TEST_F(PaymentRequestStateBasicCardDisabledTest, RetryWithPayerErrors) { +TEST_F(PaymentRequestStateTest, RetryWithPayerErrors) { mojom::PaymentOptionsPtr options = mojom::PaymentOptions::New(); options->request_payer_name = true; options->request_payer_phone = true; @@ -848,8 +397,7 @@ EXPECT_TRUE(state()->invalid_contact_profile()); } -TEST_F(PaymentRequestStateBasicCardDisabledTest, - RetryWithShippingAddressErrors) { +TEST_F(PaymentRequestStateTest, RetryWithShippingAddressErrors) { mojom::PaymentOptionsPtr options = mojom::PaymentOptions::New(); options->request_shipping = true; RecreateStateWithOptions(std::move(options)); @@ -898,7 +446,7 @@ // Testing that only supported instruments are shown. In this test the merchant // requests https://payments.example payment method, which is not supported. -TEST_F(PaymentRequestStateBasicCardDisabledTest, UnsupportedMethod) { +TEST_F(PaymentRequestStateTest, UnsupportedMethod) { RecreateStateWithRequestedMethodAndOptions( /*requested_method=*/"https://payments.example", mojom::PaymentOptions::New()); @@ -906,5 +454,104 @@ EXPECT_EQ(0u, state()->available_apps().size()); } +TEST_F(PaymentRequestStateTest, SelectedShippingAddressMessage_Normalized) { + mojom::PaymentOptionsPtr options = mojom::PaymentOptions::New(); + options->request_shipping = true; + RecreateStateWithOptions(std::move(options)); + + // Make the normalization not be instantaneous. + test_payment_request_delegate() + ->test_address_normalizer() + ->DelayNormalization(); + + int expected_changes = 2; + EXPECT_EQ(expected_changes, num_on_selected_information_changed_called()); + + // Select an address, nothing should happen until the normalization is + // completed and the merchant has validated the address. + state()->SetSelectedShippingProfile(test_address()); + EXPECT_EQ(expected_changes, num_on_selected_information_changed_called()); + EXPECT_FALSE(state()->is_ready_to_pay()); + + // Complete the normalization. + test_payment_request_delegate() + ->test_address_normalizer() + ->CompleteAddressNormalization(); + EXPECT_EQ(expected_changes, num_on_selected_information_changed_called()); + EXPECT_FALSE(state()->is_ready_to_pay()); + + // Simulate that the merchant has validated the shipping address change. + spec()->UpdateWith(CreateDefaultDetails()); + EXPECT_EQ(++expected_changes, num_on_selected_information_changed_called()); + // Not ready to pay because there's no selected shipping option. + EXPECT_FALSE(state()->is_ready_to_pay()); + + // Check that all the expected values were set for the shipping address. + EXPECT_EQ("US", selected_shipping_address()->country); + EXPECT_EQ("666 Erebus St.", selected_shipping_address()->address_line[0]); + EXPECT_EQ("Apt 8", selected_shipping_address()->address_line[1]); + EXPECT_EQ("CA", selected_shipping_address()->region); + EXPECT_EQ("Elysium", selected_shipping_address()->city); + EXPECT_EQ("", selected_shipping_address()->dependent_locality); + EXPECT_EQ("91111", selected_shipping_address()->postal_code); + EXPECT_EQ("", selected_shipping_address()->sorting_code); + EXPECT_EQ("Underworld", selected_shipping_address()->organization); + EXPECT_EQ("John H. Doe", selected_shipping_address()->recipient); + EXPECT_EQ("16502111111", selected_shipping_address()->phone); +} + +TEST_F(PaymentRequestStateTest, JaLatnShippingAddress) { + mojom::PaymentOptionsPtr options = mojom::PaymentOptions::New(); + options->request_shipping = true; + RecreateStateWithOptions(std::move(options)); + int expected_changes = 2; + + // Make the normalization not be instantaneous. + test_payment_request_delegate() + ->test_address_normalizer() + ->DelayNormalization(); + + EXPECT_EQ(expected_changes, num_on_selected_information_changed_called()); + + // Select an address, nothing should happen until the normalization is + // completed and the merchant has validated the address. + autofill::AutofillProfile profile(base::GenerateGUID(), + "https://example.com"); + autofill::test::SetProfileInfo(&profile, "Jon", "V.", "Doe", + "jon.doe@exampl.com", "Example Inc", + "Roppongi", "6 Chrome-10-1", "Tokyo", "", + "106-6126", "JP", "+81363849000"); + + state()->SetSelectedShippingProfile(&profile); + EXPECT_EQ(expected_changes, num_on_selected_information_changed_called()); + EXPECT_FALSE(state()->is_ready_to_pay()); + + // Complete the normalization. + test_payment_request_delegate() + ->test_address_normalizer() + ->CompleteAddressNormalization(); + EXPECT_EQ(expected_changes, num_on_selected_information_changed_called()); + EXPECT_FALSE(state()->is_ready_to_pay()); + + // Simulate that the merchant has validated the shipping address change. + spec()->UpdateWith(CreateDefaultDetails()); + EXPECT_EQ(++expected_changes, num_on_selected_information_changed_called()); + // Not ready to pay because there's no selected shipping option. + EXPECT_FALSE(state()->is_ready_to_pay()); + + // Check that all the expected values were set for the shipping address. + EXPECT_EQ("JP", selected_shipping_address()->country); + EXPECT_EQ("Roppongi", selected_shipping_address()->address_line[0]); + EXPECT_EQ("6 Chrome-10-1", selected_shipping_address()->address_line[1]); + EXPECT_EQ("", selected_shipping_address()->region); + EXPECT_EQ("Tokyo", selected_shipping_address()->city); + EXPECT_EQ("", selected_shipping_address()->dependent_locality); + EXPECT_EQ("106-6126", selected_shipping_address()->postal_code); + EXPECT_EQ("", selected_shipping_address()->sorting_code); + EXPECT_EQ("Example Inc", selected_shipping_address()->organization); + EXPECT_EQ("Jon V. Doe", selected_shipping_address()->recipient); + EXPECT_EQ("+81363849000", selected_shipping_address()->phone); +} + } // namespace } // namespace payments
diff --git a/components/printing/browser/print_to_pdf/pdf_print_utils.cc b/components/printing/browser/print_to_pdf/pdf_print_utils.cc index cf6a92c..98bcdad 100644 --- a/components/printing/browser/print_to_pdf/pdf_print_utils.cc +++ b/components/printing/browser/print_to_pdf/pdf_print_utils.cc
@@ -4,6 +4,7 @@ #include "components/printing/browser/print_to_pdf/pdf_print_utils.h" +#include "base/numerics/safe_conversions.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_split.h" #include "base/strings/string_util.h" @@ -11,6 +12,9 @@ #include "components/printing/browser/print_manager_utils.h" #include "printing/print_settings.h" #include "printing/units.h" +#include "ui/gfx/geometry/size.h" +#include "ui/gfx/geometry/size_conversions.h" +#include "ui/gfx/geometry/size_f.h" #include "url/url_canon.h" namespace print_to_pdf { @@ -129,10 +133,14 @@ return "bottom margin is negative"; printing::PageMargins margins_in_points; - margins_in_points.left = margin_left_in_inches * printing::kPointsPerInch; - margins_in_points.right = margin_right_in_inches * printing::kPointsPerInch; - margins_in_points.top = margin_top_in_inches * printing::kPointsPerInch; - margins_in_points.bottom = margin_bottom_in_inches * printing::kPointsPerInch; + margins_in_points.left = + base::ClampFloor(margin_left_in_inches * printing::kPointsPerInch); + margins_in_points.right = + base::ClampFloor(margin_right_in_inches * printing::kPointsPerInch); + margins_in_points.top = + base::ClampFloor(margin_top_in_inches * printing::kPointsPerInch); + margins_in_points.bottom = + base::ClampFloor(margin_bottom_in_inches * printing::kPointsPerInch); print_settings.SetCustomMargins(margins_in_points); double paper_width_in_inches = @@ -145,9 +153,9 @@ if (paper_height_in_inches <= 0) return "paper height is zero or negative"; - gfx::Size paper_size_in_points( - paper_width_in_inches * printing::kPointsPerInch, - paper_height_in_inches * printing::kPointsPerInch); + gfx::Size paper_size_in_points = gfx::ToRoundedSize( + gfx::SizeF(paper_width_in_inches * printing::kPointsPerInch, + paper_height_in_inches * printing::kPointsPerInch)); gfx::Rect printable_area_device_units(paper_size_in_points); print_settings.SetPrinterPrintableArea(paper_size_in_points, printable_area_device_units, true);
diff --git a/components/safe_browsing/content/common/proto/PRESUBMIT.py b/components/safe_browsing/content/common/proto/PRESUBMIT.py new file mode 100644 index 0000000..249f58bf --- /dev/null +++ b/components/safe_browsing/content/common/proto/PRESUBMIT.py
@@ -0,0 +1,19 @@ +# Copyright 2022 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +USE_PYTHON3 = True + + +def CheckChangeOnUpload(input_api, output_api): + results = [] + + proto_path = 'components/safe_browsing/content/common/proto/download_file_types.proto' + + if proto_path in input_api.change.LocalPaths(): + results.append( + output_api.PresubmitPromptWarning( + 'You modified one or more of the download file type protos ' + 'in: \n ' + proto_path + '\n' + 'Please ensure this change is backwards compatible.')) + return results
diff --git a/components/translate/core/browser/translate_infobar_delegate_unittest.cc b/components/translate/core/browser/translate_infobar_delegate_unittest.cc index f386fcc1..a73724e 100644 --- a/components/translate/core/browser/translate_infobar_delegate_unittest.cc +++ b/components/translate/core/browser/translate_infobar_delegate_unittest.cc
@@ -222,15 +222,14 @@ TEST_F(TranslateInfoBarDelegateTest, ShouldAutoAlwaysTranslate) { DictionaryPrefUpdate update_translate_accepted_count( pref_service_.get(), TranslatePrefs::kPrefTranslateAcceptedCount); - base::Value* update_translate_accepted_dict = - update_translate_accepted_count.Get(); - update_translate_accepted_dict->SetIntKey(kSourceLanguage, - kAutoAlwaysThreshold + 1); + base::Value::Dict& update_translate_accepted_dict = + update_translate_accepted_count->GetDict(); + update_translate_accepted_dict.Set(kSourceLanguage, kAutoAlwaysThreshold + 1); - const base::Value* dict = pref_service_->GetDictionary( + const base::Value::Dict* dict = &pref_service_->GetValueDict( TranslatePrefs::kPrefTranslateAutoAlwaysCount); absl::optional<int> translate_auto_always_count = - dict->FindIntKey(kSourceLanguage); + dict->FindInt(kSourceLanguage); EXPECT_FALSE(translate_auto_always_count.has_value()); TranslateInfoBarDelegate::Create( @@ -244,28 +243,28 @@ EXPECT_TRUE(delegate->ShouldAutoAlwaysTranslate()); absl::optional<int> count = - update_translate_accepted_dict->FindIntKey(kSourceLanguage); + update_translate_accepted_dict.FindInt(kSourceLanguage); EXPECT_EQ(absl::optional<int>(0), count); // Get the dictionary again in order to update it. - dict = pref_service_->GetDictionary( + dict = &pref_service_->GetValueDict( TranslatePrefs::kPrefTranslateAutoAlwaysCount); - translate_auto_always_count = dict->FindIntKey(kSourceLanguage); + translate_auto_always_count = dict->FindInt(kSourceLanguage); EXPECT_EQ(absl::optional<int>(1), translate_auto_always_count); } TEST_F(TranslateInfoBarDelegateTest, ShouldNotAutoAlwaysTranslateUnknown) { DictionaryPrefUpdate update_translate_accepted_count( pref_service_.get(), TranslatePrefs::kPrefTranslateAcceptedCount); - base::Value* update_translate_accepted_dict = - update_translate_accepted_count.Get(); + base::Value::Dict& update_translate_accepted_dict = + update_translate_accepted_count->GetDict(); // Should not trigger auto always translate for unknown source language. - update_translate_accepted_dict->SetIntKey(kUnknownLanguageCode, - kAutoAlwaysThreshold + 1); + update_translate_accepted_dict.Set(kUnknownLanguageCode, + kAutoAlwaysThreshold + 1); - const base::Value* dict = pref_service_->GetDictionary( + const base::Value::Dict* dict = &pref_service_->GetValueDict( TranslatePrefs::kPrefTranslateAutoAlwaysCount); absl::optional<int> translate_auto_always_count = - dict->FindIntKey(kUnknownLanguageCode); + dict->FindInt(kUnknownLanguageCode); EXPECT_FALSE(translate_auto_always_count.has_value()); TranslateInfoBarDelegate::Create( @@ -279,13 +278,13 @@ EXPECT_FALSE(delegate->ShouldAutoAlwaysTranslate()); absl::optional<int> count = - update_translate_accepted_dict->FindIntKey(kSourceLanguage); + update_translate_accepted_dict.FindInt(kSourceLanguage); // Always translate not triggered, so count should be unchanged. EXPECT_FALSE(count.has_value()); // Get the dictionary again in order to update it. - dict = pref_service_->GetDictionary( + dict = &pref_service_->GetValueDict( TranslatePrefs::kPrefTranslateAutoAlwaysCount); - translate_auto_always_count = dict->FindIntKey(kUnknownLanguageCode); + translate_auto_always_count = dict->FindInt(kUnknownLanguageCode); EXPECT_FALSE(translate_auto_always_count.has_value()); } @@ -312,15 +311,15 @@ DictionaryPrefUpdate update_translate_denied_count( pref_service_.get(), TranslatePrefs::kPrefTranslateDeniedCount); - base::Value* update_translate_denied_dict = - update_translate_denied_count.Get(); + base::Value::Dict& update_translate_denied_dict = + update_translate_denied_count->GetDict(); // 21 = kAutoNeverThreshold + 1 - update_translate_denied_dict->SetIntKey(kSourceLanguage, 21); + update_translate_denied_dict.Set(kSourceLanguage, 21); - const base::Value* dict = pref_service_->GetDictionary( + const base::Value::Dict* dict = &pref_service_->GetValueDict( TranslatePrefs::kPrefTranslateAutoNeverCount); absl::optional<int> translate_auto_never_count = - dict->FindIntKey(kSourceLanguage); + dict->FindInt(kSourceLanguage); ASSERT_FALSE(translate_auto_never_count.has_value()); TranslateInfoBarDelegate::Create( @@ -334,12 +333,12 @@ EXPECT_TRUE(delegate->ShouldAutoNeverTranslate()); absl::optional<int> count = - update_translate_denied_dict->FindIntKey(kSourceLanguage); + update_translate_denied_dict.FindInt(kSourceLanguage); EXPECT_EQ(absl::optional<int>(0), count); // Get the dictionary again in order to update it. - dict = pref_service_->GetDictionary( + dict = &pref_service_->GetValueDict( TranslatePrefs::kPrefTranslateAutoNeverCount); - translate_auto_never_count = dict->FindIntKey(kSourceLanguage); + translate_auto_never_count = dict->FindInt(kSourceLanguage); ASSERT_EQ(absl::optional<int>(1), translate_auto_never_count); }
diff --git a/components/translate/core/browser/translate_prefs.cc b/components/translate/core/browser/translate_prefs.cc index 3fa7ac4..048b9f94 100644 --- a/components/translate/core/browser/translate_prefs.cc +++ b/components/translate/core/browser/translate_prefs.cc
@@ -86,25 +86,25 @@ // pref. This function will avoid merging values from the old pref that seem to // conflict with values already present in the new pref. void MigrateObsoleteAlwaysTranslateLanguagesPref(PrefService* prefs) { - const base::Value* deprecated_dictionary = prefs->GetUserPrefValue( - TranslatePrefs::kPrefAlwaysTranslateListDeprecated); + const base::Value::Dict& deprecated_dictionary = + prefs->GetValueDict(TranslatePrefs::kPrefAlwaysTranslateListDeprecated); // Migration is performed only once per client, since the deprecated pref is // cleared after migration. This will make subsequent calls to migrate no-ops. - if (!deprecated_dictionary) + if (deprecated_dictionary.empty()) return; DictionaryPrefUpdate always_translate_dictionary_update( prefs, prefs::kPrefAlwaysTranslateList); - base::Value* always_translate_dictionary = - always_translate_dictionary_update.Get(); + base::Value::Dict& always_translate_dictionary = + always_translate_dictionary_update->GetDict(); - for (const auto old_language_pair : deprecated_dictionary->DictItems()) { + for (const auto old_language_pair : deprecated_dictionary) { // If the old pref's language pair conflicts with any of the new pref's // language pairs, where either the new pref already specifies behavior // about always translating from or to the old source language, or always // translating from the old target language, then skip merging this pair // into the new pref. - const auto& new_language_pairs = always_translate_dictionary->DictItems(); + const auto& new_language_pairs = always_translate_dictionary; if (std::any_of(new_language_pairs.begin(), new_language_pairs.end(), [&old_language_pair](const auto& new_language_pair) { return old_language_pair.first == @@ -121,7 +121,7 @@ // languages, it probably means that this source language was set to never // be translated after the old pref was deprecated, so avoid this conflict. const auto& never_translate_languages = - prefs->GetList(prefs::kBlockedLanguages)->GetListDeprecated(); + prefs->GetValueList(prefs::kBlockedLanguages); if (std::any_of( never_translate_languages.begin(), never_translate_languages.end(), [&old_language_pair](const base::Value& never_translate_language) { @@ -131,8 +131,8 @@ continue; } - always_translate_dictionary->SetStringKey( - old_language_pair.first, old_language_pair.second.GetString()); + always_translate_dictionary.Set(old_language_pair.first, + old_language_pair.second.GetString()); } prefs->ClearPref(TranslatePrefs::kPrefAlwaysTranslateListDeprecated); @@ -254,13 +254,13 @@ } // static -base::Value TranslatePrefs::GetDefaultBlockedLanguages() { - typename base::Value::ListStorage languages; +base::Value::List TranslatePrefs::GetDefaultBlockedLanguages() { + base::Value::List languages; #if BUILDFLAG(IS_CHROMEOS_ASH) // Preferred languages. std::string language = language::kFallbackInputMethodLocale; language::ToTranslateLanguageSynonym(&language); - languages.push_back(base::Value(std::move(language))); + languages.Append(std::move(language)); #else // Accept languages. #pragma GCC diagnostic push @@ -270,7 +270,7 @@ base::SplitString(l10n_util::GetStringUTF8(IDS_ACCEPT_LANGUAGES), ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) { language::ToTranslateLanguageSynonym(&language); - languages.push_back(base::Value(std::move(language))); + languages.Append(std::move(language)); // crbug.com/958348: The default value for Accept-Language *should* be the // same as the one for Blocked Languages. However, Accept-Language contains @@ -291,16 +291,15 @@ languages.erase(std::unique(languages.begin(), languages.end()), languages.end()); - return base::Value(std::move(languages)); + return languages; } bool TranslatePrefs::IsBlockedLanguage(base::StringPiece input_language) const { std::string canonical_lang(input_language); language::ToTranslateLanguageSynonym(&canonical_lang); - const base::Value* blocked = - prefs_->GetList(translate::prefs::kBlockedLanguages); - return base::Contains(blocked->GetListDeprecated(), - base::Value(std::move(canonical_lang))); + const base::Value::List& blocked = + prefs_->GetValueList(translate::prefs::kBlockedLanguages); + return base::Contains(blocked, base::Value(std::move(canonical_lang))); } void TranslatePrefs::BlockLanguage(base::StringPiece input_language) { @@ -338,14 +337,11 @@ } std::vector<std::string> TranslatePrefs::GetNeverTranslateLanguages() const { - const base::Value* fluent_languages_value = - prefs_->GetList(translate::prefs::kBlockedLanguages); - if (!fluent_languages_value) { - NOTREACHED() << "Fluent languages pref is unregistered"; - } + const base::Value::List& fluent_languages_value = + prefs_->GetValueList(translate::prefs::kBlockedLanguages); std::vector<std::string> languages; - for (const auto& language : fluent_languages_value->GetListDeprecated()) { + for (const auto& language : fluent_languages_value) { std::string chrome_language(language.GetString()); language::ToChromeLanguageSynonym(&chrome_language); languages.push_back(chrome_language); @@ -615,29 +611,29 @@ } bool TranslatePrefs::IsSiteOnNeverPromptList(base::StringPiece site) const { - return prefs_->GetDictionary(kPrefNeverPromptSitesWithTime)->FindKey(site); + return prefs_->GetValueDict(kPrefNeverPromptSitesWithTime).Find(site); } void TranslatePrefs::AddSiteToNeverPromptList(base::StringPiece site) { DCHECK(!site.empty()); AddValueToNeverPromptList(kPrefNeverPromptSitesDeprecated, site); DictionaryPrefUpdate update(prefs_, kPrefNeverPromptSitesWithTime); - update.Get()->SetKey(site, base::TimeToValue(base::Time::Now())); + update->GetDict().Set(site, base::TimeToValue(base::Time::Now())); } void TranslatePrefs::RemoveSiteFromNeverPromptList(base::StringPiece site) { DCHECK(!site.empty()); RemoveValueFromNeverPromptList(kPrefNeverPromptSitesDeprecated, site); DictionaryPrefUpdate update(prefs_, kPrefNeverPromptSitesWithTime); - update.Get()->RemoveKey(site); + update->GetDict().Remove(site); } std::vector<std::string> TranslatePrefs::GetNeverPromptSitesBetween( base::Time begin, base::Time end) const { std::vector<std::string> result; - auto* dict = prefs_->GetDictionary(kPrefNeverPromptSitesWithTime); - for (auto entry : dict->DictItems()) { + const auto& dict = prefs_->GetValueDict(kPrefNeverPromptSitesWithTime); + for (const auto entry : dict) { absl::optional<base::Time> time = base::ValueToTime(entry.second); if (!time) { // Badly formatted preferences may be synced from the server, see @@ -683,8 +679,7 @@ std::string translate_target_language(target_language); language::ToTranslateLanguageSynonym(&translate_target_language); - update.Get()->SetStringKey(translate_source_language, - translate_target_language); + update->GetDict().Set(translate_source_language, translate_target_language); // Remove source language from block list if present. UnblockLanguage(translate_source_language); } @@ -749,16 +744,16 @@ void TranslatePrefs::IncrementTranslationDeniedCount( base::StringPiece language) { DictionaryPrefUpdate update(prefs_, kPrefTranslateDeniedCount); - base::Value* dict = update.Get(); + base::Value::Dict& dict = update->GetDict(); - int count = dict->FindIntKey(language).value_or(0); + int count = dict.FindInt(language).value_or(0); if (count < std::numeric_limits<int>::max()) - dict->SetIntKey(language, count + 1); + dict.Set(language, count + 1); } void TranslatePrefs::ResetTranslationDeniedCount(base::StringPiece language) { DictionaryPrefUpdate update(prefs_, kPrefTranslateDeniedCount); - update.Get()->SetIntKey(language, 0); + update->GetDict().Set(language, 0); } int TranslatePrefs::GetTranslationIgnoredCount( @@ -771,16 +766,16 @@ void TranslatePrefs::IncrementTranslationIgnoredCount( base::StringPiece language) { DictionaryPrefUpdate update(prefs_, kPrefTranslateIgnoredCount); - base::Value* dict = update.Get(); + base::Value::Dict& dict = update->GetDict(); - int count = dict->FindIntKey(language).value_or(0); + int count = dict.FindInt(language).value_or(0); if (count < std::numeric_limits<int>::max()) - dict->SetIntKey(language, count + 1); + dict.Set(language, count + 1); } void TranslatePrefs::ResetTranslationIgnoredCount(base::StringPiece language) { DictionaryPrefUpdate update(prefs_, kPrefTranslateIgnoredCount); - update.Get()->SetIntKey(language, 0); + update->GetDict().Set(language, 0); } int TranslatePrefs::GetTranslationAcceptedCount( @@ -793,16 +788,16 @@ void TranslatePrefs::IncrementTranslationAcceptedCount( base::StringPiece language) { DictionaryPrefUpdate update(prefs_, kPrefTranslateAcceptedCount); - base::Value* dict = update.Get(); + base::Value::Dict& dict = update->GetDict(); - int count = dict->FindIntKey(language).value_or(0); + int count = dict.FindInt(language).value_or(0); if (count < std::numeric_limits<int>::max()) - dict->SetIntKey(language, count + 1); + dict.Set(language, count + 1); } void TranslatePrefs::ResetTranslationAcceptedCount(base::StringPiece language) { DictionaryPrefUpdate update(prefs_, kPrefTranslateAcceptedCount); - update.Get()->SetIntKey(language, 0); + update->GetDict().Set(language, 0); } #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS) @@ -816,17 +811,17 @@ void TranslatePrefs::IncrementTranslationAutoAlwaysCount( base::StringPiece language) { DictionaryPrefUpdate update(prefs_, kPrefTranslateAutoAlwaysCount); - base::Value* dict = update.Get(); + base::Value::Dict& dict = update->GetDict(); - int count = dict->FindIntKey(language).value_or(0); + int count = dict.FindInt(language).value_or(0); if (count < std::numeric_limits<int>::max()) - dict->SetIntKey(language, count + 1); + dict.Set(language, count + 1); } void TranslatePrefs::ResetTranslationAutoAlwaysCount( base::StringPiece language) { DictionaryPrefUpdate update(prefs_, kPrefTranslateAutoAlwaysCount); - update.Get()->SetIntKey(language, 0); + update->GetDict().Set(language, 0); } int TranslatePrefs::GetTranslationAutoNeverCount( @@ -839,17 +834,17 @@ void TranslatePrefs::IncrementTranslationAutoNeverCount( base::StringPiece language) { DictionaryPrefUpdate update(prefs_, kPrefTranslateAutoNeverCount); - base::Value* dict = update.Get(); + base::Value::Dict& dict = update->GetDict(); - int count = dict->FindIntKey(language).value_or(0); + int count = dict.FindInt(language).value_or(0); if (count < std::numeric_limits<int>::max()) - dict->SetIntKey(language, count + 1); + dict.Set(language, count + 1); } void TranslatePrefs::ResetTranslationAutoNeverCount( base::StringPiece language) { DictionaryPrefUpdate update(prefs_, kPrefTranslateAutoNeverCount); - update.Get()->SetIntKey(language, 0); + update->GetDict().Set(language, 0); } #endif // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS) @@ -997,21 +992,19 @@ // make subsequent calls to migrate no-ops. DictionaryPrefUpdate never_prompt_list_update(prefs_, kPrefNeverPromptSitesWithTime); - base::Value* never_prompt_list = never_prompt_list_update.Get(); - if (never_prompt_list) { - ListPrefUpdate deprecated_prompt_list_update( - prefs_, kPrefNeverPromptSitesDeprecated); - base::Value* deprecated_list = deprecated_prompt_list_update.Get(); - for (auto& site : deprecated_list->GetListDeprecated()) { - if (site.is_string() && - (!never_prompt_list->FindKey(site.GetString()) || - !base::ValueToTime(never_prompt_list->FindKey(site.GetString())))) { - never_prompt_list->SetKey(site.GetString(), - base::TimeToValue(base::Time::Now())); - } + base::Value::Dict& never_prompt_list = never_prompt_list_update->GetDict(); + ListPrefUpdate deprecated_prompt_list_update(prefs_, + kPrefNeverPromptSitesDeprecated); + base::Value::List& deprecated_list = deprecated_prompt_list_update->GetList(); + for (auto& site : deprecated_list) { + if (site.is_string() && + (!never_prompt_list.Find(site.GetString()) || + !base::ValueToTime(never_prompt_list.Find(site.GetString())))) { + never_prompt_list.Set(site.GetString(), + base::TimeToValue(base::Time::Now())); } - deprecated_list->ClearList(); } + deprecated_list.clear(); } // static @@ -1034,11 +1027,8 @@ bool TranslatePrefs::IsValueOnNeverPromptList(const char* pref_id, base::StringPiece value) const { - const base::Value* never_prompt_list = prefs_->GetList(pref_id); - if (!never_prompt_list) - return false; - for (const base::Value& value_in_list : - never_prompt_list->GetListDeprecated()) { + const base::Value::List& never_prompt_list = prefs_->GetValueList(pref_id); + for (const base::Value& value_in_list : never_prompt_list) { if (value_in_list.is_string() && value_in_list.GetString() == value) return true; } @@ -1063,25 +1053,20 @@ void TranslatePrefs::RemoveValueFromNeverPromptList(const char* pref_id, base::StringPiece value) { ListPrefUpdate update(prefs_, pref_id); - base::Value* never_prompt_list = update.Get(); - if (!never_prompt_list) { - NOTREACHED() << "Unregistered never-translate pref"; - return; - } + base::Value::List& never_prompt_list = update->GetList(); - auto list_view = never_prompt_list->GetListDeprecated(); - never_prompt_list->EraseListIter(std::find_if( - list_view.begin(), list_view.end(), + auto value_to_erase = std::find_if( + never_prompt_list.begin(), never_prompt_list.end(), [value](const base::Value& value_in_list) { return value_in_list.is_string() && value_in_list.GetString() == value; - })); + }); + if (value_to_erase != never_prompt_list.end()) + never_prompt_list.erase(value_to_erase); } size_t TranslatePrefs::GetListSize(const char* pref_id) const { - const base::Value* never_prompt_list = prefs_->GetList(pref_id); - return never_prompt_list == nullptr - ? 0 - : never_prompt_list->GetListDeprecated().size(); + const base::Value::List& never_prompt_list = prefs_->GetValueList(pref_id); + return never_prompt_list.size(); } bool TranslatePrefs::IsDictionaryEmpty(const char* pref_id) const {
diff --git a/components/translate/core/browser/translate_prefs.h b/components/translate/core/browser/translate_prefs.h index 86d8f16..c19a471 100644 --- a/components/translate/core/browser/translate_prefs.h +++ b/components/translate/core/browser/translate_prefs.h
@@ -175,8 +175,8 @@ void BlockLanguage(base::StringPiece source_language); void UnblockLanguage(base::StringPiece source_language); // Returns the languages that should be blocked by default as a - // base::(List)Value. - static base::Value GetDefaultBlockedLanguages(); + // base::Value::List. + static base::Value::List GetDefaultBlockedLanguages(); void ResetBlockedLanguagesToDefault(); // Prevent empty blocked languages by resetting them to the default value. // (crbug.com/902354)
diff --git a/components/translate/core/browser/translate_prefs_unittest.cc b/components/translate/core/browser/translate_prefs_unittest.cc index 9f69a8bcc..0eb6dcf 100644 --- a/components/translate/core/browser/translate_prefs_unittest.cc +++ b/components/translate/core/browser/translate_prefs_unittest.cc
@@ -43,15 +43,13 @@ using ::testing::UnorderedElementsAreArray; static void ExpectEqualLanguageLists( - const base::Value& language_values, + const base::Value::List& language_values, const std::vector<std::string>& languages) { const int input_size = languages.size(); - base::Value::ConstListView language_values_view = - language_values.GetListDeprecated(); - ASSERT_EQ(input_size, static_cast<int>(language_values_view.size())); + ASSERT_EQ(input_size, static_cast<int>(language_values.size())); for (int i = 0; i < input_size; ++i) { - ASSERT_TRUE(language_values_view[i].is_string()); - EXPECT_EQ(languages[i], language_values_view[i].GetString()); + ASSERT_TRUE(language_values[i].is_string()); + EXPECT_EQ(languages[i], language_values[i].GetString()); } } @@ -81,9 +79,9 @@ void ExpectBlockedLanguageListContent( const std::vector<std::string>& list) const { - const base::Value* const never_prompt_list = - prefs_.GetList(prefs::kBlockedLanguages); - ExpectEqualLanguageLists(*never_prompt_list, list); + const base::Value::List& never_prompt_list = + prefs_.GetValueList(prefs::kBlockedLanguages); + ExpectEqualLanguageLists(never_prompt_list, list); } // Returns a vector of language codes from the elements of the given @@ -940,23 +938,21 @@ TranslatePrefs::kPrefNeverPromptSitesDeprecated, "unmigrated.com"); translate_prefs_->AddValueToNeverPromptList( TranslatePrefs::kPrefNeverPromptSitesDeprecated, "migratedWrong.com"); - EXPECT_EQ(prefs_.Get(TranslatePrefs::kPrefNeverPromptSitesDeprecated) - ->GetListDeprecated() + EXPECT_EQ(prefs_.GetValueList(TranslatePrefs::kPrefNeverPromptSitesDeprecated) .size(), 2u); // Also put one of those sites on the new pref but migrated incorrectly. DictionaryPrefUpdate never_prompt_list_update( &prefs_, TranslatePrefs::kPrefNeverPromptSitesWithTime); - base::Value* never_prompt_list = never_prompt_list_update.Get(); - never_prompt_list->SetKey("migratedWrong.com", base::Value(0)); + base::Value::Dict& never_prompt_list = never_prompt_list_update->GetDict(); + never_prompt_list.Set("migratedWrong.com", 0); // Now migrate and fix the prefs. translate_prefs_->MigrateNeverPromptSites(); EXPECT_THAT(translate_prefs_->GetNeverPromptSitesBetween( base::Time::Now() - base::Days(1), base::Time::Max()), ElementsAre("migratedWrong.com", "unmigrated.com")); - EXPECT_EQ(prefs_.Get(TranslatePrefs::kPrefNeverPromptSitesDeprecated) - ->GetListDeprecated() + EXPECT_EQ(prefs_.GetValueList(TranslatePrefs::kPrefNeverPromptSitesDeprecated) .size(), 0u); } @@ -966,11 +962,11 @@ // Add sites with invalid times. DictionaryPrefUpdate never_prompt_list_update( &prefs_, TranslatePrefs::kPrefNeverPromptSitesWithTime); - base::Value* never_prompt_list = never_prompt_list_update.Get(); - never_prompt_list->SetKey("not-a-string.com", base::Value(0)); - never_prompt_list->SetKey("not-a-valid-time.com", base::Value("foo")); + base::Value::Dict& never_prompt_list = never_prompt_list_update->GetDict(); + never_prompt_list.Set("not-a-string.com", 0); + never_prompt_list.Set("not-a-valid-time.com", "foo"); // Add the null time (valid time). - never_prompt_list->SetKey("null-time.com", base::Value("0")); + never_prompt_list.Set("null-time.com", "0"); // This should not crash, and filter invalid times. EXPECT_THAT(translate_prefs_->GetNeverPromptSitesBetween(base::Time::Min(), @@ -1215,28 +1211,29 @@ scoped_feature_list.InitAndDisableFeature( kMigrateAlwaysTranslateLanguagesFix); - base::Value never_translate_list(base::Value::Type::LIST); + base::Value::List never_translate_list; never_translate_list.Append("en"); - base::Value old_always_translate_map(base::Value::Type::DICTIONARY); - old_always_translate_map.SetStringKey("fr", "en"); + base::Value::Dict old_always_translate_map; + old_always_translate_map.Set("fr", "en"); - base::Value new_always_translate_map(base::Value::Type::DICTIONARY); - new_always_translate_map.SetStringKey("ru", "en"); + base::Value::Dict new_always_translate_map; + new_always_translate_map.Set("ru", "en"); - prefs_.Set(prefs::kBlockedLanguages, never_translate_list.Clone()); - prefs_.Set(TranslatePrefs::kPrefAlwaysTranslateListDeprecated, - old_always_translate_map.Clone()); - prefs_.Set(prefs::kPrefAlwaysTranslateList, new_always_translate_map.Clone()); + prefs_.SetList(prefs::kBlockedLanguages, never_translate_list.Clone()); + prefs_.SetDict(TranslatePrefs::kPrefAlwaysTranslateListDeprecated, + old_always_translate_map.Clone()); + prefs_.SetDict(prefs::kPrefAlwaysTranslateList, + new_always_translate_map.Clone()); // Since the kMigrateAlwaysTranslateLanguagesFix feature is disabled, no // migration should occur during construction. TranslatePrefs translate_prefs(&prefs_); EXPECT_EQ( - *prefs_.GetDictionary(TranslatePrefs::kPrefAlwaysTranslateListDeprecated), + prefs_.GetValueDict(TranslatePrefs::kPrefAlwaysTranslateListDeprecated), old_always_translate_map); - EXPECT_EQ(*prefs_.GetDictionary(prefs::kPrefAlwaysTranslateList), + EXPECT_EQ(prefs_.GetValueDict(prefs::kPrefAlwaysTranslateList), new_always_translate_map); } @@ -1245,30 +1242,30 @@ base::test::ScopedFeatureList scoped_feature_list( kMigrateAlwaysTranslateLanguagesFix); - base::Value never_translate_list(base::Value::Type::LIST); + base::Value::List never_translate_list; never_translate_list.Append("en"); never_translate_list.Append("es"); - prefs_.Set(prefs::kBlockedLanguages, std::move(never_translate_list)); + prefs_.SetList(prefs::kBlockedLanguages, std::move(never_translate_list)); - base::Value old_always_translate_map(base::Value::Type::DICTIONARY); + base::Value::Dict old_always_translate_map; // A non-conflicting language pair that should be merged. - old_always_translate_map.SetStringKey("fr", "en"); + old_always_translate_map.Set("fr", "en"); // Conflicts with a new language pair with the same source language. - old_always_translate_map.SetStringKey("ru", "de"); + old_always_translate_map.Set("ru", "de"); // Conflicts with a new language pair with this source language as the target. - old_always_translate_map.SetStringKey("jp", "de"); + old_always_translate_map.Set("jp", "de"); // Conflicts with a new language pair with this target language as the source. - old_always_translate_map.SetStringKey("pt", "hi"); + old_always_translate_map.Set("pt", "hi"); - prefs_.Set(TranslatePrefs::kPrefAlwaysTranslateListDeprecated, - std::move(old_always_translate_map)); + prefs_.SetDict(TranslatePrefs::kPrefAlwaysTranslateListDeprecated, + std::move(old_always_translate_map)); - base::Value new_always_translate_map(base::Value::Type::DICTIONARY); - new_always_translate_map.SetStringKey("ru", "en"); - new_always_translate_map.SetStringKey("id", "jp"); - new_always_translate_map.SetStringKey("hi", "en"); - prefs_.Set(prefs::kPrefAlwaysTranslateList, - std::move(new_always_translate_map)); + base::Value::Dict new_always_translate_map; + new_always_translate_map.Set("ru", "en"); + new_always_translate_map.Set("id", "jp"); + new_always_translate_map.Set("hi", "en"); + prefs_.SetDict(prefs::kPrefAlwaysTranslateList, + std::move(new_always_translate_map)); // The always-translate pref migration should be done during construction. TranslatePrefs translate_prefs(&prefs_); @@ -1276,13 +1273,13 @@ EXPECT_FALSE(prefs_.GetUserPrefValue( TranslatePrefs::kPrefAlwaysTranslateListDeprecated)); - base::Value expected_always_translate_map(base::Value::Type::DICTIONARY); - expected_always_translate_map.SetStringKey("ru", "en"); - expected_always_translate_map.SetStringKey("id", "jp"); - expected_always_translate_map.SetStringKey("hi", "en"); - expected_always_translate_map.SetStringKey("fr", "en"); + base::Value::Dict expected_always_translate_map; + expected_always_translate_map.Set("ru", "en"); + expected_always_translate_map.Set("id", "jp"); + expected_always_translate_map.Set("hi", "en"); + expected_always_translate_map.Set("fr", "en"); - EXPECT_EQ(*prefs_.GetDictionary(prefs::kPrefAlwaysTranslateList), + EXPECT_EQ(prefs_.GetValueDict(prefs::kPrefAlwaysTranslateList), expected_always_translate_map); }
diff --git a/components/viz/common/quads/render_pass_io.cc b/components/viz/common/quads/render_pass_io.cc index a46459b7..2395e2c 100644 --- a/components/viz/common/quads/render_pass_io.cc +++ b/components/viz/common/quads/render_pass_io.cc
@@ -377,13 +377,64 @@ return true; } -base::Value MaskFilterInfoToDict(const gfx::MaskFilterInfo& mask_filter_info) { - base::Value dict(base::Value::Type::DICTIONARY); - dict.SetKey("rounded_corner_bounds", - RRectFToDict(mask_filter_info.rounded_corner_bounds())); +base::Value::Dict LinearGradientToDict( + const gfx::LinearGradient& gradient_mask) { + base::Value::Dict dict; + dict.Set("angle", static_cast<double>(gradient_mask.angle())); + dict.Set("step_count", static_cast<int>(gradient_mask.step_count())); + + base::Value::List steps; + for (size_t i = 0; i < gradient_mask.step_count(); ++i) { + base::Value::Dict step_dict; + step_dict.Set("percent", + static_cast<double>(gradient_mask.steps()[i].percent)); + step_dict.Set("alpha", static_cast<int>(gradient_mask.steps()[i].alpha)); + steps.Append(std::move(step_dict)); + } + dict.Set("steps", std::move(steps)); + return dict; } +bool LinearGradientFromDict(const base::Value::Dict& dict, + gfx::LinearGradient* out) { + absl::optional<double> angle = dict.FindDouble("angle"); + absl::optional<int> step_count = dict.FindInt("step_count"); + if (!angle || !step_count) + return false; + + gfx::LinearGradient gradient_mask = gfx::LinearGradient(*angle); + const base::Value::List* steps = dict.FindList("steps"); + if (!steps) + return false; + for (const base::Value& v : *steps) { + const base::Value::Dict* step = v.GetIfDict(); + if (!step) + return false; + + absl::optional<double> percent = step->FindDouble("percent"); + absl::optional<int> alpha = step->FindInt("alpha"); + if (!percent || !alpha) + return false; + + gradient_mask.AddStep(*percent, *alpha); + } + + *out = gradient_mask; + return true; +} + +base::Value MaskFilterInfoToDict(const gfx::MaskFilterInfo& mask_filter_info) { + base::Value::Dict dict; + dict.Set("rounded_corner_bounds", + RRectFToDict(mask_filter_info.rounded_corner_bounds())); + if (mask_filter_info.HasGradientMask()) { + dict.Set("gradient_mask", + LinearGradientToDict(*mask_filter_info.gradient_mask())); + } + return base::Value(std::move(dict)); +} + bool MaskFilterInfoFromDict(const base::Value& dict, gfx::MaskFilterInfo* out) { DCHECK(out); if (!dict.is_dict()) @@ -395,7 +446,19 @@ gfx::RRectF t_rounded_corner_bounds; if (!RRectFFromDict(*rounded_corner_bounds, &t_rounded_corner_bounds)) return false; - *out = gfx::MaskFilterInfo(t_rounded_corner_bounds); + + const base::Value::Dict* gradient_mask = + dict.FindDictKey("gradient_mask")->GetIfDict(); + if (!gradient_mask) { + *out = gfx::MaskFilterInfo(t_rounded_corner_bounds); + return true; + } + + gfx::LinearGradient t_gradient_mask; + if (!LinearGradientFromDict(*gradient_mask, &t_gradient_mask)) + return false; + + *out = gfx::MaskFilterInfo(t_rounded_corner_bounds, t_gradient_mask); return true; }
diff --git a/components/viz/common/quads/render_pass_io_unittest.cc b/components/viz/common/quads/render_pass_io_unittest.cc index c4bb3c0..6a0e2dcd 100644 --- a/components/viz/common/quads/render_pass_io_unittest.cc +++ b/components/viz/common/quads/render_pass_io_unittest.cc
@@ -125,16 +125,20 @@ ASSERT_TRUE(sqs1); gfx::Transform transform; transform.MakeIdentity(); + gfx::LinearGradient gradient_mask(40); + gradient_mask.AddStep(/*percent=*/0, /*alpha=*/0); + gradient_mask.AddStep(100, 255); sqs1->SetAll( transform, gfx::Rect(0, 0, 640, 480), gfx::Rect(10, 10, 600, 400), - gfx::MaskFilterInfo(gfx::RRectF(gfx::RectF(2.f, 3.f, 4.f, 5.f), 1.5f)), + gfx::MaskFilterInfo(gfx::RRectF(gfx::RectF(2.f, 3.f, 4.f, 5.f), 1.5f), + gradient_mask), gfx::Rect(5, 20, 1000, 200), false, 0.5f, SkBlendMode::kDstOver, 101); sqs1->is_fast_rounded_corner = true; sqs1->de_jelly_delta_y = 0.7f; } base::Value dict0 = CompositorRenderPassToDict(*render_pass0); auto render_pass1 = CompositorRenderPassFromDict(dict0); - EXPECT_TRUE(render_pass1); + ASSERT_TRUE(render_pass1); { // Verify two SQS. EXPECT_EQ(2u, render_pass1->shared_quad_state_list.size()); @@ -145,6 +149,7 @@ EXPECT_EQ(gfx::Rect(), sqs0->quad_layer_rect); EXPECT_EQ(gfx::Rect(), sqs0->visible_quad_layer_rect); EXPECT_FALSE(sqs0->mask_filter_info.HasRoundedCorners()); + EXPECT_FALSE(sqs0->mask_filter_info.HasGradientMask()); EXPECT_EQ(absl::nullopt, sqs0->clip_rect); EXPECT_TRUE(sqs0->are_contents_opaque); EXPECT_EQ(1.0f, sqs0->opacity); @@ -163,6 +168,13 @@ sqs1->mask_filter_info.rounded_corner_bounds().GetType()); EXPECT_EQ(1.5f, sqs1->mask_filter_info.rounded_corner_bounds().GetSimpleRadius()); + ASSERT_TRUE(sqs1->mask_filter_info.HasGradientMask()); + EXPECT_EQ(40, sqs1->mask_filter_info.gradient_mask()->angle()); + EXPECT_EQ(2u, sqs1->mask_filter_info.gradient_mask()->step_count()); + EXPECT_EQ(gfx::LinearGradient::Step({0, 0}), + sqs1->mask_filter_info.gradient_mask()->steps()[0]); + EXPECT_EQ(gfx::LinearGradient::Step({100, 255}), + sqs1->mask_filter_info.gradient_mask()->steps()[1]); EXPECT_EQ(gfx::RectF(2.f, 3.f, 4.f, 5.f), sqs1->mask_filter_info.bounds()); EXPECT_EQ(gfx::Rect(5, 20, 1000, 200), sqs1->clip_rect); EXPECT_FALSE(sqs1->are_contents_opaque);
diff --git a/components/viz/service/display/DEPS b/components/viz/service/display/DEPS index ca3f9db..6910887 100644 --- a/components/viz/service/display/DEPS +++ b/components/viz/service/display/DEPS
@@ -35,6 +35,7 @@ "+ui/gfx/video_types.h", "+ui/gl/ca_renderer_layer_params.h", "+ui/gl/dc_renderer_layer_params.h", + "+ui/gl/direct_composition_surface_win.h", "+ui/gl/gl_fence.h", "+ui/gl/gl_utils.h", "+ui/gl/gpu_switching_manager.h",
diff --git a/components/viz/service/display/dc_layer_overlay.cc b/components/viz/service/display/dc_layer_overlay.cc index cd9c63a..d02a4f0 100644 --- a/components/viz/service/display/dc_layer_overlay.cc +++ b/components/viz/service/display/dc_layer_overlay.cc
@@ -30,7 +30,6 @@ #include "ui/gfx/geometry/rect_conversions.h" #include "ui/gl/gl_switches.h" #include "ui/gl/gl_utils.h" -#include "ui/gl/gpu_switching_manager.h" namespace viz { @@ -469,41 +468,28 @@ bool skip_initialization_for_testing) : has_overlay_support_(skip_initialization_for_testing), allowed_yuv_overlay_count_(allowed_yuv_overlay_count), - debug_settings_(debug_settings), - viz_task_runner_(skip_initialization_for_testing - ? nullptr - : base::ThreadTaskRunnerHandle::Get()) { + debug_settings_(debug_settings) { if (!skip_initialization_for_testing) { UpdateHasHwOverlaySupport(); - ui::GpuSwitchingManager::GetInstance()->AddObserver(this); + gl::DirectCompositionOverlayCapsMonitor::GetInstance()->AddObserver(this); } allow_promotion_hinting_ = media::SupportMediaFoundationClearPlayback(); } DCLayerOverlayProcessor::~DCLayerOverlayProcessor() { - ui::GpuSwitchingManager::GetInstance()->RemoveObserver(this); + gl::DirectCompositionOverlayCapsMonitor::GetInstance()->RemoveObserver(this); } -// Called on the Viz Compositor thread void DCLayerOverlayProcessor::UpdateHasHwOverlaySupport() { - DCHECK(viz_task_runner_->BelongsToCurrentThread()); + // gl::AreOverlaysSupportedWin() calls + // gl::DirectCompositionSurfaceWin::AreOverlaysSupported(). It's thread safe. has_overlay_support_ = gl::AreOverlaysSupportedWin(); } -// Not on the Viz Compositor thread -void DCLayerOverlayProcessor::OnDisplayAdded() { - viz_task_runner_->PostTask( - FROM_HERE, - base::BindOnce(&DCLayerOverlayProcessor::UpdateHasHwOverlaySupport, - base::Unretained(this))); -} - -// Not on the Viz Compositor thread -void DCLayerOverlayProcessor::OnDisplayRemoved() { - viz_task_runner_->PostTask( - FROM_HERE, - base::BindOnce(&DCLayerOverlayProcessor::UpdateHasHwOverlaySupport, - base::Unretained(this))); +// Called on the Viz Compositor thread. +void DCLayerOverlayProcessor::OnOverlayCapsChanged() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + UpdateHasHwOverlaySupport(); } void DCLayerOverlayProcessor::ClearOverlayState() {
diff --git a/components/viz/service/display/dc_layer_overlay.h b/components/viz/service/display/dc_layer_overlay.h index 53bf411c..33c7b07d 100644 --- a/components/viz/service/display/dc_layer_overlay.h +++ b/components/viz/service/display/dc_layer_overlay.h
@@ -10,7 +10,7 @@ #include "base/containers/flat_map.h" #include "base/memory/raw_ptr.h" #include "base/memory/ref_counted.h" -#include "base/task/single_thread_task_runner.h" +#include "base/threading/thread_checker.h" #include "components/viz/common/quads/aggregated_render_pass.h" #include "components/viz/service/display/aggregated_frame.h" #include "components/viz/service/viz_service_export.h" @@ -19,7 +19,7 @@ #include "ui/gfx/geometry/rect_f.h" #include "ui/gfx/hdr_metadata.h" #include "ui/gfx/video_types.h" -#include "ui/gl/gpu_switching_observer.h" +#include "ui/gl/direct_composition_surface_win.h" namespace viz { struct DebugRendererSettings; @@ -74,8 +74,8 @@ typedef std::vector<DCLayerOverlay> DCLayerOverlayList; -class VIZ_SERVICE_EXPORT DCLayerOverlayProcessor - : public ui::GpuSwitchingObserver { +class VIZ_SERVICE_EXPORT DCLayerOverlayProcessor final + : public gl::DirectCompositionOverlayCapsObserver { public: using FilterOperationsMap = base::flat_map<AggregatedRenderPassId, cc::FilterOperations*>; @@ -89,7 +89,7 @@ DCLayerOverlayProcessor(const DCLayerOverlayProcessor&) = delete; DCLayerOverlayProcessor& operator=(const DCLayerOverlayProcessor&) = delete; - virtual ~DCLayerOverlayProcessor(); + ~DCLayerOverlayProcessor() override; // Virtual for testing. virtual void Process(DisplayResourceProvider* resource_provider, @@ -106,9 +106,8 @@ // be empty. gfx::Rect PreviousFrameOverlayDamageContribution(); - // GpuSwitchingObserver implementation. - void OnDisplayAdded() override; - void OnDisplayRemoved() override; + // DirectCompositionOverlayCapsObserver implementation. + void OnOverlayCapsChanged() override; void UpdateHasHwOverlaySupport(); void set_frames_since_last_qualified_multi_overlays_for_testing(int value) { @@ -191,7 +190,7 @@ bool has_overlay_support_; const int allowed_yuv_overlay_count_; int processed_yuv_overlay_count_ = 0; - unsigned long frames_since_last_qualified_multi_overlays_ = 0; + uint64_t frames_since_last_qualified_multi_overlays_ = 0; // Reference to the global viz singleton. const raw_ptr<const DebugRendererSettings> debug_settings_; @@ -218,7 +217,7 @@ std::vector<gfx::Rect> previous_frame_overlay_candidate_rects_{}; int frames_since_last_overlay_candidate_rects_change_ = 0; - scoped_refptr<base::SingleThreadTaskRunner> viz_task_runner_; + THREAD_CHECKER(thread_checker_); }; } // namespace viz
diff --git a/components/viz/service/display/direct_renderer.cc b/components/viz/service/display/direct_renderer.cc index 3f514bb..2e956bbf 100644 --- a/components/viz/service/display/direct_renderer.cc +++ b/components/viz/service/display/direct_renderer.cc
@@ -968,6 +968,13 @@ return current_frame()->display_color_spaces.GetSDRMaxLuminanceNits(); } +bool DirectRenderer::ShouldApplyGradientMask(const DrawQuad* quad) const { + if (!quad->shared_quad_state->mask_filter_info.HasGradientMask()) + return false; + + return true; +} + gfx::ColorSpace DirectRenderer::RootRenderPassColorSpace() const { return current_frame()->display_color_spaces.GetOutputColorSpace( current_frame()->root_render_pass->content_color_usage,
diff --git a/components/viz/service/display/direct_renderer.h b/components/viz/service/display/direct_renderer.h index 8144d55..ddd6c4e4 100644 --- a/components/viz/service/display/direct_renderer.h +++ b/components/viz/service/display/direct_renderer.h
@@ -286,6 +286,7 @@ } bool ShouldApplyRoundedCorner(const DrawQuad* quad) const; + bool ShouldApplyGradientMask(const DrawQuad* quad) const; float CurrentFrameSDRWhiteLevel() const; gfx::ColorSpace RootRenderPassColorSpace() const;
diff --git a/components/viz/service/display/renderer_pixeltest.cc b/components/viz/service/display/renderer_pixeltest.cc index db371b71..af59e3e 100644 --- a/components/viz/service/display/renderer_pixeltest.cc +++ b/components/viz/service/display/renderer_pixeltest.cc
@@ -4411,7 +4411,7 @@ gfx::RRectF rounded_corner_rrect(gfx::RectF(blue_rect), kCornerRadius); SharedQuadState* shared_state_rounded = CreateTestSharedQuadState( quad_to_target_transform, viewport_rect, root_pass.get(), - gfx::MaskFilterInfo(rounded_corner_rrect, gfx::LinearGradient())); + gfx::MaskFilterInfo(rounded_corner_rrect)); auto* blue = root_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); blue->SetNew(shared_state_rounded, blue_rect, blue_rect, SkColors::kBlue, @@ -4450,7 +4450,7 @@ gfx::RRectF rounded_corner_rrect(gfx::RectF(blue_rect), kCornerRadius); SharedQuadState* shared_state_rounded = CreateTestSharedQuadState( quad_to_target_transform, viewport_rect, root_pass.get(), - gfx::MaskFilterInfo(rounded_corner_rrect, gfx::LinearGradient())); + gfx::MaskFilterInfo(rounded_corner_rrect)); const uint8_t colors[] = {0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255}; @@ -4518,7 +4518,7 @@ quad_to_target_transform.Translate(blue_offset_from_target); SharedQuadState* shared_state_with_rrect = CreateTestSharedQuadState( quad_to_target_transform, child_pass_local_rect, child_pass.get(), - gfx::MaskFilterInfo(blue_rrect, gfx::LinearGradient())); + gfx::MaskFilterInfo(blue_rrect)); auto* blue = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); blue->SetNew(shared_state_with_rrect, blue_rect, blue_rect, SkColors::kBlue, false); @@ -4539,7 +4539,7 @@ gfx::RRectF rounded_corner_bounds(gfx::RectF(pass_rect), kCornerRadius); SharedQuadState* pass_shared_state = CreateTestSharedQuadState(gfx::Transform(), pass_rect, root_pass.get(), - gfx::MaskFilterInfo(rounded_corner_bounds, gfx::LinearGradient())); + gfx::MaskFilterInfo(rounded_corner_bounds)); CreateTestRenderPassDrawQuad(pass_shared_state, pass_rect, child_pass_id, root_pass.get()); @@ -4553,6 +4553,125 @@ cc::FuzzyPixelOffByOneComparator(true))); } +TEST_P(GPURendererPixelTest, LinearGradientOnRenderPass) { + gfx::Rect viewport_rect(this->device_viewport_size_); + constexpr int kCornerRadius = 20; + + AggregatedRenderPassId root_pass_id{1}; + auto root_pass = CreateTestRootRenderPass(root_pass_id, viewport_rect); + + AggregatedRenderPassId child_pass_id{2}; + gfx::Rect pass_rect(this->device_viewport_size_); + gfx::Rect child_pass_local_rect = gfx::Rect(pass_rect.size()); + gfx::Transform transform_to_root; + transform_to_root.Translate(pass_rect.OffsetFromOrigin()); + auto child_pass = CreateTestRenderPass(child_pass_id, child_pass_local_rect, + transform_to_root); + + gfx::Rect white_rect = child_pass_local_rect; + SharedQuadState* shared_state_without_rrect = + CreateTestSharedQuadState(gfx::Transform(), child_pass_local_rect, + child_pass.get(), gfx::MaskFilterInfo()); + auto* white = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); + white->SetNew(shared_state_without_rrect, white_rect, white_rect, + SkColors::kWhite, false); + + gfx::RRectF rounded_corner_bounds(gfx::RectF(pass_rect), kCornerRadius); + gfx::LinearGradient gradient_mask(90); + gradient_mask.AddStep(/*percent=*/0, /*alpha=*/0); + gradient_mask.AddStep(50, 255); + gradient_mask.AddStep(100, 255); + SharedQuadState* pass_shared_state = CreateTestSharedQuadState( + gfx::Transform(), pass_rect, root_pass.get(), + gfx::MaskFilterInfo(rounded_corner_bounds, gradient_mask)); + CreateTestRenderPassDrawQuad(pass_shared_state, pass_rect, child_pass_id, + root_pass.get()); + + AggregatedRenderPassList pass_list; + pass_list.push_back(std::move(child_pass)); + pass_list.push_back(std::move(root_pass)); + + EXPECT_TRUE(this->RunPixelTest( + &pass_list, + base::FilePath(FILE_PATH_LITERAL("linear_gradient_render_pass.png")), + cc::FuzzyPixelComparator(/*discard_alpha=*/true, + /*error_pixels_percentage_limit=*/0.6f, + /*small_error_pixels_percentage_limit=*/0.f, + /*avg_abs_error_limit=*/255.f, + /*max_abs_error_limit=*/255, + /*small_error_threshold=*/0))); +} + +TEST_P(GPURendererPixelTest, MultiLinearGradientOnRenderPass) { + gfx::Rect viewport_rect(this->device_viewport_size_); + constexpr int kCornerRadius = 20; + constexpr int kInset = 20; + constexpr int kBlueCornerRadius = 10; + + AggregatedRenderPassId root_pass_id{1}; + auto root_pass = CreateTestRootRenderPass(root_pass_id, viewport_rect); + + AggregatedRenderPassId child_pass_id{2}; + gfx::Rect pass_rect(this->device_viewport_size_); + pass_rect.Inset(kInset); + gfx::Rect child_pass_local_rect = gfx::Rect(pass_rect.size()); + gfx::Transform transform_to_root; + transform_to_root.Translate(pass_rect.OffsetFromOrigin()); + auto child_pass = CreateTestRenderPass(child_pass_id, child_pass_local_rect, + transform_to_root); + + gfx::Rect blue_rect = child_pass_local_rect; + gfx::Vector2dF blue_offset_from_target(-30, 40); + gfx::RRectF blue_rrect(gfx::RectF(blue_rect), kBlueCornerRadius); + blue_rrect.Offset(blue_offset_from_target); + gfx::LinearGradient blue_gradient(0); + blue_gradient.AddStep(/*percent=*/0, /*alpha=*/255); + blue_gradient.AddStep(100, 0); + + gfx::Transform quad_to_target_transform; + quad_to_target_transform.Translate(blue_offset_from_target); + SharedQuadState* shared_state_with_rrect = CreateTestSharedQuadState( + quad_to_target_transform, child_pass_local_rect, child_pass.get(), + gfx::MaskFilterInfo(blue_rrect, blue_gradient)); + auto* blue = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); + blue->SetNew(shared_state_with_rrect, blue_rect, blue_rect, SkColors::kBlue, + false); + + gfx::Rect white_rect = child_pass_local_rect; + SharedQuadState* shared_state_without_rrect = + CreateTestSharedQuadState(gfx::Transform(), child_pass_local_rect, + child_pass.get(), gfx::MaskFilterInfo()); + auto* white = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); + white->SetNew(shared_state_without_rrect, white_rect, white_rect, + SkColors::kWhite, false); + + gfx::RRectF rounded_corner_bounds(gfx::RectF(pass_rect), kCornerRadius); + gfx::LinearGradient gradient_mask(90); + gradient_mask.AddStep(/*percent=*/0, /*alpha=*/0); + gradient_mask.AddStep(50, 255); + gradient_mask.AddStep(100, 255); + SharedQuadState* pass_shared_state = CreateTestSharedQuadState( + gfx::Transform(), pass_rect, root_pass.get(), + gfx::MaskFilterInfo(rounded_corner_bounds, gradient_mask)); + CreateTestRenderPassDrawQuad(pass_shared_state, pass_rect, child_pass_id, + root_pass.get()); + + AggregatedRenderPassList pass_list; + pass_list.push_back(std::move(child_pass)); + pass_list.push_back(std::move(root_pass)); + + EXPECT_TRUE(this->RunPixelTest( + &pass_list, + base::FilePath( + FILE_PATH_LITERAL("multi_linear_gradient_render_pass.png")), + cc::FuzzyPixelComparator(/*discard_alpha=*/true, + /*error_pixels_percentage_limit=*/0.6f, + /*small_error_pixels_percentage_limit=*/0.f, + /*avg_abs_error_limit=*/255.f, + /*max_abs_error_limit=*/255, + /*small_error_threshold=*/0))); +} + TEST_P(RendererPixelTest, RoundedCornerMultiRadii) { gfx::Rect viewport_rect(this->device_viewport_size_); constexpr gfx::RoundedCornersF kCornerRadii(5, 15, 25, 35); @@ -4570,7 +4689,7 @@ gfx::Transform quad_to_target_transform; SharedQuadState* shared_state_normal = CreateTestSharedQuadState( quad_to_target_transform, pass_rect, root_pass.get(), - gfx::MaskFilterInfo(rounded_corner_bounds, gfx::LinearGradient())); + gfx::MaskFilterInfo(rounded_corner_bounds)); auto* blue = root_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); blue->SetNew(shared_state_normal, blue_rect, blue_rect, SkColors::kBlue, false); @@ -4638,24 +4757,21 @@ ll_rect.set_width(ul_rect.width()); ll_rect.set_height(lr_rect.height()); - SharedQuadState* shared_state_normal_ul = CreateTestSharedQuadState( - gfx::Transform(), pass_rect, root_pass.get(), - gfx::MaskFilterInfo(rounded_corner_bounds_ul, gfx::LinearGradient())); + SharedQuadState* shared_state_normal_ul = + CreateTestSharedQuadState(gfx::Transform(), pass_rect, root_pass.get(), + gfx::MaskFilterInfo(rounded_corner_bounds_ul)); - SharedQuadState* shared_state_normal_ur = CreateTestSharedQuadState( - gfx::Transform(), pass_rect, root_pass.get(), - gfx::MaskFilterInfo(rounded_corner_bounds_ur, - gfx::LinearGradient())); + SharedQuadState* shared_state_normal_ur = + CreateTestSharedQuadState(gfx::Transform(), pass_rect, root_pass.get(), + gfx::MaskFilterInfo(rounded_corner_bounds_ur)); - SharedQuadState* shared_state_normal_lr = CreateTestSharedQuadState( - gfx::Transform(), pass_rect, root_pass.get(), - gfx::MaskFilterInfo(rounded_corner_bounds_lr, - gfx::LinearGradient())); + SharedQuadState* shared_state_normal_lr = + CreateTestSharedQuadState(gfx::Transform(), pass_rect, root_pass.get(), + gfx::MaskFilterInfo(rounded_corner_bounds_lr)); - SharedQuadState* shared_state_normal_ll = CreateTestSharedQuadState( - gfx::Transform(), pass_rect, root_pass.get(), - gfx::MaskFilterInfo(rounded_corner_bounds_ll, - gfx::LinearGradient())); + SharedQuadState* shared_state_normal_ll = + CreateTestSharedQuadState(gfx::Transform(), pass_rect, root_pass.get(), + gfx::MaskFilterInfo(rounded_corner_bounds_ll)); auto* ul = root_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); auto* ur = root_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
diff --git a/components/viz/service/display/skia_renderer.cc b/components/viz/service/display/skia_renderer.cc index 427879fa..5a61de0 100644 --- a/components/viz/service/display/skia_renderer.cc +++ b/components/viz/service/display/skia_renderer.cc
@@ -70,7 +70,9 @@ #include "third_party/skia/modules/skcms/skcms.h" #include "ui/base/ui_base_features.h" #include "ui/gfx/color_transform.h" +#include "ui/gfx/geometry/angle_conversions.h" #include "ui/gfx/geometry/axis_transform2d.h" +#include "ui/gfx/geometry/linear_gradient.h" #include "ui/gfx/geometry/rect_conversions.h" #include "ui/gfx/geometry/size_conversions.h" #include "ui/gfx/geometry/skia_conversions.h" @@ -1158,6 +1160,9 @@ current_canvas_->clipRRect( static_cast<SkRRect>(mask_filter_info->rounded_corner_bounds()), /*doAntiAlias=*/true); + + if (mask_filter_info->HasGradientMask()) + PrepareGradient(mask_filter_info); } if (cdt) { @@ -1167,6 +1172,89 @@ } } +#define MaskColor(a) SkColorSetARGB(a, a, a, a); + +void SkiaRenderer::PrepareGradient( + const absl::optional<gfx::MaskFilterInfo>& mask_filter_info) { + if (!mask_filter_info || !mask_filter_info->HasGradientMask()) + return; + + const gfx::RectF rect = mask_filter_info->bounds(); + const absl::optional<gfx::LinearGradient>& gradient_mask = + mask_filter_info->gradient_mask(); + const int16_t angle = gradient_mask->angle() % 360; + + // For positive angles, the start point is the bottom left rect point. For + // negative angles, the start point is the upper left rect point. + bool negative = angle < 0; + SkPoint start_end[2]; + start_end[0] = {0, negative ? 0 : rect.height()}; + + // We explicitly specify the end point when cos(angle) = 0 and for axis + // aligned angles, where complex computation is not required to determine the + // end point. + switch (std::abs(angle)) { + case 0: + ABSL_FALLTHROUGH_INTENDED; + case 180: + ABSL_FALLTHROUGH_INTENDED; + case 360: + start_end[1] = {rect.width(), negative ? 0 : rect.height()}; + break; + case 90: + ABSL_FALLTHROUGH_INTENDED; + case 270: + start_end[1] = {0, negative ? rect.height() : 0}; + break; + // For non-axis aligned angles, the end point is the intersection of + // the gradient line and the normal line. The normal line is orthogonal to + // the gradient line and intersects the corner diagonal from the start + // point. + // Positive angle gradient line example: + // + + // +-/-------+ + // |/ ) | + // +---------+ + // + // Negative angle gradient line example: + // +---------+ + // |\ ) | + // +-\-------+ + // + + default: { + // TODO(crbug.com/1039003): add computation for angles >90 deg. + float rad_angle = gfx::DegToRad(static_cast<float>(angle)); + float s = std::sin(rad_angle); + float c = std::cos(rad_angle); + float t = std::tan(rad_angle); + + float a = rect.width() * t; + float b = rect.height() - a; + float cc = b * s; + float d = cc * c; + float e = cc * s; + float end_x = (rect.width() + d); + float end_y = negative ? (a + e) : (rect.height() - a - e); + + start_end[1] = {end_x, end_y}; + } + } + + SkScalar positions[gfx::LinearGradient::kMaxStepSize]; + SkColor gradient_colors[gfx::LinearGradient::kMaxStepSize]; + + size_t i = 0; + for (; i < gradient_mask->step_count(); ++i) { + positions[i] = gradient_mask->steps()[i].percent / 100.f; + gradient_colors[i] = MaskColor(gradient_mask->steps()[i].alpha); + } + + SkPoint::Offset(start_end, /*count=*/2, rect.x(), rect.y()); + sk_sp<SkShader> gradient = SkGradientShader::MakeLinear( + start_end, gradient_colors, positions, /*count=*/i, SkTileMode::kClamp); + current_canvas_->clipShader(std::move(gradient)); +} + void SkiaRenderer::PrepareCanvasForRPDQ(const DrawRPDQParams& rpdq_params, DrawQuadParams* params) { // Clip to the filter bounds prior to saving the layer, which has been @@ -1423,10 +1511,10 @@ // Determine final rounded rect clip geometry. We transform it from target // space to window space to make batching and canvas preparation easier // (otherwise we'd have to separate those two matrices in the CDT). - if (ShouldApplyRoundedCorner(quad)) { + if (ShouldApplyRoundedCorner(quad) || ShouldApplyGradientMask(quad)) { // Transform by the window and projection matrix to go from target to // device space, which should always be a scale+translate. - SkRRect corner_bounds = SkRRect( + SkRRect corner_bounds = static_cast<SkRRect>( quad->shared_quad_state->mask_filter_info.rounded_corner_bounds()); SkMatrix to_device; gfx::TransformToFlattenedSkMatrix(target_to_device, &to_device); @@ -1434,16 +1522,20 @@ // SkRRect::transform should always succeed here, since we know // corner_bounds is not empty and 'to_device' should just be scale+translate SkRRect device_bounds; - if (corner_bounds.transform(to_device, &device_bounds)) { - params.mask_filter_info.emplace( - gfx::MaskFilterInfo(gfx::RRectF(device_bounds))); - } else { + if (!corner_bounds.transform(to_device, &device_bounds)) { // TODO(crbug/1220004): We used to assert transform succeeded, but an // unreproduceable fuzzer test case could trip it. To be safe, and to // match the most likely scenario that the device transform has scale=0, // just force the clip to empty so we don't draw anything. - params.mask_filter_info.emplace( - gfx::MaskFilterInfo(gfx::RRectF(SkRRect::MakeEmpty()))); + params.mask_filter_info.emplace(gfx::RRectF(SkRRect::MakeEmpty())); + } else { + if (ShouldApplyGradientMask(quad)) { + params.mask_filter_info.emplace( + gfx::RRectF(device_bounds), + quad->shared_quad_state->mask_filter_info.gradient_mask().value()); + } else { + params.mask_filter_info.emplace(gfx::RRectF(device_bounds)); + } } } @@ -1625,6 +1717,9 @@ if (ShouldApplyRoundedCorner(quad)) return nullptr; + if (ShouldApplyGradientMask(quad)) + return nullptr; + // The quad type knows how to apply RPDQ filters, and the quad settings can // be merged into the RPDQs settings in CalculateBypassParams. return quad;
diff --git a/components/viz/service/display/skia_renderer.h b/components/viz/service/display/skia_renderer.h index 29e94c80..f941566 100644 --- a/components/viz/service/display/skia_renderer.h +++ b/components/viz/service/display/skia_renderer.h
@@ -20,6 +20,7 @@ #include "components/viz/service/viz_service_export.h" #include "third_party/skia/include/core/SkCanvas.h" #include "ui/gfx/color_conversion_sk_filter_cache.h" +#include "ui/gfx/geometry/mask_filter_info.h" #include "ui/latency/latency_info.h" class SkColorFilter; @@ -122,6 +123,8 @@ const absl::optional<gfx::Rect>& scissor_rect, const absl::optional<gfx::MaskFilterInfo>& mask_filter_info, const gfx::Transform* cdt); + void PrepareGradient( + const absl::optional<gfx::MaskFilterInfo>& mask_filter_info); // Further modify the canvas as needed to apply the effects represented by // |rpdq_params|. Call Prepare[Paint|Color]OrCanvasForRPDQ when possible,
diff --git a/components/viz/service/display_embedder/skia_output_device.cc b/components/viz/service/display_embedder/skia_output_device.cc index c9c31e7..579f759b 100644 --- a/components/viz/service/display_embedder/skia_output_device.cc +++ b/components/viz/service/display_embedder/skia_output_device.cc
@@ -15,7 +15,6 @@ #include "base/task/task_traits.h" #include "base/task/thread_pool.h" #include "base/task/thread_pool/thread_pool_instance.h" -#include "components/viz/service/display/dc_layer_overlay.h" #include "gpu/command_buffer/service/memory_tracking.h" #include "gpu/command_buffer/service/skia_utils.h" #include "services/tracing/public/cpp/perfetto/flow_event_utils.h" @@ -26,6 +25,10 @@ #include "ui/gfx/presentation_feedback.h" #include "ui/latency/latency_tracker.h" +#if BUILDFLAG(IS_WIN) +#include "components/viz/service/display/dc_layer_overlay.h" +#endif + namespace viz { namespace {
diff --git a/components/viz/service/display_embedder/skia_output_device_gl.cc b/components/viz/service/display_embedder/skia_output_device_gl.cc index 142f75d..8fc533f 100644 --- a/components/viz/service/display_embedder/skia_output_device_gl.cc +++ b/components/viz/service/display_embedder/skia_output_device_gl.cc
@@ -13,7 +13,6 @@ #include "build/build_config.h" #include "build/chromeos_buildflags.h" #include "components/viz/common/gpu/context_lost_reason.h" -#include "components/viz/service/display/dc_layer_overlay.h" #include "gpu/command_buffer/common/swap_buffers_complete_params.h" #include "gpu/command_buffer/service/feature_info.h" #include "gpu/command_buffer/service/gl_utils.h" @@ -38,6 +37,10 @@ #include "ui/gl/gl_utils.h" #include "ui/gl/gl_version_info.h" +#if BUILDFLAG(IS_WIN) +#include "components/viz/service/display/dc_layer_overlay.h" +#endif + namespace viz { namespace {
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc index 748baec..6b6625a 100644 --- a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc +++ b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
@@ -30,7 +30,6 @@ #include "components/viz/common/resources/resource_format_utils.h" #include "components/viz/common/skia_helper.h" #include "components/viz/common/viz_utils.h" -#include "components/viz/service/display/dc_layer_overlay.h" #include "components/viz/service/display/output_surface_frame.h" #include "components/viz/service/display/overlay_candidate.h" #include "components/viz/service/display_embedder/image_context_impl.h" @@ -81,6 +80,10 @@ #include "ui/gl/gl_fence.h" #include "ui/gl/gl_surface.h" +#if BUILDFLAG(IS_WIN) +#include "components/viz/service/display/dc_layer_overlay.h" +#endif + #if BUILDFLAG(ENABLE_VULKAN) #include "components/viz/service/display_embedder/skia_output_device_vulkan.h" #include "gpu/vulkan/vulkan_device_queue.h"
diff --git a/components/viz/service/gl/gpu_service_impl.cc b/components/viz/service/gl/gpu_service_impl.cc index 0e7303d7..d0e56cb3 100644 --- a/components/viz/service/gl/gpu_service_impl.cc +++ b/components/viz/service/gl/gpu_service_impl.cc
@@ -430,18 +430,16 @@ #endif #if BUILDFLAG(IS_WIN) - auto info_callback = - base::BindRepeating(&GpuServiceImpl::UpdateOverlayAndDXGIInfo, - weak_ptr_factory_.GetWeakPtr()); - gl::DirectCompositionSurfaceWin::SetOverlayHDRGpuInfoUpdateCallback( - info_callback); - if (media::SupportMediaFoundationClearPlayback()) { // Initialize the OverlayStateService using the GPUServiceImpl task // sequence. auto* overlay_state_service = OverlayStateService::GetInstance(); overlay_state_service->Initialize(base::SequencedTaskRunnerHandle::Get()); } + + // Add GpuServiceImpl to DirectCompositionOverlayCapsMonitor observer list for + // overlay and DXGI info update. + gl::DirectCompositionOverlayCapsMonitor::GetInstance()->AddObserver(this); #endif gpu_memory_buffer_factory_ = @@ -461,6 +459,10 @@ if (!in_host_process()) GetLogMessageManager()->ShutdownLogging(); +#if BUILDFLAG(IS_WIN) + gl::DirectCompositionOverlayCapsMonitor::GetInstance()->RemoveObserver(this); +#endif + // Destroy the receiver on the IO thread. { base::WaitableEvent wait; @@ -1339,7 +1341,8 @@ } #if BUILDFLAG(IS_WIN) -void GpuServiceImpl::UpdateOverlayAndDXGIInfo() { +// Update Overlay and DXGI Info +void GpuServiceImpl::OnOverlayCapsChanged() { gpu::OverlayInfo old_overlay_info = gpu_info_.overlay_info; gpu::CollectHardwareOverlayInfo(&gpu_info_.overlay_info);
diff --git a/components/viz/service/gl/gpu_service_impl.h b/components/viz/service/gl/gpu_service_impl.h index 2bf9cc1..9139bb64 100644 --- a/components/viz/service/gl/gpu_service_impl.h +++ b/components/viz/service/gl/gpu_service_impl.h
@@ -48,6 +48,10 @@ #include "ui/gfx/gpu_extra_info.h" #include "ui/gfx/native_widget_types.h" +#if BUILDFLAG(IS_WIN) +#include "ui/gl/direct_composition_surface_win.h" +#endif + #if BUILDFLAG(IS_CHROMEOS_ASH) namespace arc { class ProtectedBufferManager; @@ -85,8 +89,12 @@ // This runs in the GPU process, and communicates with the gpu host (which is // the window server) over the mojom APIs. This is responsible for setting up // the connection to clients, allocating/free'ing gpu memory etc. -class VIZ_SERVICE_EXPORT GpuServiceImpl : public gpu::GpuChannelManagerDelegate, - public mojom::GpuService { +class VIZ_SERVICE_EXPORT GpuServiceImpl + : public gpu::GpuChannelManagerDelegate, +#if BUILDFLAG(IS_WIN) + public gl::DirectCompositionOverlayCapsObserver, +#endif + public mojom::GpuService { public: GpuServiceImpl(const gpu::GPUInfo& gpu_info, std::unique_ptr<gpu::GpuWatchdogThread> watchdog, @@ -248,6 +256,11 @@ #if BUILDFLAG(IS_WIN) void SendCreatedChildWindow(gpu::SurfaceHandle parent_window, gpu::SurfaceHandle child_window) override; + + // DirectCompositionOverlayCapsObserver implementation. + // Update overlay info and HDR status on the GPU process and send the updated + // info back to the browser process if there is a change. + void OnOverlayCapsChanged() override; #endif // Installs a base::LogMessageHandlerFunction which ensures messages are sent
diff --git a/components/viz/test/data/linear_gradient_render_pass.png b/components/viz/test/data/linear_gradient_render_pass.png new file mode 100644 index 0000000..3725d53 --- /dev/null +++ b/components/viz/test/data/linear_gradient_render_pass.png Binary files differ
diff --git a/components/viz/test/data/multi_linear_gradient_render_pass.png b/components/viz/test/data/multi_linear_gradient_render_pass.png new file mode 100644 index 0000000..ebd4829 --- /dev/null +++ b/components/viz/test/data/multi_linear_gradient_render_pass.png Binary files differ
diff --git a/content/app/content_main_runner_impl.cc b/content/app/content_main_runner_impl.cc index 88e46d8..ed19f7f 100644 --- a/content/app/content_main_runner_impl.cc +++ b/content/app/content_main_runner_impl.cc
@@ -815,11 +815,12 @@ base::FetchAndCacheSystemInfo(); #endif - int exit_code = 0; if (!GetContentClient()) ContentClientCreator::Create(delegate_); - if (delegate_->BasicStartupComplete(&exit_code)) - return exit_code; + absl::optional<int> basic_startup_exit_code = + delegate_->BasicStartupComplete(); + if (basic_startup_exit_code.has_value()) + return basic_startup_exit_code.value(); completed_basic_startup_ = true; const base::CommandLine& command_line = @@ -1089,7 +1090,11 @@ const bool has_thread_pool = GetContentClient()->browser()->CreateThreadPool("Browser"); - delegate_->PreBrowserMain(); + absl::optional<int> pre_browser_main_exit_code = + delegate_->PreBrowserMain(); + if (pre_browser_main_exit_code.has_value()) + return pre_browser_main_exit_code.value(); + #if BUILDFLAG(IS_WIN) if (l10n_util::GetLocaleOverrides().empty()) { // Override the configured locale with the user's preferred UI language. @@ -1111,7 +1116,10 @@ variations::VariationsIdsProvider::Mode::kUseSignedInState); } - delegate_->PostEarlyInitialization(invoked_in_browser); + absl::optional<int> post_early_initialization_exit_code = + delegate_->PostEarlyInitialization(invoked_in_browser); + if (post_early_initialization_exit_code.has_value()) + return post_early_initialization_exit_code.value(); // The hang watcher needs to be started once the feature list is available // but before the IO thread is started.
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn index 1969237..2f97246 100644 --- a/content/browser/BUILD.gn +++ b/content/browser/BUILD.gn
@@ -1777,6 +1777,8 @@ "renderer_host/render_widget_host_view_child_frame.h", "renderer_host/render_widget_targeter.cc", "renderer_host/render_widget_targeter.h", + "renderer_host/renderer_cancellation_throttle.cc", + "renderer_host/renderer_cancellation_throttle.h", "renderer_host/renderer_sandboxed_process_launcher_delegate.cc", "renderer_host/renderer_sandboxed_process_launcher_delegate.h", "renderer_host/should_swap_browsing_instance.h",
diff --git a/content/browser/accessibility/browser_accessibility_cocoa.mm b/content/browser/accessibility/browser_accessibility_cocoa.mm index fdfd9a0..27d8447f 100644 --- a/content/browser/accessibility/browser_accessibility_cocoa.mm +++ b/content/browser/accessibility/browser_accessibility_cocoa.mm
@@ -31,6 +31,7 @@ #include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/blink/public/strings/grit/blink_strings.h" #include "third_party/skia/include/core/SkColor.h" +#include "ui/accessibility/ax_common.h" #include "ui/accessibility/ax_enum_util.h" #include "ui/accessibility/ax_range.h" #include "ui/accessibility/ax_role_properties.h" @@ -1084,8 +1085,12 @@ // Hook back up to RenderWidgetHostViewCocoa. BrowserAccessibilityManagerMac* manager = _owner->manager()->GetRootManager()->ToBrowserAccessibilityManagerMac(); - CHECK(manager); - DCHECK(manager->GetParentView()); + if (!manager) { + // TODO(accessibility) Determine why this is happening. + SANITIZER_NOTREACHED(); + return nil; + } + SANITIZER_CHECK(manager->GetParentView()); return manager->GetParentView(); }
diff --git a/content/browser/accessibility/render_accessibility_host.cc b/content/browser/accessibility/render_accessibility_host.cc index b56ddc9..5be0325 100644 --- a/content/browser/accessibility/render_accessibility_host.cc +++ b/content/browser/accessibility/render_accessibility_host.cc
@@ -16,10 +16,8 @@ RenderAccessibilityHost::RenderAccessibilityHost( base::WeakPtr<RenderFrameHostImpl> render_frame_host_impl, - mojo::PendingReceiver<blink::mojom::RenderAccessibilityHost> receiver, ui::AXTreeID tree_id) : render_frame_host_impl_(std::move(render_frame_host_impl)), - receiver_{this, std::move(receiver)}, tree_id_(tree_id) {} RenderAccessibilityHost::~RenderAccessibilityHost() = default;
diff --git a/content/browser/accessibility/render_accessibility_host.h b/content/browser/accessibility/render_accessibility_host.h index 1458192..07c0ece 100644 --- a/content/browser/accessibility/render_accessibility_host.h +++ b/content/browser/accessibility/render_accessibility_host.h
@@ -10,7 +10,7 @@ #include "base/memory/weak_ptr.h" #include "content/public/browser/global_routing_id.h" #include "mojo/public/cpp/bindings/pending_receiver.h" -#include "mojo/public/cpp/bindings/receiver.h" +#include "mojo/public/cpp/bindings/receiver_set.h" #include "mojo/public/cpp/bindings/self_owned_receiver.h" #include "third_party/blink/public/mojom/render_accessibility.mojom.h" @@ -39,9 +39,13 @@ public: RenderAccessibilityHost( base::WeakPtr<RenderFrameHostImpl> render_frame_host_impl, - mojo::PendingReceiver<blink::mojom::RenderAccessibilityHost> receiver, ui::AXTreeID tree_id); + void Bind( + mojo::PendingReceiver<blink::mojom::RenderAccessibilityHost> receiver) { + receiver_.Add(this, std::move(receiver)); + } + RenderAccessibilityHost(const RenderAccessibilityHost&) = delete; RenderAccessibilityHost& operator=(const RenderAccessibilityHost&) = delete; @@ -56,7 +60,9 @@ private: base::WeakPtr<RenderFrameHostImpl> render_frame_host_impl_; - mojo::Receiver<blink::mojom::RenderAccessibilityHost> receiver_; + // TODO(chrishtr): change this back to a Receiver once all render process + /// callsites of this mojo interface have been migrated to Blink. + mojo::ReceiverSet<blink::mojom::RenderAccessibilityHost> receiver_; const ui::AXTreeID tree_id_; };
diff --git a/content/browser/android/dialog_overlay_impl.cc b/content/browser/android/dialog_overlay_impl.cc index ba46167..0eb14562 100644 --- a/content/browser/android/dialog_overlay_impl.cc +++ b/content/browser/android/dialog_overlay_impl.cc
@@ -128,8 +128,7 @@ // changes only. if (auto* window = web_contents()->GetNativeView()->GetWindowAndroid()) { RegisterWindowObserverIfNeeded(window); - ScopedJavaLocalRef<jobject> token = window->GetWindowToken(); - Java_DialogOverlayImpl_onWindowToken(env, obj, token); + Java_DialogOverlayImpl_onWindowAndroid(env, obj, window->GetJavaObject()); } // Pass up a reference to the container view so we can observe its location. @@ -243,15 +242,13 @@ DCHECK_CURRENTLY_ON(BrowserThread::UI); JNIEnv* env = AttachCurrentThread(); - ScopedJavaLocalRef<jobject> token; - - if (auto* window = web_contents()->GetNativeView()->GetWindowAndroid()) { + auto* window = web_contents()->GetNativeView()->GetWindowAndroid(); + if (window) RegisterWindowObserverIfNeeded(window); - token = window->GetWindowToken(); - } + ScopedJavaLocalRef<jobject> obj = obj_.get(env); if (!obj.is_null()) - Java_DialogOverlayImpl_onWindowToken(env, obj, token); + Java_DialogOverlayImpl_onWindowAndroid(env, obj, window->GetJavaObject()); StartObservingContainerView(); } @@ -260,7 +257,7 @@ JNIEnv* env = AttachCurrentThread(); ScopedJavaLocalRef<jobject> obj = obj_.get(env); if (!obj.is_null()) - Java_DialogOverlayImpl_onWindowToken(env, obj, nullptr); + Java_DialogOverlayImpl_onWindowAndroid(env, obj, nullptr); Stop(); }
diff --git a/content/browser/attribution_reporting/attribution_filter_data.cc b/content/browser/attribution_reporting/attribution_filter_data.cc index 3bc896c..2ed65b2 100644 --- a/content/browser/attribution_reporting/attribution_filter_data.cc +++ b/content/browser/attribution_reporting/attribution_filter_data.cc
@@ -81,12 +81,12 @@ // static absl::optional<AttributionFilterData> AttributionFilterData::FromSourceJSON( - base::Value* value) { + base::Value* input_value) { // TODO(johnidel): Consider logging registration JSON metrics here. - if (!value) + if (!input_value) return AttributionFilterData(); - base::Value::Dict* dict = value->GetIfDict(); + base::Value::Dict* dict = input_value->GetIfDict(); if (!dict) return absl::nullopt; @@ -115,8 +115,8 @@ std::vector<std::string> values; values.reserve(num_values); - for (base::Value& value : *list) { - std::string* string = value.GetIfString(); + for (base::Value& item : *list) { + std::string* string = item.GetIfString(); if (!string) return absl::nullopt;
diff --git a/content/browser/attribution_reporting/attribution_filter_data.h b/content/browser/attribution_reporting/attribution_filter_data.h index 94fc3418..7f7409a7 100644 --- a/content/browser/attribution_reporting/attribution_filter_data.h +++ b/content/browser/attribution_reporting/attribution_filter_data.h
@@ -37,19 +37,20 @@ // Source filter data is not allowed to contain a `source_type` filter. static absl::optional<AttributionFilterData> FromSourceFilterValues( - FilterValues&&); + FilterValues&& filter_values); // Trigger filter data is allowed to contain a `source_type` filter. static absl::optional<AttributionFilterData> FromTriggerFilterValues( - FilterValues&&); + FilterValues&& filter_values); - static absl::optional<AttributionFilterData> FromSourceJSON(base::Value*); + static absl::optional<AttributionFilterData> FromSourceJSON( + base::Value* input_value); // Returns filter data that matches only the given source type. - static AttributionFilterData ForSourceType(AttributionSourceType); + static AttributionFilterData ForSourceType(AttributionSourceType source_type); // Creates without validation. - static AttributionFilterData CreateForTesting(FilterValues); + static AttributionFilterData CreateForTesting(FilterValues filter_values); AttributionFilterData();
diff --git a/content/browser/attribution_reporting/attribution_storage_sql.cc b/content/browser/attribution_reporting/attribution_storage_sql.cc index ab93be9..9e03c5b 100644 --- a/content/browser/attribution_reporting/attribution_storage_sql.cc +++ b/content/browser/attribution_reporting/attribution_storage_sql.cc
@@ -22,6 +22,7 @@ #include "base/memory/raw_ptr.h" #include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" +#include "base/notreached.h" #include "base/numerics/checked_math.h" #include "base/ranges/algorithm.h" #include "base/time/time.h" @@ -58,11 +59,11 @@ namespace content { // Version number of the database. -const int AttributionStorageSql::kCurrentVersionNumber = 34; +const int AttributionStorageSql::kCurrentVersionNumber = 35; // Earliest version which can use a |kCurrentVersionNumber| database // without failing. -const int AttributionStorageSql::kCompatibleVersionNumber = 34; +const int AttributionStorageSql::kCompatibleVersionNumber = 35; // Latest version of the database that cannot be upgraded to // |kCurrentVersionNumber| without razing the database. @@ -373,6 +374,49 @@ return user_data_directory.Append(kDatabasePath); } +// These values are persisted to logs. Entries should not be renumbered and +// numeric values should never be reused. +enum class DestinationLimitResult { + kAllowedByPendingAllowedByUnexpired = 0, + kAllowedByPendingDroppedByUnexpired = 1, + kDroppedByPendingAllowedByUnexpired = 2, + kDroppedByPendingDroppedByUnexpired = 3, + kError = 4, + + kMaxValue = kError, +}; + +DestinationLimitResult GetDestinationLimitResult( + RateLimitResult pending_sources_limit, + RateLimitResult unexpired_sources_limit) { + switch (pending_sources_limit) { + case RateLimitResult::kAllowed: { + switch (unexpired_sources_limit) { + case RateLimitResult::kAllowed: + return DestinationLimitResult::kAllowedByPendingAllowedByUnexpired; + case RateLimitResult::kNotAllowed: + return DestinationLimitResult::kAllowedByPendingDroppedByUnexpired; + case RateLimitResult::kError: + return DestinationLimitResult::kError; + } + } + case RateLimitResult::kNotAllowed: { + switch (unexpired_sources_limit) { + case RateLimitResult::kAllowed: + // Unexpired sources limit is stricter than pending sources limit. + NOTREACHED(); + return DestinationLimitResult::kDroppedByPendingAllowedByUnexpired; + case RateLimitResult::kNotAllowed: + return DestinationLimitResult::kDroppedByPendingDroppedByUnexpired; + case RateLimitResult::kError: + return DestinationLimitResult::kError; + } + } + case RateLimitResult::kError: + return DestinationLimitResult::kError; + } +} + } // namespace // static @@ -504,9 +548,26 @@ StorableSource::Result::kInsufficientSourceCapacity); } - if (!HasCapacityForUniqueDestinationLimitForPendingSource(source)) { - return StoreSourceResult( - StorableSource::Result::kInsufficientUniqueDestinationCapacity); + RateLimitResult unexpired_sources_destination_limit = + rate_limit_table_.SourceAllowedForDestinationLimit(db_.get(), source); + RateLimitResult pending_sources_destination_limit = + HasCapacityForUniqueDestinationLimitForPendingSource(source); + + // For now we only record metrics on this limit to measure how it performs + // compared to the pending sources limit. + base::UmaHistogramEnumeration( + "Conversions.UniqueDestinationLimitForUnexpiredSourcesResult", + GetDestinationLimitResult(pending_sources_destination_limit, + unexpired_sources_destination_limit)); + + switch (pending_sources_destination_limit) { + case RateLimitResult::kAllowed: + break; + case RateLimitResult::kNotAllowed: + return StoreSourceResult( + StorableSource::Result::kInsufficientUniqueDestinationCapacity); + case RateLimitResult::kError: + return StoreSourceResult(StorableSource::Result::kInternalError); } switch (rate_limit_table_.SourceAllowedForReportingOriginLimit(db_.get(), @@ -2286,9 +2347,9 @@ db_init_status_ = DbStatus::kClosed; } -bool AttributionStorageSql:: - HasCapacityForUniqueDestinationLimitForPendingSource( - const StorableSource& source) { +RateLimitResult +AttributionStorageSql::HasCapacityForUniqueDestinationLimitForPendingSource( + const StorableSource& source) { const int max = delegate_->GetMaxDestinationsPerSourceSiteReportingOrigin(); // TODO(apaseltiner): We could just make // `GetMaxDestinationsPerSourceSiteReportingOrigin()` return `size_t`, but it @@ -2319,15 +2380,16 @@ // The destination isn't new, so it doesn't change the count. if (destination == serialized_conversion_destination) - return true; + return RateLimitResult::kAllowed; destinations.insert(std::move(destination)); if (destinations.size() == static_cast<size_t>(max)) - return false; + return RateLimitResult::kNotAllowed; } - return statement.Succeeded(); + return statement.Succeeded() ? RateLimitResult::kAllowed + : RateLimitResult::kError; } bool AttributionStorageSql::DeleteSources(
diff --git a/content/browser/attribution_reporting/attribution_storage_sql.h b/content/browser/attribution_reporting/attribution_storage_sql.h index 88bded6..8457491f 100644 --- a/content/browser/attribution_reporting/attribution_storage_sql.h +++ b/content/browser/attribution_reporting/attribution_storage_sql.h
@@ -198,7 +198,8 @@ absl::optional<std::vector<uint64_t>> ReadDedupKeys( StoredSource::Id source_id) VALID_CONTEXT_REQUIRED(sequence_checker_); - [[nodiscard]] bool HasCapacityForUniqueDestinationLimitForPendingSource( + [[nodiscard]] RateLimitResult + HasCapacityForUniqueDestinationLimitForPendingSource( const StorableSource& source) VALID_CONTEXT_REQUIRED(sequence_checker_); [[nodiscard]] absl::optional<AttributionReport::EventLevelData::Id>
diff --git a/content/browser/attribution_reporting/attribution_storage_sql_migrations.cc b/content/browser/attribution_reporting/attribution_storage_sql_migrations.cc index e1befa0..3298c09 100644 --- a/content/browser/attribution_reporting/attribution_storage_sql_migrations.cc +++ b/content/browser/attribution_reporting/attribution_storage_sql_migrations.cc
@@ -7,8 +7,11 @@ #include "base/check.h" #include "base/metrics/histogram_functions.h" #include "base/time/time.h" +#include "content/browser/attribution_reporting/common_source_info.h" +#include "content/browser/attribution_reporting/rate_limit_table.h" #include "sql/database.h" #include "sql/meta_table.h" +#include "sql/statement.h" #include "sql/transaction.h" namespace content { @@ -90,6 +93,115 @@ return transaction.Commit(); } +bool MigrateToVersion35(sql::Database* db, sql::MetaTable* meta_table) { + // Wrap each migration in its own transaction. See comment in + // `MigrateToVersion34`. + sql::Transaction transaction(db); + if (!transaction.Begin()) + return false; + + static constexpr char kNewRateLimitsTableSql[] = + "CREATE TABLE IF NOT EXISTS new_rate_limits" + "(id INTEGER PRIMARY KEY NOT NULL," + "scope INTEGER NOT NULL," + "source_id INTEGER NOT NULL," + "source_site TEXT NOT NULL," + "source_origin TEXT NOT NULL," + "destination_site TEXT NOT NULL," + "destination_origin TEXT NOT NULL," + "reporting_origin TEXT NOT NULL," + "time INTEGER NOT NULL," + "expiry_time INTEGER NOT NULL)"; + if (!db->Execute(kNewRateLimitsTableSql)) + return false; + + // Transfer the existing rows to the new table, inserting `base::Time()` + // as default values for the expiry_time column. + static constexpr char kPopulateNewRateLimitsTableSql[] = + "INSERT INTO new_rate_limits SELECT " + "id,scope,source_id,source_site,source_origin,destination_site," + "destination_origin,reporting_origin,time,0 " + "FROM rate_limits"; + if (!db->Execute(kPopulateNewRateLimitsTableSql)) + return false; + + static constexpr char kDropOldRateLimitsTableSql[] = "DROP TABLE rate_limits"; + if (!db->Execute(kDropOldRateLimitsTableSql)) + return false; + + static constexpr char kRenameRateLimitsTableSql[] = + "ALTER TABLE new_rate_limits RENAME TO rate_limits"; + if (!db->Execute(kRenameRateLimitsTableSql)) + return false; + + // Update the expiry_time column for the existing source rows. + static constexpr char kUpdateSourceExpiryTimeSql[] = + "UPDATE rate_limits SET expiry_time=? WHERE id=?"; + sql::Statement update_source_expiry_time_statement( + db->GetUniqueStatement(kUpdateSourceExpiryTimeSql)); + + static_assert(static_cast<int>(RateLimitTable::Scope::kSource) == 0, + "update `scope=0` clause below"); + + static constexpr char kGetRateLimitsSql[] = + "SELECT R.id,R.time,I.expiry_time " + "FROM rate_limits R " + "LEFT JOIN sources I ON R.source_id=I.source_id " + "WHERE R.scope=0 " + "ORDER BY R.id"; + sql::Statement get_rate_limits_statement( + db->GetUniqueStatement(kGetRateLimitsSql)); + while (get_rate_limits_statement.Step()) { + base::Time source_expiry_time; + if (get_rate_limits_statement.GetColumnType(2) == sql::ColumnType::kNull) { + // Use maximum expiry time if there's no matching source. + source_expiry_time = get_rate_limits_statement.ColumnTime(1) + + kDefaultAttributionSourceExpiry; + } else { + source_expiry_time = get_rate_limits_statement.ColumnTime(2); + } + + update_source_expiry_time_statement.Reset(/*clear_bound_vars=*/true); + + update_source_expiry_time_statement.BindTime(0, source_expiry_time); + update_source_expiry_time_statement.BindInt64( + 1, get_rate_limits_statement.ColumnInt64(0)); + if (!update_source_expiry_time_statement.Run()) + return false; + } + + if (!get_rate_limits_statement.Succeeded()) + return false; + + // Create the rate_limits table indices on the new table. + static constexpr char kRateLimitSourceSiteReportingOriginIndexSql[] = + "CREATE INDEX IF NOT EXISTS rate_limit_source_site_reporting_origin_idx " + "ON rate_limits" + "(scope,source_site,reporting_origin)"; + if (!db->Execute(kRateLimitSourceSiteReportingOriginIndexSql)) + return false; + + static constexpr char kRateLimitReportingOriginIndexSql[] = + "CREATE INDEX IF NOT EXISTS rate_limit_reporting_origin_idx " + "ON rate_limits(scope,destination_site,source_site)"; + if (!db->Execute(kRateLimitReportingOriginIndexSql)) + return false; + + static constexpr char kRateLimitTimeIndexSql[] = + "CREATE INDEX IF NOT EXISTS rate_limit_time_idx ON rate_limits(time)"; + if (!db->Execute(kRateLimitTimeIndexSql)) + return false; + + static constexpr char kRateLimitImpressionIdIndexSql[] = + "CREATE INDEX IF NOT EXISTS rate_limit_source_id_idx " + "ON rate_limits(source_id)"; + if (!db->Execute(kRateLimitImpressionIdIndexSql)) + return false; + + meta_table->SetVersionNumber(35); + return transaction.Commit(); +} + } // namespace bool UpgradeAttributionStorageSqlSchema(sql::Database* db, @@ -103,6 +215,10 @@ if (!MigrateToVersion34(db, meta_table)) return false; } + if (meta_table->GetVersionNumber() == 34) { + if (!MigrateToVersion35(db, meta_table)) + return false; + } // Add similar if () blocks for new versions here. base::UmaHistogramMediumTimes("Conversions.Storage.MigrationTime",
diff --git a/content/browser/attribution_reporting/attribution_storage_sql_migrations_unittest.cc b/content/browser/attribution_reporting/attribution_storage_sql_migrations_unittest.cc index 9ffca1a..330efa9b 100644 --- a/content/browser/attribution_reporting/attribution_storage_sql_migrations_unittest.cc +++ b/content/browser/attribution_reporting/attribution_storage_sql_migrations_unittest.cc
@@ -236,4 +236,58 @@ histograms.ExpectTotalCount("Conversions.Storage.MigrationTime", 1); } +TEST_F(AttributionStorageSqlMigrationsTest, MigrateVersion34ToCurrent) { + base::HistogramTester histograms; + LoadDatabase(GetVersionFilePath(34), DbPath()); + + // Verify pre-conditions. + { + sql::Database db; + ASSERT_TRUE(db.Open(DbPath())); + ASSERT_FALSE(db.DoesColumnExist("rate_limits", "expiry_time")); + + sql::Statement s(db.GetUniqueStatement("SELECT * FROM rate_limits")); + + ASSERT_TRUE(s.Step()); + ASSERT_EQ(9, s.ColumnInt64(8)); // time + ASSERT_TRUE(s.Step()); + ASSERT_EQ(9, s.ColumnInt64(8)); // time + ASSERT_TRUE(s.Step()); + ASSERT_EQ(9, s.ColumnInt64(8)); // time + ASSERT_FALSE(s.Step()); + } + + MigrateDatabase(); + + // Verify schema is current. + { + sql::Database db; + ASSERT_TRUE(db.Open(DbPath())); + + // Check version. + EXPECT_EQ(AttributionStorageSql::kCurrentVersionNumber, + VersionFromDatabase(&db)); + + // Compare without quotes as sometimes migrations cause table names to be + // string literals. + EXPECT_EQ(RemoveQuotes(GetCurrentSchema()), RemoveQuotes(db.GetSchema())); + + // Verify that data is preserved across the migration. + sql::Statement s(db.GetUniqueStatement("SELECT * FROM rate_limits")); + + ASSERT_TRUE(s.Step()); + ASSERT_EQ(7, s.ColumnInt64(9)); // expiry_time with matching source + ASSERT_TRUE(s.Step()); + EXPECT_EQ(9 + base::Days(30).InMicroseconds(), + s.ColumnInt64(9)); // expiry_time without matching source + ASSERT_TRUE(s.Step()); + EXPECT_EQ(0, s.ColumnInt64(9)); // expiry_time for attribution + ASSERT_FALSE(s.Step()); + } + + // DB creation histograms should be recorded. + histograms.ExpectTotalCount("Conversions.Storage.CreationTime", 0); + histograms.ExpectTotalCount("Conversions.Storage.MigrationTime", 1); +} + } // namespace content
diff --git a/content/browser/attribution_reporting/attribution_storage_sql_unittest.cc b/content/browser/attribution_reporting/attribution_storage_sql_unittest.cc index c46e7d7..69baf96b94 100644 --- a/content/browser/attribution_reporting/attribution_storage_sql_unittest.cc +++ b/content/browser/attribution_reporting/attribution_storage_sql_unittest.cc
@@ -227,11 +227,11 @@ // [conversion_domain_idx], [impression_expiry_idx], // [impression_origin_idx], [impression_site_idx], // [conversion_report_time_idx], [conversion_impression_id_idx], - // [rate_limit_attribution_idx], [rate_limit_reporting_origin_idx], - // [rate_limit_time_idx], [rate_limit_impression_id_idx], - // [aggregate_source_id_idx], [aggregate_trigger_time_idx], - // [aggregate_report_time_idx], [contribution_aggregation_id_idx] and - // the meta table index. + // [rate_limit_source_site_reporting_origin_idx], + // [rate_limit_reporting_origin_idx], [rate_limit_time_idx], + // [rate_limit_impression_id_idx], [aggregate_source_id_idx], + // [aggregate_trigger_time_idx], [aggregate_report_time_idx], + // [contribution_aggregation_id_idx] and the meta table index. EXPECT_EQ(15u, sql::test::CountSQLIndices(&raw_db)); } }
diff --git a/content/browser/attribution_reporting/attribution_storage_unittest.cc b/content/browser/attribution_reporting/attribution_storage_unittest.cc index b6f0177..f3775ca9 100644 --- a/content/browser/attribution_reporting/attribution_storage_unittest.cc +++ b/content/browser/attribution_reporting/attribution_storage_unittest.cc
@@ -22,6 +22,7 @@ #include "base/memory/raw_ptr.h" #include "base/ranges/algorithm.h" #include "base/strings/stringprintf.h" +#include "base/test/metrics/histogram_tester.h" #include "base/test/task_environment.h" #include "base/time/time.h" #include "content/browser/attribution_reporting/aggregatable_histogram_contribution.h" @@ -37,6 +38,7 @@ #include "content/browser/attribution_reporting/attribution_trigger.h" #include "content/browser/attribution_reporting/attribution_utils.h" #include "content/browser/attribution_reporting/common_source_info.h" +#include "content/browser/attribution_reporting/rate_limit_result.h" #include "content/browser/attribution_reporting/storable_source.h" #include "content/browser/attribution_reporting/stored_source.h" #include "content/public/browser/storage_partition.h" @@ -1112,6 +1114,66 @@ EXPECT_THAT(storage()->GetActiveSources(), SizeIs(6)); } +TEST_F(AttributionStorageTest, DestinationLimitResultMetric) { + base::HistogramTester histograms; + + delegate()->set_max_destinations_per_source_site_reporting_origin(1); + delegate()->set_delete_expired_sources_frequency(base::Milliseconds(10)); + + const base::TimeDelta expiry = base::Milliseconds(5); + + const auto store_source = [&](const char* impression_origin, + const char* reporting_origin, + const char* destination_origin) { + return storage() + ->StoreSource( + SourceBuilder() + .SetImpressionOrigin( + url::Origin::Create(GURL(impression_origin))) + .SetReportingOrigin(url::Origin::Create(GURL(reporting_origin))) + .SetConversionOrigin( + url::Origin::Create(GURL(destination_origin))) + .SetExpiry(expiry) + .Build()) + .status; + }; + + // Allowed by pending, allowed by unexpired. + store_source("https://s.test", "https://a.r.test", "https://d1.test"); + + // Dropped by pending, dropped by expired. + store_source("https://s.test", "https://a.r.test", "https://d2.test"); + + EXPECT_EQ( + AttributionTrigger::EventLevelResult::kSuccess, + MaybeCreateAndStoreEventLevelReport( + TriggerBuilder() + .SetReportingOrigin(url::Origin::Create(GURL("https://a.r.test"))) + .SetDestinationOrigin( + url::Origin::Create(GURL("https://d1.test"))) + .Build())); + + // Allowed by pending, dropped by unexpired (but still stored). + store_source("https://s.test", "https://a.r.test", "https://d2.test"); + + task_environment_.FastForwardBy(expiry); + + // Allowed by pending, allowed by unexpired. + store_source("https://s.test", "https://a.r.test", "https://d3.test"); + + static constexpr char kMetric[] = + "Conversions.UniqueDestinationLimitForUnexpiredSourcesResult"; + + // kAllowedByPendingAllowedByUnexpired = 0 + histograms.ExpectBucketCount(kMetric, 0, 2); + + // kAllowedByPendingDroppedByUnexpired = 1 + histograms.ExpectBucketCount(kMetric, 1, 1); + + // kDroppedByPendingDroppedByUnexpired = 3 + histograms.ExpectBucketCount(kMetric, 3, 1); +} + TEST_F(AttributionStorageTest, MaxAttributionDestinationsPerSource_AppliesToNavigationSources) { delegate()->set_max_destinations_per_source_site_reporting_origin(1);
diff --git a/content/browser/attribution_reporting/common_source_info.cc b/content/browser/attribution_reporting/common_source_info.cc index 8f86a531..a7c03d1 100644 --- a/content/browser/attribution_reporting/common_source_info.cc +++ b/content/browser/attribution_reporting/common_source_info.cc
@@ -18,10 +18,10 @@ base::Time impression_time, AttributionSourceType source_type) { constexpr base::TimeDelta kMinImpressionExpiry = base::Days(1); - constexpr base::TimeDelta kDefaultImpressionExpiry = base::Days(30); // Default to the maximum expiry time. - base::TimeDelta expiry = declared_expiry.value_or(kDefaultImpressionExpiry); + base::TimeDelta expiry = + declared_expiry.value_or(kDefaultAttributionSourceExpiry); // Expiry time for event sources must be a whole number of days. if (source_type == AttributionSourceType::kEvent) @@ -29,8 +29,8 @@ // If the impression specified its own expiry, clamp it to the minimum and // maximum. - return impression_time + - base::clamp(expiry, kMinImpressionExpiry, kDefaultImpressionExpiry); + return impression_time + base::clamp(expiry, kMinImpressionExpiry, + kDefaultAttributionSourceExpiry); } CommonSourceInfo::CommonSourceInfo(uint64_t source_event_id,
diff --git a/content/browser/attribution_reporting/common_source_info.h b/content/browser/attribution_reporting/common_source_info.h index 9ac91c3ca..fd5e420 100644 --- a/content/browser/attribution_reporting/common_source_info.h +++ b/content/browser/attribution_reporting/common_source_info.h
@@ -21,6 +21,8 @@ namespace content { +constexpr base::TimeDelta kDefaultAttributionSourceExpiry = base::Days(30); + // Contains common attributes of `StorableSource` and `StoredSource`. class CONTENT_EXPORT CommonSourceInfo { public:
diff --git a/content/browser/attribution_reporting/rate_limit_table.cc b/content/browser/attribution_reporting/rate_limit_table.cc index 24cf76b..32904e92 100644 --- a/content/browser/attribution_reporting/rate_limit_table.cc +++ b/content/browser/attribution_reporting/rate_limit_table.cc
@@ -49,6 +49,9 @@ // |reporting_origin| is the reporting origin of the impression/conversion. // |time| is the time of either the source registration or the attribution // trigger, depending on |scope|. + // |expiry_time| is only meaningful when |scope| is + // `RateLimitTable::Scope::kSource` and contains the source's expiry time, + // otherwise it is set to `base::Time()`. static constexpr char kRateLimitTableSql[] = "CREATE TABLE IF NOT EXISTS rate_limits" "(id INTEGER PRIMARY KEY NOT NULL," @@ -59,25 +62,26 @@ "destination_site TEXT NOT NULL," "destination_origin TEXT NOT NULL," "reporting_origin TEXT NOT NULL," - "time INTEGER NOT NULL)"; + "time INTEGER NOT NULL," + "expiry_time INTEGER NOT NULL)"; if (!db->Execute(kRateLimitTableSql)) return false; static_assert(static_cast<int>(Scope::kAttribution) == 1, "update `scope=1` clause below"); - // Optimizes calls to |AttributionAllowedForAttributionLimit()|. - static constexpr char kRateLimitAttributionIndexSql[] = - "CREATE INDEX IF NOT EXISTS rate_limit_attribution_idx ON rate_limits" - "(destination_site,source_site,reporting_origin,time)" - "WHERE scope=1"; - if (!db->Execute(kRateLimitAttributionIndexSql)) + // Optimizes calls to `SourceAllowedForDestinationLimit()`. + static constexpr char kRateLimitSourceSiteReportingOriginIndexSql[] = + "CREATE INDEX IF NOT EXISTS rate_limit_source_site_reporting_origin_idx " + "ON rate_limits(scope,source_site,reporting_origin)"; + if (!db->Execute(kRateLimitSourceSiteReportingOriginIndexSql)) return false; - // Optimizes calls to |AllowedForReportingOriginLimit()|. + // Optimizes calls to `AllowedForReportingOriginLimit()` and + // `AttributionAllowedForAttributionLimit()`. static constexpr char kRateLimitReportingOriginIndexSql[] = "CREATE INDEX IF NOT EXISTS rate_limit_reporting_origin_idx " - "ON rate_limits(scope,destination_site,source_site,time)"; + "ON rate_limits(scope,destination_site,source_site)"; if (!db->Execute(kRateLimitReportingOriginIndexSql)) return false; @@ -128,11 +132,21 @@ last_cleared_ = now; } + base::Time expiry_time; + switch (scope) { + case Scope::kSource: + expiry_time = common_info.expiry_time(); + break; + case Scope::kAttribution: + expiry_time = base::Time(); + break; + } + static constexpr char kStoreRateLimitSql[] = "INSERT INTO rate_limits" "(scope,source_id,source_site,source_origin," - "destination_site,destination_origin,reporting_origin,time)" - "VALUES(?,?,?,?,?,?,?,?)"; + "destination_site,destination_origin,reporting_origin,time,expiry_time)" + "VALUES(?,?,?,?,?,?,?,?,?)"; sql::Statement statement( db->GetCachedStatement(SQL_FROM_HERE, kStoreRateLimitSql)); statement.BindInt(0, static_cast<int>(scope)); @@ -143,6 +157,8 @@ statement.BindString(5, SerializeOrigin(common_info.conversion_origin())); statement.BindString(6, SerializeOrigin(common_info.reporting_origin())); statement.BindTime(7, time); + statement.BindTime(8, expiry_time); + return statement.Run(); } @@ -164,16 +180,16 @@ static constexpr char kAttributionAllowedSql[] = "SELECT COUNT(*)FROM rate_limits " - DCHECK_SQL_INDEXED_BY("rate_limit_attribution_idx") + DCHECK_SQL_INDEXED_BY("rate_limit_reporting_origin_idx") "WHERE scope=1 " - "AND source_site=? " "AND destination_site=? " + "AND source_site=? " "AND reporting_origin=? " "AND time>?"; sql::Statement statement( db->GetCachedStatement(SQL_FROM_HERE, kAttributionAllowedSql)); - statement.BindString(0, common_info.ImpressionSite().Serialize()); - statement.BindString(1, common_info.ConversionDestination().Serialize()); + statement.BindString(0, common_info.ConversionDestination().Serialize()); + statement.BindString(1, common_info.ImpressionSite().Serialize()); statement.BindString(2, SerializeOrigin(common_info.reporting_origin())); statement.BindTime(3, min_timestamp); @@ -195,6 +211,59 @@ source.common_info().impression_time()); } +RateLimitResult RateLimitTable::SourceAllowedForDestinationLimit( + sql::Database* db, + const StorableSource& source) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + static_assert(static_cast<int>(Scope::kSource) == 0, + "update `scope=0` clause below"); + + // Check the number of unique destinations covered by all source registrations + // whose [source_time, expiry_time] intersect with the current source_time. + static constexpr char kSourceAllowedSql[] = + "SELECT destination_site FROM rate_limits " + DCHECK_SQL_INDEXED_BY("rate_limit_source_site_reporting_origin_idx") + "WHERE scope=0 " + "AND source_site=? " + "AND reporting_origin=? " + "AND expiry_time>?"; + sql::Statement statement( + db->GetCachedStatement(SQL_FROM_HERE, kSourceAllowedSql)); + + const CommonSourceInfo& common_info = source.common_info(); + statement.BindString(0, common_info.ImpressionSite().Serialize()); + statement.BindString(1, SerializeOrigin(common_info.reporting_origin())); + statement.BindTime(2, common_info.impression_time()); + + const std::string serialized_destination_site = + common_info.ConversionDestination().Serialize(); + + const int limit = delegate_->GetMaxDestinationsPerSourceSiteReportingOrigin(); + DCHECK_GT(limit, 0); + + base::flat_set<std::string> destination_sites; + while (statement.Step()) { + std::string destination_site = statement.ColumnString(0); + + // The destination site isn't new, so it doesn't change the count. + // + // TODO(linnan): Consider adding an early exit query which first checks for + // the existence of `destination_site` for (source_site, reporting_origin), + // to avoid querying all of the rows in the case of multiple sources. + if (destination_site == serialized_destination_site) + return RateLimitResult::kAllowed; + + destination_sites.insert(std::move(destination_site)); + + if (destination_sites.size() == static_cast<size_t>(limit)) + return RateLimitResult::kNotAllowed; + } + + return statement.Succeeded() ? RateLimitResult::kAllowed + : RateLimitResult::kError; +} + RateLimitResult RateLimitTable::AttributionAllowedForReportingOriginLimit( sql::Database* db, const AttributionInfo& attribution_info) { @@ -339,17 +408,25 @@ } bool RateLimitTable::DeleteExpiredRateLimits(sql::Database* db) { - base::Time timestamp = - base::Time::Now() - delegate_->GetRateLimits().time_window; + base::Time now = base::Time::Now(); + base::Time timestamp = now - delegate_->GetRateLimits().time_window; + static_assert(static_cast<int>(Scope::kAttribution) == 1, + "update `scope=1` clause below"); + + // Attribution rate limit entries can be deleted as long as their time falls + // outside the rate limit window. For source entries, if the expiry time has + // not passed, keep entries around to ensure + // `SourceAllowedForDestinationLimit()` is computed properly. static constexpr char kDeleteExpiredRateLimits[] = // clang-format off "DELETE FROM rate_limits " DCHECK_SQL_INDEXED_BY("rate_limit_time_idx") - "WHERE time<=?"; // clang-format on + "WHERE time<=? AND(scope=1 OR expiry_time<=?)"; // clang-format on sql::Statement statement( db->GetCachedStatement(SQL_FROM_HERE, kDeleteExpiredRateLimits)); statement.BindTime(0, timestamp); + statement.BindTime(1, now); return statement.Run(); }
diff --git a/content/browser/attribution_reporting/rate_limit_table.h b/content/browser/attribution_reporting/rate_limit_table.h index 3eb905c0..a9f86de 100644 --- a/content/browser/attribution_reporting/rate_limit_table.h +++ b/content/browser/attribution_reporting/rate_limit_table.h
@@ -70,6 +70,10 @@ sql::Database* db, const StorableSource& source); + [[nodiscard]] RateLimitResult SourceAllowedForDestinationLimit( + sql::Database* db, + const StorableSource& source); + [[nodiscard]] RateLimitResult AttributionAllowedForReportingOriginLimit( sql::Database* db, const AttributionInfo& attribution_info);
diff --git a/content/browser/attribution_reporting/rate_limit_table_unittest.cc b/content/browser/attribution_reporting/rate_limit_table_unittest.cc index fd720a5..94d26d9 100644 --- a/content/browser/attribution_reporting/rate_limit_table_unittest.cc +++ b/content/browser/attribution_reporting/rate_limit_table_unittest.cc
@@ -61,18 +61,21 @@ std::string impression_origin, std::string conversion_origin, std::string reporting_origin, - base::Time time) + base::Time time, + base::TimeDelta source_expiry = base::Milliseconds(30)) : scope(scope), impression_origin(std::move(impression_origin)), conversion_origin(std::move(conversion_origin)), reporting_origin(std::move(reporting_origin)), - time(time) {} + time(time), + source_expiry(source_expiry) {} RateLimitScope scope; std::string impression_origin; std::string conversion_origin; std::string reporting_origin; base::Time time; + base::TimeDelta source_expiry; SourceBuilder NewSourceBuilder() const { // Ensure that operations involving attributions use the trigger time, not @@ -83,6 +86,7 @@ builder.SetImpressionOrigin(url::Origin::Create(GURL(impression_origin))); builder.SetConversionOrigin(url::Origin::Create(GURL(conversion_origin))); builder.SetReportingOrigin(url::Origin::Create(GURL(reporting_origin))); + builder.SetExpiry(source_expiry); return builder; } @@ -167,6 +171,13 @@ &db_, row.NewSourceBuilder().Build()); } + [[nodiscard]] RateLimitResult SourceAllowedForDestinationLimit( + const RateLimitRow& row) { + CHECK_EQ(row.scope, RateLimitScope::kSource); + return table_.SourceAllowedForDestinationLimit( + &db_, row.NewSourceBuilder().Build()); + } + [[nodiscard]] RateLimitResult AttributionAllowedForReportingOriginLimit( const RateLimitRow& row) { return table_.AttributionAllowedForReportingOriginLimit( @@ -666,6 +677,60 @@ Pair(_, Field(&RateLimitRow::impression_origin, "https://s3.test")))); } +TEST_F(RateLimitTableTest, AddRateLimitSource_DeletesExpiredRows) { + delegate_.set_rate_limits({ + .time_window = base::Minutes(2), + .max_source_registration_reporting_origins = + std::numeric_limits<int64_t>::max(), + .max_attribution_reporting_origins = std::numeric_limits<int64_t>::max(), + .max_attributions = INT_MAX, + }); + + delegate_.set_delete_expired_rate_limits_frequency(base::Minutes(4)); + + ASSERT_TRUE(table_.AddRateLimitForSource( + &db_, + SourceBuilder() + .SetImpressionOrigin(url::Origin::Create(GURL("https://s1.test"))) + .BuildStored())); + + ASSERT_TRUE(table_.AddRateLimitForSource( + &db_, + SourceBuilder() + .SetImpressionOrigin(url::Origin::Create(GURL("https://s2.test"))) + .SetExpiry(base::Minutes(5)) + .BuildStored())); + + task_environment_.FastForwardBy(base::Minutes(4) - base::Milliseconds(1)); + + ASSERT_TRUE(table_.AddRateLimitForSource( + &db_, + SourceBuilder() + .SetImpressionOrigin(url::Origin::Create(GURL("https://s3.test"))) + .BuildStored())); + + // No row has expired at this point. + ASSERT_THAT(GetRateLimitRows(), SizeIs(3)); + + // Advance to the next expiry period. + task_environment_.FastForwardBy(base::Milliseconds(1)); + + ASSERT_TRUE(table_.AddRateLimitForSource( + &db_, + SourceBuilder() + .SetImpressionOrigin(url::Origin::Create(GURL("https://s4.test"))) + .BuildStored())); + + // The first row should be expired at this point. The second row is not + // expired since the source is not expired yet. + ASSERT_THAT( + GetRateLimitRows(), + ElementsAre( + Pair(_, Field(&RateLimitRow::impression_origin, "https://s2.test")), + Pair(_, Field(&RateLimitRow::impression_origin, "https://s3.test")), + Pair(_, Field(&RateLimitRow::impression_origin, "https://s4.test")))); +} + TEST_F(RateLimitTableTest, ClearDataForSourceIds) { for (int64_t id = 4; id <= 6; id++) { ASSERT_TRUE(table_.AddRateLimitForSource( @@ -691,4 +756,53 @@ ElementsAre(Pair(1, _), Pair(3, _), Pair(5, _))); } +TEST_F(RateLimitTableTest, SourceAllowedForDestinationLimit) { + delegate_.set_max_destinations_per_source_site_reporting_origin(2); + + const base::Time now = base::Time::Now(); + const base::TimeDelta expiry = base::Milliseconds(30); + + const struct { + RateLimitRow row; + RateLimitResult expected; + } kRateLimitsToAdd[] = { + {RateLimitRow::Source("https://a.s1.test", "https://a.d1.test", + "https://a.r1.test", now, expiry), + RateLimitResult::kAllowed}, + {RateLimitRow::Source("https://a.s1.test", "https://a.d2.test", + "https://a.r1.test", now, expiry), + RateLimitResult::kAllowed}, + {RateLimitRow::Source("https://a.s1.test", "https://a.d2.test", + "https://a.r1.test", now, expiry), + RateLimitResult::kAllowed}, + {RateLimitRow::Source("https://a.s1.test", "https://a.d3.test", + "https://a.r1.test", now), + RateLimitResult::kNotAllowed}, + {RateLimitRow::Source("https://a.s2.test", "https://a.d2.test", + "https://a.r1.test", now), + RateLimitResult::kAllowed}, + {RateLimitRow::Source("https://a.s1.test", "https://a.d2.test", + "https://a.r2.test", now), + RateLimitResult::kAllowed}, + }; + + for (const auto& rate_limit : kRateLimitsToAdd) { + ASSERT_EQ(rate_limit.expected, + SourceAllowedForDestinationLimit(rate_limit.row)) + << rate_limit.row; + + if (rate_limit.expected == RateLimitResult::kAllowed) { + ASSERT_TRUE(AddRateLimitForSource(rate_limit.row)) << rate_limit.row; + } + } + + task_environment_.FastForwardBy(expiry); + + // This is allowed because the original sources have expired. + const auto row = + RateLimitRow::Source("https://a.s1.test", "https://a.d3.test", + "https://a.r1.test", base::Time::Now()); + EXPECT_EQ(RateLimitResult::kAllowed, SourceAllowedForDestinationLimit(row)); +} + } // namespace content
diff --git a/content/browser/private_aggregation/private_aggregation_budget_storage.cc b/content/browser/private_aggregation/private_aggregation_budget_storage.cc index 9bde440..0541652 100644 --- a/content/browser/private_aggregation/private_aggregation_budget_storage.cc +++ b/content/browser/private_aggregation/private_aggregation_budget_storage.cc
@@ -43,7 +43,7 @@ } // namespace // static -void PrivateAggregationBudgetStorage::CreateAsync( +base::OnceClosure PrivateAggregationBudgetStorage::CreateAsync( scoped_refptr<base::SequencedTaskRunner> db_task_runner, bool exclusively_run_in_memory, base::FilePath path_to_db_dir, @@ -57,15 +57,21 @@ // `base::Unretained` is safe here as it is impossible for `storage` to be // deleted before initialization finishes as it is now owned by the reply // callback below, i.e. passed to `FinishInitializationOnMainSequence()`. + // Similarly, passing the database raw pointer is safe as it can only be + // destroyed on the database sequence after `InitializeOnDbSequence()`. db_task_runner->PostTaskAndReplyWithResult( FROM_HERE, base::BindOnce(&PrivateAggregationBudgetStorage::InitializeOnDbSequence, - base::Unretained(raw_storage), exclusively_run_in_memory, + base::Unretained(raw_storage), + /*db=*/raw_storage->db_.get(), exclusively_run_in_memory, std::move(path_to_db_dir)), base::BindOnce( &PrivateAggregationBudgetStorage::FinishInitializationOnMainSequence, - base::Unretained(raw_storage), /*owned_this=*/std::move(storage), + base::Unretained(raw_storage), std::move(storage), std::move(on_done_initializing))); + + return base::BindOnce(&PrivateAggregationBudgetStorage::Shutdown, + raw_storage->weak_factory_.GetWeakPtr()); } PrivateAggregationBudgetStorage::PrivateAggregationBudgetStorage( @@ -77,26 +83,29 @@ &budgets_table_, /*max_num_entries=*/absl::nullopt, kFlushDelay), - db_task_runner_(std::move(db_task_runner)) {} + db_task_runner_(std::move(db_task_runner)), + db_(std::make_unique<sql::Database>( + sql::DatabaseOptions{.exclusive_locking = true, + .page_size = 4096, + .cache_size = 32})) {} PrivateAggregationBudgetStorage::~PrivateAggregationBudgetStorage() { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - db_task_runner_->DeleteSoon(FROM_HERE, db_.release()); + Shutdown(); } bool PrivateAggregationBudgetStorage::InitializeOnDbSequence( + sql::Database* db, bool exclusively_run_in_memory, base::FilePath path_to_db_dir) { DCHECK(db_task_runner_->RunsTasksInCurrentSequence()); + DCHECK(db); - db_ = std::make_unique<sql::Database>(sql::DatabaseOptions{ - .exclusive_locking = true, .page_size = 4096, .cache_size = 32}); + db->set_histogram_tag("PrivateAggregation"); - db_->set_histogram_tag("PrivateAggregation"); - + // TODO(crbug.com/1323320): Record histograms for the different + // outcomes/errors. if (exclusively_run_in_memory) { - if (!db_->OpenInMemory()) { - HandleInitializationFailure(); + if (!db->OpenInMemory()) { return false; } } else { @@ -104,31 +113,30 @@ base::DirectoryExists(path_to_db_dir) || base::CreateDirectory(path_to_db_dir); if (!dir_exists_or_was_created) { - HandleInitializationFailure(); return false; } base::FilePath path_to_database = path_to_db_dir.Append(kDatabaseFilename); - if (!db_->Open(path_to_database)) { - HandleInitializationFailure(); + if (!db->Open(path_to_database)) { return false; } } table_manager_->InitializeOnDbSequence( - db_.get(), std::vector<std::string>{kBudgetsTableName}, - kCurrentSchemaVersion); + db, std::vector<std::string>{kBudgetsTableName}, kCurrentSchemaVersion); budgets_data_.InitializeOnDBSequence(); return true; } -void PrivateAggregationBudgetStorage::HandleInitializationFailure() { - DCHECK(db_task_runner_->RunsTasksInCurrentSequence()); +void PrivateAggregationBudgetStorage::Shutdown() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - // TODO(crbug.com/1323320): Record histograms for the different - // outcomes/errors. - db_.reset(); + if (db_) { + // The sequenced task runner will ensure that this `db_` destruction task + // doesn't run until after `InitializeOnDbSequence()` runs. + db_task_runner_->DeleteSoon(FROM_HERE, db_.release()); + } } void PrivateAggregationBudgetStorage::FinishInitializationOnMainSequence(
diff --git a/content/browser/private_aggregation/private_aggregation_budget_storage.h b/content/browser/private_aggregation/private_aggregation_budget_storage.h index 6934a1b..bf6db31 100644 --- a/content/browser/private_aggregation/private_aggregation_budget_storage.h +++ b/content/browser/private_aggregation/private_aggregation_budget_storage.h
@@ -51,8 +51,10 @@ // Calls `on_done_initializing` once initialization is complete, passing an // owning pointer if initialization was successful and nullptr otherwise. If // `exclusively_run_in_memory` is `true`, the database will not be persisted - // to disk. - static void CreateAsync( + // to disk. Returns a closure that shuts down the storage before it is + // finished initializing. This is necessary to avoid posting tasks after + // shutdown if initialization finishes too late. + static base::OnceClosure CreateAsync( scoped_refptr<base::SequencedTaskRunner> db_task_runner, bool exclusively_run_in_memory, base::FilePath path_to_db_dir, @@ -79,6 +81,11 @@ return &budgets_data_; } + // Asynchronously tears down the budget storage database. Can be called before + // initialization is complete. This is necessary to avoid posting tasks after + // shutdown if initialization finishes too late. + void Shutdown(); + private: explicit PrivateAggregationBudgetStorage( scoped_refptr<base::SequencedTaskRunner> db_task_runner); @@ -87,11 +94,12 @@ // KeyValueData's initialization methods. If `exclusively_run_in_memory` is // true, the underlying database will be in-memory and not be persisted to // disk. Otherwise, a copy of the data is kept in-memory, but regularly - // flushed to disk. - [[nodiscard]] bool InitializeOnDbSequence(bool exclusively_run_in_memory, + // flushed to disk. Takes a raw pointer to the database in case `db_` is + // released before or while this is running. + [[nodiscard]] bool InitializeOnDbSequence(sql::Database* db, + bool exclusively_run_in_memory, base::FilePath path_to_db_dir); - void HandleInitializationFailure(); void FinishInitializationOnMainSequence( std::unique_ptr<PrivateAggregationBudgetStorage> owned_this, base::OnceCallback<void(std::unique_ptr<PrivateAggregationBudgetStorage>)> @@ -107,10 +115,14 @@ // sequence to clean up the DB. scoped_refptr<base::SequencedTaskRunner> db_task_runner_; - // Should only be accessed on the `db_task_runner_` sequence. + // Created on the main sequence, but otherwise should only be accessed on the + // `db_task_runner_` sequence. It is also released (but not deleted) on the + // main sequence. std::unique_ptr<sql::Database> db_; SEQUENCE_CHECKER(sequence_checker_); + + base::WeakPtrFactory<PrivateAggregationBudgetStorage> weak_factory_{this}; }; } // namespace content
diff --git a/content/browser/private_aggregation/private_aggregation_budget_storage_unittest.cc b/content/browser/private_aggregation/private_aggregation_budget_storage_unittest.cc index 9a596b4..05b48a52 100644 --- a/content/browser/private_aggregation/private_aggregation_budget_storage_unittest.cc +++ b/content/browser/private_aggregation/private_aggregation_budget_storage_unittest.cc
@@ -52,16 +52,16 @@ task_environment_.RunUntilIdle(); } - void OpenDatabase(bool run_in_memory, - base::OnceClosure on_done_initializing) { + base::OnceClosure OpenDatabase(bool run_in_memory, + base::OnceClosure on_done_initializing) { base::OnceCallback<void(std::unique_ptr<PrivateAggregationBudgetStorage>)> create_cb = base::BindOnce( &PrivateAggregationBudgetStorageTest::OnStorageInitialized, base::Unretained(this), std::move(on_done_initializing)); - PrivateAggregationBudgetStorage::CreateAsync(db_task_runner_, run_in_memory, - storage_directory(), - std::move(create_cb)); + return PrivateAggregationBudgetStorage::CreateAsync( + db_task_runner_, run_in_memory, storage_directory(), + std::move(create_cb)); } // Waits for the database to be initialized. @@ -246,4 +246,30 @@ run_loop.Run(); } +TEST_F(PrivateAggregationBudgetStorageTest, + StorageShutdownImmediatelyAfterCreation_DoesNotCrash) { + base::RunLoop run_loop; + base::OnceClosure shutdown = OpenDatabase( + /*run_in_memory=*/false, + /*on_done_initializing=*/base::BindLambdaForTesting([this, &run_loop]() { + CloseDatabase(); + run_loop.Quit(); + })); + std::move(shutdown).Run(); + run_loop.Run(); +} + +TEST_F(PrivateAggregationBudgetStorageTest, + StorageShutdownImmediatelyAfterInitialization_DoesNotCrash) { + base::RunLoop run_loop; + base::OnceClosure shutdown = OpenDatabase( + /*run_in_memory=*/false, + /*on_done_initializing=*/base::BindLambdaForTesting([&, this]() { + std::move(shutdown).Run(); + CloseDatabase(); + run_loop.Quit(); + })); + run_loop.Run(); +} + } // namespace content
diff --git a/content/browser/private_aggregation/private_aggregation_budgeter.cc b/content/browser/private_aggregation/private_aggregation_budgeter.cc index 412847c..6535d68 100644 --- a/content/browser/private_aggregation/private_aggregation_budgeter.cc +++ b/content/browser/private_aggregation/private_aggregation_budgeter.cc
@@ -20,7 +20,6 @@ #include "base/memory/scoped_refptr.h" #include "base/notreached.h" #include "base/numerics/checked_math.h" -#include "base/ranges/algorithm.h" #include "base/task/sequenced_task_runner.h" #include "base/time/time.h" #include "content/browser/private_aggregation/private_aggregation_budget_key.h" @@ -54,7 +53,7 @@ bool exclusively_run_in_memory, const base::FilePath& path_to_db_dir) { DCHECK(db_task_runner); - PrivateAggregationBudgetStorage::CreateAsync( + shutdown_initializing_storage_ = PrivateAggregationBudgetStorage::CreateAsync( std::move(db_task_runner), exclusively_run_in_memory, path_to_db_dir, /*on_done_initializing=*/ base::BindOnce(&PrivateAggregationBudgeter::OnStorageDoneInitializing, @@ -63,7 +62,15 @@ PrivateAggregationBudgeter::PrivateAggregationBudgeter() = default; -PrivateAggregationBudgeter::~PrivateAggregationBudgeter() = default; +PrivateAggregationBudgeter::~PrivateAggregationBudgeter() { + if (shutdown_initializing_storage_) { + // As the budget storage's lifetime is extended until initialization is + // complete, its destructor could run after browser shutdown has begun (when + // tasks can no longer be posted). We post the database deletion task now + // instead. + std::move(shutdown_initializing_storage_).Run(); + } +} void PrivateAggregationBudgeter::ConsumeBudget( int budget, @@ -87,6 +94,7 @@ void PrivateAggregationBudgeter::OnStorageDoneInitializing( std::unique_ptr<PrivateAggregationBudgetStorage> storage) { + DCHECK(shutdown_initializing_storage_); DCHECK(!storage_); DCHECK_EQ(storage_status_, StorageStatus::kInitializing); @@ -96,6 +104,7 @@ } else { storage_status_ = StorageStatus::kInitializationFailed; } + shutdown_initializing_storage_.Reset(); ProcessAllPendingCalls(); }
diff --git a/content/browser/private_aggregation/private_aggregation_budgeter.h b/content/browser/private_aggregation/private_aggregation_budgeter.h index bbdf65e..24a94ce 100644 --- a/content/browser/private_aggregation/private_aggregation_budgeter.h +++ b/content/browser/private_aggregation/private_aggregation_budgeter.h
@@ -8,7 +8,7 @@ #include <memory> #include <vector> -#include "base/callback_forward.h" +#include "base/callback.h" #include "base/memory/weak_ptr.h" #include "base/time/time.h" #include "content/browser/private_aggregation/private_aggregation_budget_key.h" @@ -117,6 +117,10 @@ // `storage_status_` should be `kOpen`. std::unique_ptr<PrivateAggregationBudgetStorage> storage_; + // Holds a closure that will shut down the initializing storage until + // initialization is complete. After then, it is null. + base::OnceClosure shutdown_initializing_storage_; + base::WeakPtrFactory<PrivateAggregationBudgeter> weak_factory_{this}; };
diff --git a/content/browser/renderer_host/navigation_controller_impl_browsertest.cc b/content/browser/renderer_host/navigation_controller_impl_browsertest.cc index e235f2ef..4412f69 100644 --- a/content/browser/renderer_host/navigation_controller_impl_browsertest.cc +++ b/content/browser/renderer_host/navigation_controller_impl_browsertest.cc
@@ -35,6 +35,7 @@ #include "content/browser/renderer_host/navigation_request.h" #include "content/browser/renderer_host/render_frame_host_impl.h" #include "content/browser/renderer_host/render_process_host_impl.h" +#include "content/browser/renderer_host/renderer_cancellation_throttle.h" #include "content/browser/site_info.h" #include "content/browser/web_contents/web_contents_impl.h" #include "content/browser/web_contents/web_contents_view.h" @@ -21457,6 +21458,223 @@ EXPECT_EQ(1, controller.GetCurrentEntryIndex()); } +// Tests that renderer-initiated navigation cancellation from the same JS task +// that created the navigation can still be triggered after WillProcessResponse, +// as the browser defers the navigation until the JS task that started it +// finishes. +IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTestNoServer, + RendererInitiatedCancellationDueToJS) { + net::test_server::ControllableHttpResponse fetch_response( + embedded_test_server(), "/fetch"); + + ASSERT_TRUE(embedded_test_server()->Start()); + // Navigate to a page with an iframe. + GURL url1(embedded_test_server()->GetURL( + "a.com", "/cross_site_iframe_factory.html?a(a)")); + EXPECT_TRUE(NavigateToURL(contents(), url1)); + + FrameTreeNode* root = contents()->GetPrimaryFrameTree().root(); + FrameTreeNode* child = root->child_at(0); + + GURL child_url = child->current_url(); + GURL child_url_2(embedded_test_server()->GetURL("a.com", "/title1.html")); + + // Now navigate the child frame to another same-site document, but cancel it + // from the JS task after a synchronous XHR request that we can control. + TestNavigationManager nav_manager(contents(), child_url_2); + ExecuteScriptAsync(child, R"( + location.href = '/title1.html'; + var request = new XMLHttpRequest(); + request.open("GET", "/fetch", /*async=*/false); + request.send(""); + var fetch_success = (request.readyState == 4 && request.status == 200); + window.stop(); + )"); + + // The navigation should be able to start, as the synchronous XHR request + // hasn't completed, and the navigation hasn't been canceled yet. + EXPECT_TRUE(nav_manager.WaitForRequestStart()); + nav_manager.ResumeNavigation(); + NavigationRequest* request = + static_cast<NavigationRequest*>(nav_manager.GetNavigationHandle()); + EXPECT_EQ(request, child->navigation_request()); + + // The navigation should be able to reach the WillProcessResponse stage, + // and gets deferred by RendererCancellationThrottle after that. Wait for the + // first NavigationThrottle deferral. + base::RunLoop run_loop; + NavigationThrottleRunner* throttle_runner = + request->GetNavigationThrottleRunnerForTesting(); + throttle_runner->set_first_deferral_callback_for_testing( + run_loop.QuitClosure()); + run_loop.Run(); + + // Check that the deferral is caused by RendererCancellationThrottle. + EXPECT_TRUE(request->IsDeferredForTesting()); + EXPECT_STREQ("RendererCancellationThrottle", + throttle_runner->GetDeferringThrottle()->GetNameForLogging()); + EXPECT_EQ(request->state(), NavigationRequest::WILL_PROCESS_RESPONSE); + + // Unblock the JS task in the renderer by sending the response for the sync + // XHR request. After that, the renderer will trigger navigation cancellation + // due to the window.stop() call. + fetch_response.WaitForRequest(); + fetch_response.Send(net::HTTP_OK, "foo"); + fetch_response.Done(); + + // The navigation got canceled without committing. + nav_manager.WaitForNavigationFinished(); + EXPECT_FALSE(nav_manager.was_successful()); + EXPECT_EQ(child_url, child->current_url()); + EXPECT_EQ(true, EvalJs(child, "fetch_success")); +} + +// Tests that the crash of the renderer that created a navigation will cancel +// the navigation. +IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTestNoServer, + RendererInitiatedCancellationDueToCrash) { + net::test_server::ControllableHttpResponse fetch_response( + embedded_test_server(), "/fetch"); + + ASSERT_TRUE(embedded_test_server()->Start()); + // Navigate to a page with an iframe. + GURL url1(embedded_test_server()->GetURL( + "a.com", "/cross_site_iframe_factory.html?a(b)")); + EXPECT_TRUE(NavigateToURL(contents(), url1)); + + FrameTreeNode* root = contents()->GetPrimaryFrameTree().root(); + FrameTreeNode* child = root->child_at(0); + + GURL child_url = child->current_url(); + GURL child_url_2(embedded_test_server()->GetURL("b.com", "/title1.html")); + + // Now navigate the child frame to another same-site page, but cancel it + // from the JS task after a synchronous XHR request that we can control. + TestNavigationManager nav_manager(contents(), child_url_2); + ExecuteScriptAsync(child, R"( + location.href = '/title1.html'; + var request = new XMLHttpRequest(); + request.open("GET", "/fetch", /*async=*/false); + request.send(""); + var fetch_success = (request.readyState == 4 && request.status == 200); + window.stop(); + )"); + + // The navigation should be able to start, as the synchronous XHR request + // hasn't completed, and the navigation hasn't been canceled yet. + EXPECT_TRUE(nav_manager.WaitForRequestStart()); + nav_manager.ResumeNavigation(); + NavigationRequest* request = + static_cast<NavigationRequest*>(nav_manager.GetNavigationHandle()); + EXPECT_EQ(request, child->navigation_request()); + + // The navigation should be able to reach the WillProcessResponse stage, + // and gets deferred by RendererCancellationThrottle after that. Wait for the + // first NavigationThrottle deferral. + base::RunLoop run_loop; + NavigationThrottleRunner* throttle_runner = + request->GetNavigationThrottleRunnerForTesting(); + throttle_runner->set_first_deferral_callback_for_testing( + run_loop.QuitClosure()); + run_loop.Run(); + + // Check that the deferral is caused by RendererCancellationThrottle. + EXPECT_TRUE(request->IsDeferredForTesting()); + EXPECT_STREQ("RendererCancellationThrottle", + throttle_runner->GetDeferringThrottle()->GetNameForLogging()); + EXPECT_EQ(request->state(), NavigationRequest::WILL_PROCESS_RESPONSE); + + // Kill the renderer process that started the navigation. + RenderProcessHost* child_process = child->current_frame_host()->GetProcess(); + RenderProcessHostWatcher crash_observer( + child_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); + child_process->Shutdown(0); + crash_observer.Wait(); + + // The navigation got canceled without committing. + nav_manager.WaitForNavigationFinished(); + EXPECT_FALSE(nav_manager.was_successful()); + // If the process is not shared with the main frame, the current URL of the + // child frame is empty after the process crashed. If the process is shared, + // the child frame will be gone because the main frame's process crashed. + if (AreAllSitesIsolatedForTesting()) + EXPECT_EQ(GURL(), child->current_url()); +} + +// Tests that if waiting for a renderer-initiated navigation cancellation takes +// too long, a warning for an unresponsive renderer will be sent. +IN_PROC_BROWSER_TEST_P( + NavigationControllerBrowserTestNoServer, + RendererInitiatedCancellationTimeoutWarnsUnresponsiveRenderer) { + net::test_server::ControllableHttpResponse fetch_response( + embedded_test_server(), "/fetch"); + + ASSERT_TRUE(embedded_test_server()->Start()); + // Navigate to a page with an iframe. + GURL url1(embedded_test_server()->GetURL( + "a.com", "/cross_site_iframe_factory.html?a(b)")); + EXPECT_TRUE(NavigateToURL(contents(), url1)); + + FrameTreeNode* root = contents()->GetPrimaryFrameTree().root(); + FrameTreeNode* child = root->child_at(0); + + GURL child_url = child->current_url(); + GURL child_url_2(embedded_test_server()->GetURL("b.com", "/title1.html")); + + // Set the cancellation timeout to a low enough value to wait in the test. + RendererCancellationThrottle::SetCancellationTimeoutForTesting( + base::Milliseconds(100)); + UnresponsiveRendererObserver unresponsive_renderer_observer(contents()); + + // Now navigate the child frame to another same-site page, but cancel it + // from the JS task after a synchronous XHR request that we can control. + TestNavigationManager nav_manager(contents(), child_url_2); + ExecuteScriptAsync(child, R"( + location.href = '/title1.html'; + var request = new XMLHttpRequest(); + request.open("GET", "/fetch", /*async=*/false); + request.send(""); + var fetch_success = (request.readyState == 4 && request.status == 200); + window.stop(); + )"); + + // The navigation should be able to start, as the synchronous XHR request + // hasn't completed, and the navigation hasn't been canceled yet. + EXPECT_TRUE(nav_manager.WaitForRequestStart()); + nav_manager.ResumeNavigation(); + NavigationRequest* request = + static_cast<NavigationRequest*>(nav_manager.GetNavigationHandle()); + EXPECT_EQ(request, child->navigation_request()); + + // The navigation should be able to reach the WillProcessResponse stage, + // and gets deferred by RendererCancellationThrottle after that. Wait for the + // first NavigationThrottle deferral. + base::RunLoop run_loop; + NavigationThrottleRunner* throttle_runner = + request->GetNavigationThrottleRunnerForTesting(); + throttle_runner->set_first_deferral_callback_for_testing( + run_loop.QuitClosure()); + run_loop.Run(); + + // Check that the deferral is caused by RendererCancellationThrottle. + EXPECT_TRUE(request->IsDeferredForTesting()); + EXPECT_STREQ("RendererCancellationThrottle", + throttle_runner->GetDeferringThrottle()->GetNameForLogging()); + EXPECT_EQ(request->state(), NavigationRequest::WILL_PROCESS_RESPONSE); + + // Verify that we will be notified about the unresponsive renderer. + RenderProcessHost* hung_process = unresponsive_renderer_observer.Wait(); + EXPECT_EQ(hung_process, child->current_frame_host()->GetProcess()); + + // Verify that the throttle still waits for the renderer-initiated + // cancellation. + EXPECT_TRUE(request->IsDeferredForTesting()); + + // Reset the cancellation timeout to the default value. + RendererCancellationThrottle::SetCancellationTimeoutForTesting( + base::TimeDelta()); +} + INSTANTIATE_TEST_SUITE_P( All, NavigationControllerAlertDialogBrowserTest,
diff --git a/content/browser/renderer_host/navigation_request.cc b/content/browser/renderer_host/navigation_request.cc index 88ec399..1ca4240 100644 --- a/content/browser/renderer_host/navigation_request.cc +++ b/content/browser/renderer_host/navigation_request.cc
@@ -1180,7 +1180,9 @@ mojo::PendingAssociatedRemote<mojom::NavigationClient> navigation_client, scoped_refptr<PrefetchedSignedExchangeCache> prefetched_signed_exchange_cache, - std::unique_ptr<WebBundleHandleTracker> web_bundle_handle_tracker) { + std::unique_ptr<WebBundleHandleTracker> web_bundle_handle_tracker, + mojo::PendingReceiver<mojom::NavigationRendererCancellationListener> + renderer_cancellation_listener) { TRACE_EVENT0("navigation", "NavigationRequest::CreateRendererInitiated"); // Only normal navigations to a different document or reloads are expected. // - Renderer-initiated same document navigations never start in the browser. @@ -1273,7 +1275,9 @@ std::move(web_bundle_handle_tracker), nullptr, // rfh_restored_from_back_forward_cache initiator_process_id, - /*was_opener_suppressed=*/false, /*is_pdf=*/false)); + /*was_opener_suppressed=*/false, /*is_pdf=*/false, + /*is_fenced_frame_opaque_url=*/absl::nullopt, + std::move(renderer_cancellation_listener))); return navigation_request; } @@ -1447,7 +1451,9 @@ int initiator_process_id, bool was_opener_suppressed, bool is_pdf, - absl::optional<bool> is_fenced_frame_opaque_url) + absl::optional<bool> is_fenced_frame_opaque_url, + mojo::PendingReceiver<mojom::NavigationRendererCancellationListener> + renderer_cancellation_listener) : frame_tree_node_(frame_tree_node), is_synchronous_renderer_commit_(is_synchronous_renderer_commit), common_params_(std::move(common_params)), @@ -1587,6 +1593,21 @@ DCHECK(navigation_client.is_valid()); SetNavigationClient(std::move(navigation_client)); + + // Wait for renderer-initiated cancellation if needed. Navigation can + // proceed as soon as the corresponding JS task in the renderer finishes + // without calling window.stop() or other navigation cancellation triggers. + // That means there is no need to synchronise this signal with other + // renderer events, so this interface doesn't have to be associated and can + // use a prioritized task runner. + // kNavigationNetworkResponse is used as CommitNavigation typically already + // runs in on a task from this task runner (via OnResponseReceived message + // received from the network service). + if (renderer_cancellation_listener.is_valid()) { + renderer_cancellation_listener_.Bind( + std::move(renderer_cancellation_listener), + GetUIThreadTaskRunner({BrowserTaskType::kNavigationNetworkResponse})); + } } else if (entry) { DCHECK(!navigation_client.is_valid()); if (frame_entry) { @@ -2523,8 +2544,9 @@ render_frame_host_->GetNavigationClientFromInterfaceProvider(); HandleInterfaceDisconnection( &commit_navigation_client_, - base::BindOnce(&NavigationRequest::OnRendererAbortedNavigation, - base::Unretained(this))); + base::BindOnce( + &NavigationRequest::OnRendererRequestedNavigationCancellation, + base::Unretained(this))); return commit_navigation_client_.get(); } @@ -5524,12 +5546,31 @@ navigation_controller.GetEntryCount(); } -void NavigationRequest::RendererAbortedNavigationForTesting() { - OnRendererAbortedNavigation(); +void NavigationRequest::RendererRequestedNavigationCancellationForTesting() { + OnRendererRequestedNavigationCancellation(); } -void NavigationRequest::OnRendererAbortedNavigation() { - if (IsWaitingToCommit()) { +void NavigationRequest::OnRendererRequestedNavigationCancellation() { + // Renderer-initiated navigation cancellations can only happen before the + // navigation gets into the READY_TO_COMMIT state, because + // RendererCancellationThrottle will prevent renderer-initiated navigations + // from entering that state before the JS task that started the navigation + // finishes. After navigation reaches READY_TO_COMMIT stage, we should + // ignore these navigation cancellations, except for these two cases: + // 1. It reuses the current RenderFrame(Host), because the RenderFrame expects + // the navigation to be cancelled successfully (as the state in the renderer + // is already updated to cancel the navigation). + // TODO(https://crbug.com/936696): This case will eventually go away with + // RenderDocument as cross-document navigations won't reuse RenderFrameHosts + // anymore. Fix tests that expect this behavior. + // 2. The target renderer had crashed, so the speculative RenderFrame is not + // live anymore, because the navigation can't commit in a crashed renderer. + if (!IsWaitingToCommit()) { + // The cancellation happens before READY_TO_COMMIT. + frame_tree_node_->navigator().CancelNavigation(frame_tree_node_); + } else if (render_frame_host_ == + frame_tree_node_->render_manager()->current_frame_host() || + !render_frame_host_->IsRenderFrameLive()) { // If the NavigationRequest has already reached READY_TO_COMMIT, // `render_frame_host_` owns `this`. Cache any needed state in stack // variables to avoid a use-after-free. @@ -5542,11 +5583,9 @@ // runs in `CommitPendingIfNecessary()` that expects `DidStopLoading()` // won't be called if `FrameTreeNode::navigation_request()` is null... frame_tree_node->render_manager()->MaybeCleanUpNavigation(); - } else { - frame_tree_node_->navigator().CancelNavigation(frame_tree_node_); } - // Do not add code after this, NavigationRequest has been destroyed. + // Do not add code after this, NavigationRequest might have been destroyed. } void NavigationRequest::HandleInterfaceDisconnection( @@ -6138,8 +6177,9 @@ // Binds the OnAbort callback HandleInterfaceDisconnection( &request_navigation_client_, - base::BindOnce(&NavigationRequest::OnRendererAbortedNavigation, - base::Unretained(this))); + base::BindOnce( + &NavigationRequest::OnRendererRequestedNavigationCancellation, + base::Unretained(this))); } bool NavigationRequest::NeedsUrlLoader() { @@ -6215,7 +6255,7 @@ // navigations do not, so we must look explicitly. We should not proceed and // claim "ReadyToCommitNavigation" to the delegate if the renderer is gone. if (!render_frame_host_->IsRenderFrameLive()) { - OnRendererAbortedNavigation(); + OnRendererRequestedNavigationCancellation(); // DO NOT ADD CODE AFTER THIS, as the NavigationHandle has been deleted // by the previous call. return; @@ -7915,6 +7955,22 @@ network::CrossOriginResourcePolicy::kHeaderName, "same-origin"); } +void NavigationRequest::RendererCancellationWindowEnded() { + // The renderer had indicated that the navigation cancellation window had + // ended, so the navigation can resume if it is currently waiting for this + // signal. + renderer_cancellation_window_ended_ = true; + if (renderer_cancellation_window_ended_callback_) { + std::move(renderer_cancellation_window_ended_callback_).Run(); + } + renderer_cancellation_listener_.reset(); +} + +bool NavigationRequest::ShouldWaitForRendererCancellationWindowToEnd() { + return renderer_cancellation_listener_.is_bound() && + !renderer_cancellation_window_ended_; +} + NavigationRequest::ScopedCrashKeys::ScopedCrashKeys( NavigationRequest& navigation_request) : initiator_origin_(
diff --git a/content/browser/renderer_host/navigation_request.h b/content/browser/renderer_host/navigation_request.h index 81194f5..50eeabe 100644 --- a/content/browser/renderer_host/navigation_request.h +++ b/content/browser/renderer_host/navigation_request.h
@@ -111,6 +111,7 @@ public NavigationThrottleRunner::Delegate, public CommitDeferringConditionRunner::Delegate, public FencedFrameURLMapping::MappingResultObserver, + public mojom::NavigationRendererCancellationListener, private RenderProcessHostObserver, private network::mojom::CookieAccessObserver { public: @@ -239,7 +240,9 @@ mojo::PendingAssociatedRemote<mojom::NavigationClient> navigation_client, scoped_refptr<PrefetchedSignedExchangeCache> prefetched_signed_exchange_cache, - std::unique_ptr<WebBundleHandleTracker> web_bundle_handle_tracker); + std::unique_ptr<WebBundleHandleTracker> web_bundle_handle_tracker, + mojo::PendingReceiver<mojom::NavigationRendererCancellationListener> + renderer_cancellation_listener); // Creates a NavigationRequest for synchronous navigation that have committed // in the renderer process. Those are: @@ -392,6 +395,9 @@ #endif base::SafeRef<NavigationHandle> GetSafeRef() override; + // mojom::NavigationRendererCancellationListener implementation + void RendererCancellationWindowEnded() override; + void RegisterCommitDeferringConditionForTesting( std::unique_ptr<CommitDeferringCondition> condition); @@ -546,8 +552,8 @@ return throttle_runner_.get(); } - // Simulates renderer aborting navigation. - void RendererAbortedNavigationForTesting(); + // Simulates renderer cancelling the navigation. + void RendererRequestedNavigationCancellationForTesting(); typedef base::OnceCallback<bool(NavigationThrottle::ThrottleCheckResult)> ThrottleChecksFinishedCallback; @@ -629,6 +635,22 @@ ready_to_commit_callback_for_testing_ = std::move(callback); } + void set_renderer_cancellation_window_ended_callback( + base::OnceClosure callback) { + DCHECK(!renderer_cancellation_window_ended()); + renderer_cancellation_window_ended_callback_ = std::move(callback); + } + + bool renderer_cancellation_window_ended() const { + return renderer_cancellation_window_ended_; + } + + // Returns true if this navigation should wait for the renderer-initiated + // navigation cancellation window to end before committing, and returns false + // otherwise. See comment for `renderer_cancellation_listener_` for more + // details. + bool ShouldWaitForRendererCancellationWindowToEnd(); + // Sets the READY_TO_COMMIT -> DID_COMMIT timeout. Resets the timeout to the // default value if |timeout| is zero. static void SetCommitTimeoutForTesting(const base::TimeDelta& timeout); @@ -994,7 +1016,9 @@ int initiator_process_id, bool was_opener_suppressed, bool is_pdf, - absl::optional<bool> is_fenced_frame_opaque_url = absl::nullopt); + absl::optional<bool> is_fenced_frame_opaque_url = absl::nullopt, + mojo::PendingReceiver<mojom::NavigationRendererCancellationListener> + renderer_cancellation_listener = mojo::NullReceiver()); // Checks if this navigation may activate a prerendered page. If it's // possible, schedules to start running CommitDeferringConditions for @@ -1244,8 +1268,9 @@ // renderer process. void UpdateCommitNavigationParamsHistory(); - // Called when an ongoing renderer-initiated navigation is aborted. - void OnRendererAbortedNavigation(); + // Called when the renderer requesting a navigation cancellation, or because + // the renderer crashed. + void OnRendererRequestedNavigationCancellation(); // Binds the given error_handler to be called when an interface disconnection // happens on the renderer side. @@ -2089,6 +2114,23 @@ scoped_refptr<NavigationOrDocumentHandle> navigation_or_document_handle_; + // Renderer-initiated navigations can be canceled until the JS task that + // started the navigation finishes. See RendererCancellationThrottle for more + // details. The window of time in which the renderer can cancel the navigation + // is called the "cancellation window" and the navigation can't commit until + // the cancellation window ended, which `renderer_cancellation_listener_` + // listens to. `renderer_cancellation_window_ended_` is true if the + // cancellation window had ended. If + // `renderer_cancellation_window_ended_callback_` is set, the navigation is + // being deferred by RendererCancellationThrottle to wait for the cancellation + // window to finish or for the navigation to get canceled. If it is set when + // the cancellation window ended, the callback will be run, to resume the + // navigation. + mojo::Receiver<mojom::NavigationRendererCancellationListener> + renderer_cancellation_listener_{this}; + bool renderer_cancellation_window_ended_ = false; + base::OnceClosure renderer_cancellation_window_ended_callback_; + base::WeakPtrFactory<NavigationRequest> weak_factory_{this}; };
diff --git a/content/browser/renderer_host/navigation_throttle_runner.cc b/content/browser/renderer_host/navigation_throttle_runner.cc index 8298fa4..f87f00a 100644 --- a/content/browser/renderer_host/navigation_throttle_runner.cc +++ b/content/browser/renderer_host/navigation_throttle_runner.cc
@@ -17,6 +17,7 @@ #include "content/browser/renderer_host/mixed_content_navigation_throttle.h" #include "content/browser/renderer_host/navigation_request.h" #include "content/browser/renderer_host/navigator_delegate.h" +#include "content/browser/renderer_host/renderer_cancellation_throttle.h" #include "content/public/browser/navigation_handle.h" namespace content { @@ -177,6 +178,11 @@ // throttles handling pages with 407 errors that require extra authentication. AddThrottle(HttpErrorNavigationThrottle::MaybeCreateThrottleFor(*request)); + // Wait for renderer-initiated navigation cancelation window to end. This will + // wait for the JS task that starts the navigation to finish, so add it close + // to the end to not delay running other throttles. + AddThrottle(RendererCancellationThrottle::MaybeCreateThrottleFor(request)); + // Insert all testing NavigationThrottles last. throttles_.insert(throttles_.end(), std::make_move_iterator(testing_throttles.begin()), @@ -240,6 +246,9 @@ case NavigationThrottle::DEFER: next_index_ = i + 1; defer_start_time_ = base::Time::Now(); + if (first_deferral_callback_for_testing_) { + std::move(first_deferral_callback_for_testing_).Run(); + } return; } }
diff --git a/content/browser/renderer_host/navigation_throttle_runner.h b/content/browser/renderer_host/navigation_throttle_runner.h index 5c1ea30..d40c54c7 100644 --- a/content/browser/renderer_host/navigation_throttle_runner.h +++ b/content/browser/renderer_host/navigation_throttle_runner.h
@@ -73,6 +73,10 @@ // |navigation_throttle|. void AddThrottle(std::unique_ptr<NavigationThrottle> navigation_throttle); + void set_first_deferral_callback_for_testing(base::OnceClosure callback) { + first_deferral_callback_for_testing_ = std::move(callback); + } + private: void ProcessInternal(); void InformDelegate(const NavigationThrottle::ThrottleCheckResult& result); @@ -92,6 +96,10 @@ // The time a throttle started deferring the navigation. base::Time defer_start_time_; + // This test-only callback will be run the first time a NavigationThrottle + // defers this navigation. + base::OnceClosure first_deferral_callback_for_testing_; + // The event currently being processed. Event current_event_ = Event::NoEvent; base::WeakPtrFactory<NavigationThrottleRunner> weak_factory_{this};
diff --git a/content/browser/renderer_host/navigator.cc b/content/browser/renderer_host/navigator.cc index b88a9d6..798890a 100644 --- a/content/browser/renderer_host/navigator.cc +++ b/content/browser/renderer_host/navigator.cc
@@ -938,7 +938,9 @@ mojo::PendingAssociatedRemote<mojom::NavigationClient> navigation_client, scoped_refptr<PrefetchedSignedExchangeCache> prefetched_signed_exchange_cache, - std::unique_ptr<WebBundleHandleTracker> web_bundle_handle_tracker) { + std::unique_ptr<WebBundleHandleTracker> web_bundle_handle_tracker, + mojo::PendingReceiver<mojom::NavigationRendererCancellationListener> + renderer_cancellation_listener) { TRACE_EVENT0("navigation", "Navigator::OnBeginNavigation"); // TODO(clamy): the url sent by the renderer should be validated with // FilterURL. @@ -990,7 +992,8 @@ controller_.GetEntryCount(), override_user_agent, std::move(blob_url_loader_factory), std::move(navigation_client), std::move(prefetched_signed_exchange_cache), - std::move(web_bundle_handle_tracker))); + std::move(web_bundle_handle_tracker), + std::move(renderer_cancellation_listener))); NavigationRequest* navigation_request = frame_tree_node->navigation_request(); navigation_data_ = std::make_unique<NavigationMetricsData>(
diff --git a/content/browser/renderer_host/navigator.h b/content/browser/renderer_host/navigator.h index 96f36b8..821b4b6 100644 --- a/content/browser/renderer_host/navigator.h +++ b/content/browser/renderer_host/navigator.h
@@ -183,7 +183,9 @@ mojo::PendingAssociatedRemote<mojom::NavigationClient> navigation_client, scoped_refptr<PrefetchedSignedExchangeCache> prefetched_signed_exchange_cache, - std::unique_ptr<WebBundleHandleTracker> web_bundle_handle_tracker); + std::unique_ptr<WebBundleHandleTracker> web_bundle_handle_tracker, + mojo::PendingReceiver<mojom::NavigationRendererCancellationListener> + renderer_cancellation_listener); // Used to restart a navigation that was thought to be same-document in // cross-document mode.
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc index fe27260..85161d8a7 100644 --- a/content/browser/renderer_host/render_frame_host_impl.cc +++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -1443,23 +1443,31 @@ blink::mojom::BeginNavigationParamsPtr begin_navigation_params; scoped_refptr<network::SharedURLLoaderFactory> blob_url_loader_factory; mojo::PendingAssociatedRemote<mojom::NavigationClient> navigation_client; + mojo::PendingReceiver<mojom::NavigationRendererCancellationListener> + renderer_cancellation_listener; PendingNavigation( blink::mojom::CommonNavigationParamsPtr common_params, blink::mojom::BeginNavigationParamsPtr begin_navigation_params, scoped_refptr<network::SharedURLLoaderFactory> blob_url_loader_factory, - mojo::PendingAssociatedRemote<mojom::NavigationClient> navigation_client); + mojo::PendingAssociatedRemote<mojom::NavigationClient> navigation_client, + mojo::PendingReceiver<mojom::NavigationRendererCancellationListener> + renderer_cancellation_listener); }; PendingNavigation::PendingNavigation( blink::mojom::CommonNavigationParamsPtr common_params, blink::mojom::BeginNavigationParamsPtr begin_navigation_params, scoped_refptr<network::SharedURLLoaderFactory> blob_url_loader_factory, - mojo::PendingAssociatedRemote<mojom::NavigationClient> navigation_client) + mojo::PendingAssociatedRemote<mojom::NavigationClient> navigation_client, + mojo::PendingReceiver<mojom::NavigationRendererCancellationListener> + renderer_cancellation_listener) : common_params(std::move(common_params)), begin_navigation_params(std::move(begin_navigation_params)), blob_url_loader_factory(std::move(blob_url_loader_factory)), - navigation_client(std::move(navigation_client)) {} + navigation_client(std::move(navigation_client)), + renderer_cancellation_listener( + std::move(renderer_cancellation_listener)) {} // static RenderFrameHost* RenderFrameHost::FromID(const GlobalRenderFrameHostId& id) { @@ -3546,7 +3554,8 @@ std::move(pending_navigate_->blob_url_loader_factory), std::move(pending_navigate_->navigation_client), EnsurePrefetchedSignedExchangeCache(), - MaybeCreateWebBundleHandleTracker()); + MaybeCreateWebBundleHandleTracker(), + std::move(pending_navigate_->renderer_cancellation_listener)); pending_navigate_.reset(); } } @@ -7744,7 +7753,9 @@ mojo::PendingRemote<blink::mojom::BlobURLToken> blob_url_token, mojo::PendingAssociatedRemote<mojom::NavigationClient> navigation_client, mojo::PendingRemote<blink::mojom::PolicyContainerHostKeepAliveHandle> - initiator_policy_container_host_keep_alive_handle) { + initiator_policy_container_host_keep_alive_handle, + mojo::PendingReceiver<mojom::NavigationRendererCancellationListener> + renderer_cancellation_listener) { if (frame_tree_node_->render_manager()->is_attaching_inner_delegate()) { // Avoid starting any new navigations since this frame is in the process of // attaching an inner delegate. @@ -7854,7 +7865,8 @@ if (waiting_for_init_) { pending_navigate_ = std::make_unique<PendingNavigation>( std::move(validated_params), std::move(begin_params), - std::move(blob_url_loader_factory), std::move(navigation_client)); + std::move(blob_url_loader_factory), std::move(navigation_client), + std::move(renderer_cancellation_listener)); return; } @@ -7870,7 +7882,8 @@ frame_tree_node(), std::move(validated_params), std::move(begin_params), std::move(blob_url_loader_factory), std::move(navigation_client), EnsurePrefetchedSignedExchangeCache(), - MaybeCreateWebBundleHandleTracker()); + MaybeCreateWebBundleHandleTracker(), + std::move(renderer_cancellation_listener)); } void RenderFrameHostImpl::SubresourceResponseStarted( @@ -10374,13 +10387,19 @@ // tasks in flight: use `render_frame_scoped_weak_ptr_factory_` to ensure // those tasks are dropped if they arrive after the reset of their // corresponding RenderAccessibilityHost. - render_accessibility_host_ = base::SequenceBound<RenderAccessibilityHost>( - base::FeatureList::IsEnabled( - features::kRenderAccessibilityHostDeserializationOffMainThread) - ? base::ThreadPool::CreateSequencedTaskRunner({}) - : base::SequencedTaskRunnerHandle::Get(), - render_frame_scoped_weak_ptr_factory_.GetWeakPtr(), std::move(receiver), - GetAXTreeID()); + ui::AXTreeID ax_tree_id = GetAXTreeID(); + if (!render_accessibility_host_ || + ax_tree_id != render_accessibility_host_ax_tree_id_) { + render_accessibility_host_ = base::SequenceBound<RenderAccessibilityHost>( + base::FeatureList::IsEnabled( + features::kRenderAccessibilityHostDeserializationOffMainThread) + ? base::ThreadPool::CreateSequencedTaskRunner({}) + : base::SequencedTaskRunnerHandle::Get(), + render_frame_scoped_weak_ptr_factory_.GetWeakPtr(), ax_tree_id); + } + render_accessibility_host_ax_tree_id_ = ax_tree_id; + render_accessibility_host_.AsyncCall(&RenderAccessibilityHost::Bind) + .WithArgs(std::move(receiver)); } bool RenderFrameHostImpl::CancelPrerendering(
diff --git a/content/browser/renderer_host/render_frame_host_impl.h b/content/browser/renderer_host/render_frame_host_impl.h index 6d51179..29688f6 100644 --- a/content/browser/renderer_host/render_frame_host_impl.h +++ b/content/browser/renderer_host/render_frame_host_impl.h
@@ -2790,7 +2790,9 @@ mojo::PendingRemote<blink::mojom::BlobURLToken> blob_url_token, mojo::PendingAssociatedRemote<mojom::NavigationClient> navigation_client, mojo::PendingRemote<blink::mojom::PolicyContainerHostKeepAliveHandle> - initiator_policy_container_host_keep_alive_handle) override; + initiator_policy_container_host_keep_alive_handle, + mojo::PendingReceiver<mojom::NavigationRendererCancellationListener> + renderer_cancellation_listener) override; void SubresourceResponseStarted(const url::SchemeHostPort& final_response_url, net::CertStatus cert_status) override; void ResourceLoadComplete( @@ -3882,6 +3884,7 @@ render_accessibility_; base::SequenceBound<RenderAccessibilityHost> render_accessibility_host_; + ui::AXTreeID render_accessibility_host_ax_tree_id_; mojo::AssociatedReceiver<mojom::DomAutomationControllerHost> dom_automation_controller_receiver_{this};
diff --git a/content/browser/renderer_host/renderer_cancellation_throttle.cc b/content/browser/renderer_host/renderer_cancellation_throttle.cc new file mode 100644 index 0000000..cb9fd2e --- /dev/null +++ b/content/browser/renderer_host/renderer_cancellation_throttle.cc
@@ -0,0 +1,115 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/renderer_host/renderer_cancellation_throttle.h" + +#include "content/browser/renderer_host/frame_tree_node.h" +#include "content/browser/renderer_host/navigation_request.h" + +namespace content { + +namespace { + +// Default timeout for the cancellation window. Chosen initially based on the +// default commit timeout for navigation requests. Will be updated based on the +// "Navigation.RendererInitiatedCancellation.DeferStartToCancellationWindowEnd" +// UMA after. +constexpr base::TimeDelta kDefaultCancellationTimeout = base::Seconds(30); +base::TimeDelta g_cancellation_timeout = kDefaultCancellationTimeout; + +} // namespace + +// static +std::unique_ptr<RendererCancellationThrottle> +RendererCancellationThrottle::MaybeCreateThrottleFor(NavigationHandle* handle) { + NavigationRequest* request = NavigationRequest::From(handle); + if (request->ShouldWaitForRendererCancellationWindowToEnd()) { + return std::make_unique<RendererCancellationThrottle>(handle); + } + return nullptr; +} + +// static +void RendererCancellationThrottle::SetCancellationTimeoutForTesting( + base::TimeDelta timeout) { + if (timeout.is_zero()) { + g_cancellation_timeout = kDefaultCancellationTimeout; + } else { + g_cancellation_timeout = timeout; + } +} + +RendererCancellationThrottle::RendererCancellationThrottle( + NavigationHandle* navigation_handle) + : NavigationThrottle(navigation_handle) {} + +RendererCancellationThrottle::~RendererCancellationThrottle() = default; + +NavigationThrottle::ThrottleCheckResult +RendererCancellationThrottle::WillProcessResponse() { + will_process_response_time_ = base::TimeTicks::Now(); + NavigationRequest* request = NavigationRequest::From(navigation_handle()); + DCHECK(request); + if (request->renderer_cancellation_window_ended()) { + // The cancellation window had already ended, so the navigation doesn't need + // deferring. + return NavigationThrottle::PROCEED; + } + + if (!request->GetRenderFrameHost() || + request->GetRenderFrameHost()->GetSiteInstance() != + request->frame_tree_node()->current_frame_host()->GetSiteInstance()) { + // Only defer same-SiteInstance navigations, as only those navigations + // were previously guaranteed to be cancelable from the same JS task it + // started on (see comment in the header file for more details). + return NavigationThrottle::PROCEED; + } + + // Start the cancellation timeout, to warn users of an unresponsive renderer + // if the cancellation window is longer than the set time limit. + RestartTimeout(); + // Wait for the navigation cancellation window to end before continuing. + request->set_renderer_cancellation_window_ended_callback(base::BindOnce( + &RendererCancellationThrottle::NavigationCancellationWindowEnded, + base::Unretained(this))); + + return NavigationThrottle::DEFER; +} + +void RendererCancellationThrottle::NavigationCancellationWindowEnded() { + CHECK(NavigationRequest::From(navigation_handle()) + ->renderer_cancellation_window_ended()); + base::UmaHistogramTimes( + "Navigation.RendererInitiatedCancellation." + "DeferStartToCancellationWindowEnd", + base::TimeTicks::Now() - will_process_response_time_); + // Stop the timeout and notify that renderer is responsive if necessary. + renderer_cancellation_timeout_timer_.Stop(); + NavigationRequest* request = NavigationRequest::From(navigation_handle()); + request->GetRenderFrameHost()->GetRenderWidgetHost()->RendererIsResponsive(); + + Resume(); +} + +void RendererCancellationThrottle::OnTimeout() { + // Warn that the renderer is unresponsive. + NavigationRequest* request = NavigationRequest::From(navigation_handle()); + DCHECK(request); + request->GetRenderFrameHost()->GetRenderWidgetHost()->RendererIsUnresponsive( + base::BindRepeating(&RendererCancellationThrottle::RestartTimeout, + weak_factory_.GetWeakPtr())); +} + +void RendererCancellationThrottle::RestartTimeout() { + renderer_cancellation_timeout_timer_.Start( + FROM_HERE, g_cancellation_timeout, + base::BindOnce(&RendererCancellationThrottle::OnTimeout, + base::Unretained(this))); +} + +const char* RendererCancellationThrottle::GetNameForLogging() { + return "RendererCancellationThrottle"; +} + +} // namespace content \ No newline at end of file
diff --git a/content/browser/renderer_host/renderer_cancellation_throttle.h b/content/browser/renderer_host/renderer_cancellation_throttle.h new file mode 100644 index 0000000..6b48bc77 --- /dev/null +++ b/content/browser/renderer_host/renderer_cancellation_throttle.h
@@ -0,0 +1,78 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_RENDERER_HOST_RENDERER_CANCELLATION_THROTTLE_H_ +#define CONTENT_BROWSER_RENDERER_HOST_RENDERER_CANCELLATION_THROTTLE_H_ + +#include "base/timer/timer.h" +#include "content/common/content_export.h" +#include "content/public/browser/navigation_throttle.h" + +namespace content { + +// Renderer-initiated navigations can be canceled from the JS task it was +// initiated from, e.g. if the script runs window.stop() after initiating the +// navigation. See also https://github.com/whatwg/html/issues/3447 and +// https://crbug.com/763106 for more background. +// +// The renderer cancels navigation by triggering the disconnection of the +// NavigationClient interface used to start the navigation, eventually +// calling `NavigationRequest::OnRendererAbortedNavigation()`. +// +// Same-SiteInstanceGroup navigations used to use the same NavigationClient for +// starting and committing the navigation. This means even if a CommitNavigation +// IPC is in-flight at the time of navigation cancellation, the navigation can +// still get canceled. Also, since the same RenderFrame is reused, the +// CommitNavigation IPC also implicitly waits for the JS task that triggers the +// navigation to finish, as the commit can't be processed before then. +// +// However, with RenderDocument, the RenderFrame and NavigationClient won't be +// reused, which means navigation cancellations might only affect navigations +// that haven't entered READY_TO_COMMIT stage. +// +// RendererCancellationThrottle helps preserve the previous behavior by waiting +// for the JS task to finish, through deferring the navigation before it gets +// into the READY_TO_COMMIT stage, until the renderer that started the +// navigation sends the `NavigationCancellationWindowEnded` IPC that corresponds +// to the navigation, signifying that the JS task that initiated the navigation +// had ended and no renderer-initiated navigation cancellations can happen after +// that point. +class CONTENT_EXPORT RendererCancellationThrottle : public NavigationThrottle { + public: + static std::unique_ptr<RendererCancellationThrottle> MaybeCreateThrottleFor( + NavigationHandle* handle); + + // Sets the cancellation timeout. Resets the timeout to the default value if + // `timeout` is zero. + static void SetCancellationTimeoutForTesting(base::TimeDelta timeout); + + explicit RendererCancellationThrottle(NavigationHandle* navigation_handle); + ~RendererCancellationThrottle() override; + RendererCancellationThrottle() = delete; + RendererCancellationThrottle(const RendererCancellationThrottle&) = delete; + RendererCancellationThrottle& operator=(const RendererCancellationThrottle&) = + delete; + + // The renderer had indicated that the navigation cancellation window had + // ended, so the navigation can resume. + void NavigationCancellationWindowEnded(); + + private: + NavigationThrottle::ThrottleCheckResult WillProcessResponse() override; + const char* GetNameForLogging() override; + + void OnTimeout(); + void RestartTimeout(); + + // The time WillProcessResponse() was called. + base::TimeTicks will_process_response_time_; + + base::OneShotTimer renderer_cancellation_timeout_timer_; + + base::WeakPtrFactory<RendererCancellationThrottle> weak_factory_{this}; +}; + +} // namespace content + +#endif // CONTENT_BROWSER_RENDERER_HOST_RENDERER_CANCELLATION_THROTTLE_H_ \ No newline at end of file
diff --git a/content/browser/security_exploit_browsertest.cc b/content/browser/security_exploit_browsertest.cc index bfb2bf2..f003403b 100644 --- a/content/browser/security_exploit_browsertest.cc +++ b/content/browser/security_exploit_browsertest.cc
@@ -1537,7 +1537,7 @@ navigation_client.InitWithNewEndpointAndPassReceiver(); rfh->frame_host_receiver_for_testing().impl()->BeginNavigation( std::move(common_params), std::move(begin_params), mojo::NullRemote(), - std::move(navigation_client), mojo::NullRemote()); + std::move(navigation_client), mojo::NullRemote(), mojo::NullReceiver()); EXPECT_EQ(bad_message::RFH_BASE_URL_FOR_DATA_URL_SPECIFIED, process_kill_waiter.Wait());
diff --git a/content/browser/webauth/authenticator_common.cc b/content/browser/webauth/authenticator_common.cc index 9897bc3..c08d270e 100644 --- a/content/browser/webauth/authenticator_common.cc +++ b/content/browser/webauth/authenticator_common.cc
@@ -174,11 +174,11 @@ } // Parses the FIDO transport types extension from the DER-encoded, X.509 -// certificate in |der_cert| and appends any unique transport types found to -// |out_transports|. -void AppendUniqueTransportsFromCertificate( +// certificate in |der_cert| and adds any transport types found to +// |out_transports|. Returns true if any transports were added. +bool AddTransportsFromCertificate( base::span<const uint8_t> der_cert, - std::vector<device::FidoTransportProtocol>* out_transports) { + base::flat_set<device::FidoTransportProtocol>* out_transports) { // See // https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-authenticator-transports-extension-v1.2-ps-20170411.html#fido-u2f-certificate-transports-extension static constexpr uint8_t kTransportTypesOID[] = { @@ -192,7 +192,7 @@ sizeof(kTransportTypesOID)), &present, &critical, &contents) || !present) { - return; + return false; } const net::der::Input contents_der(contents); @@ -200,7 +200,7 @@ absl::optional<net::der::BitString> transport_bits = contents_parser.ReadBitString(); if (!transport_bits) { - return; + return false; } // The certificate extension contains a BIT STRING where different bits @@ -218,12 +218,15 @@ {4, device::FidoTransportProtocol::kInternal}, }; + bool ret = false; for (const auto& mapping : kTransportMapping) { - if (transport_bits->AssertsBit(mapping.bit_index) && - !base::Contains(*out_transports, mapping.transport)) { - out_transports->push_back(mapping.transport); + if (transport_bits->AssertsBit(mapping.bit_index)) { + out_transports->insert(mapping.transport); + ret |= true; } } + + return ret; } enum class AttestationErasureOption { @@ -1654,23 +1657,34 @@ *response_data.transport_used()) : device::AuthenticatorAttachment::kAny; - // The transport list must not contain duplicates but the order doesn't matter - // because Blink will sort the resulting strings before returning them. - std::vector<device::FidoTransportProtocol> transports; + base::flat_set<device::FidoTransportProtocol> transports; + // transports_authoritative tracks whether the contents of `transports` are + // considered to be sufficient complete to report back to the website. + bool transports_authoritative = false; + if (response_data.transport_used()) { - transports.push_back(*response_data.transport_used()); + transports.insert(*response_data.transport_used()); } - // If the attestation certificate specifies that the token supports any other - // transports, include them in the list. + if (response_data.transports) { + transports.insert(response_data.transports->begin(), + response_data.transports->end()); + transports_authoritative = true; + } + // Also include any transports from the attestation certificate. absl::optional<base::span<const uint8_t>> leaf_cert = response_data.attestation_object() .attestation_statement() .GetLeafCertificate(); if (leaf_cert) { - AppendUniqueTransportsFromCertificate(*leaf_cert, &transports); + transports_authoritative |= + AddTransportsFromCertificate(*leaf_cert, &transports); } - response->transports = std::move(transports); + // The order of transports doesn't matter because Blink will sort the + // resulting strings before returning them. + if (transports_authoritative) { + response->transports.assign(transports.begin(), transports.end()); + } bool did_create_hmac_secret = false; bool did_store_cred_blob = false;
diff --git a/content/browser/webauth/authenticator_impl_unittest.cc b/content/browser/webauth/authenticator_impl_unittest.cc index 8953fcc..f8ba28e 100644 --- a/content/browser/webauth/authenticator_impl_unittest.cc +++ b/content/browser/webauth/authenticator_impl_unittest.cc
@@ -15,6 +15,7 @@ #include "base/bind.h" #include "base/callback_helpers.h" #include "base/compiler_specific.h" +#include "base/containers/flat_set.h" #include "base/files/file.h" #include "base/json/json_reader.h" #include "base/json/json_writer.h" @@ -3844,7 +3845,49 @@ std::get<0>(*failure_reason_receiver.result())); } -TEST_F(AuthenticatorImplTest, Transports) { +TEST_F(AuthenticatorImplTest, NoNonAuthoritativeTransports) { + NavigateAndCommit(GURL(kTestOrigin1)); + virtual_device_factory_->SetSupportedProtocol( + device::ProtocolVersion::kCtap2); + device::VirtualCtap2Device::Config config; + // If there are no transports in the attestation certificate, and none from + // getInfo, then none should be reported because there isn't enough + // information to say. + config.include_transports_in_attestation_certificate = false; + virtual_device_factory_->SetCtap2Config(config); + + MakeCredentialResult result = AuthenticatorMakeCredential(); + ASSERT_EQ(result.status, AuthenticatorStatus::SUCCESS); + + EXPECT_TRUE(result.response->transports.empty()); +} + +TEST_F(AuthenticatorImplTest, TransportsFromGetInfo) { + NavigateAndCommit(GURL(kTestOrigin1)); + virtual_device_factory_->SetSupportedProtocol( + device::ProtocolVersion::kCtap2); + device::VirtualCtap2Device::Config config; + config.include_transports_in_attestation_certificate = false; + config.transports_in_get_info = { + device::FidoTransportProtocol::kBluetoothLowEnergy}; + virtual_device_factory_->SetCtap2Config(config); + + MakeCredentialResult result = AuthenticatorMakeCredential(); + ASSERT_EQ(result.status, AuthenticatorStatus::SUCCESS); + + base::flat_set<device::FidoTransportProtocol> reported( + result.response->transports.begin(), result.response->transports.end()); + EXPECT_EQ(reported.size(), 2u); + // The transports from the getInfo are authoritative and so they should be + // reported. In addition to 'ble' from getInfo, 'usb' should be included + // because that's what was used to communicate with the virtual authenticator. + EXPECT_TRUE( + reported.contains(device::FidoTransportProtocol::kBluetoothLowEnergy)); + EXPECT_TRUE(reported.contains( + device::FidoTransportProtocol::kUsbHumanInterfaceDevice)); +} + +TEST_F(AuthenticatorImplTest, TransportsInAttestationCertificate) { NavigateAndCommit(GURL(kTestOrigin1)); for (auto protocol :
diff --git a/content/browser/webid/idp_network_request_manager.cc b/content/browser/webid/idp_network_request_manager.cc index c503328..e00f826 100644 --- a/content/browser/webid/idp_network_request_manager.cc +++ b/content/browser/webid/idp_network_request_manager.cc
@@ -511,15 +511,6 @@ std::move(callback).Run(FetchStatus::kSuccess, token->GetString()); } -void OnRevokeResponse(IdpNetworkRequestManager::RevokeCallback callback, - std::unique_ptr<std::string> response_body, - int response_code) { - IdpNetworkRequestManager::RevokeResponse status = - response_body ? IdpNetworkRequestManager::RevokeResponse::kSuccess - : IdpNetworkRequestManager::RevokeResponse::kError; - std::move(callback).Run(status); -} - void OnLogoutCompleted(IdpNetworkRequestManager::LogoutCallback callback, std::unique_ptr<std::string> response_body, int response_code) { @@ -690,30 +681,6 @@ return request_body; } -void IdpNetworkRequestManager::SendRevokeRequest(const GURL& revoke_url, - const std::string& client_id, - const std::string& hint, - RevokeCallback callback) { - std::string revoke_request_body; - if (!client_id.empty()) - revoke_request_body += "client_id=" + client_id; - - if (hint.empty()) { - std::move(callback).Run(RevokeResponse::kError); - return; - } - if (!revoke_request_body.empty()) - revoke_request_body += "&"; - revoke_request_body += "hint=" + hint; - - std::unique_ptr<network::SimpleURLLoader> url_loader = - CreateCredentialedUrlLoader(revoke_url, /* send_referrer= */ true, - revoke_request_body); - DownloadUrl(std::move(url_loader), - base::BindOnce(&OnRevokeResponse, std::move(callback)), - maxResponseSizeInKiB * 1024); -} - void IdpNetworkRequestManager::SendLogout(const GURL& logout_url, LogoutCallback callback) { // TODO(kenrb): Add browser test verifying that the response to this can
diff --git a/content/browser/webid/idp_network_request_manager.h b/content/browser/webid/idp_network_request_manager.h index 8406750..74ba378 100644 --- a/content/browser/webid/idp_network_request_manager.h +++ b/content/browser/webid/idp_network_request_manager.h
@@ -161,12 +161,6 @@ const std::string& request, TokenRequestCallback callback); - // Send a revoke token request to the IDP. - virtual void SendRevokeRequest(const GURL& revoke_url, - const std::string& client_id, - const std::string& hint, - RevokeCallback callback); - // Send logout request to a single target. virtual void SendLogout(const GURL& logout_url, LogoutCallback);
diff --git a/content/browser/webid/idp_network_request_manager_unittest.cc b/content/browser/webid/idp_network_request_manager_unittest.cc index 3f36c4e..65e8b144 100644 --- a/content/browser/webid/idp_network_request_manager_unittest.cc +++ b/content/browser/webid/idp_network_request_manager_unittest.cc
@@ -49,7 +49,6 @@ const char kTestTokenEndpoint[] = "https://idp.test/token_endpoint"; const char kTestClientMetadataEndpoint[] = "https://idp.test/client_metadata_endpoint"; -const char kTestRevocationEndpoint[] = "https://idp.test/revocation_endpoint"; class IdpNetworkRequestManagerTest : public ::testing::Test { public: @@ -173,26 +172,6 @@ return data; } - RevokeResponse SendRevokeRequestAndWaitForResponse( - const char* client_id, - const char* hint, - net::HttpStatusCode http_status = net::HTTP_NO_CONTENT) { - GURL revocation_endpoint(kTestRevocationEndpoint); - test_url_loader_factory().AddResponse(revocation_endpoint.spec(), "", - http_status); - - RevokeResponse status; - base::RunLoop run_loop; - auto callback = - base::BindLambdaForTesting([&](RevokeResponse revoke_status) { - status = revoke_status; - run_loop.Quit(); - }); - manager().SendRevokeRequest(revocation_endpoint, client_id, hint, - std::move(callback)); - run_loop.Run(); - return status; - } IdpNetworkRequestManager& manager() { return *manager_; } network::TestURLLoaderFactory& test_url_loader_factory() { @@ -803,35 +782,6 @@ ASSERT_EQ("", data.terms_of_service_url); } -// Tests the revoke implementation. -TEST_F(IdpNetworkRequestManagerTest, Revoke) { - bool called = false; - auto interceptor = - base::BindLambdaForTesting([&](const network::ResourceRequest& request) { - called = true; - EXPECT_EQ(GURL(kTestRpUrl), request.referrer); - // Check that the request body is correct - ASSERT_NE(request.request_body, nullptr); - ASSERT_EQ(1ul, request.request_body->elements()->size()); - const network::DataElement& elem = - request.request_body->elements()->at(0); - ASSERT_EQ(network::DataElement::Tag::kBytes, elem.type()); - const network::DataElementBytes& byte_elem = - elem.As<network::DataElementBytes>(); - EXPECT_EQ("client_id=xxx&hint=yyy", byte_elem.AsStringPiece()); - }); - test_url_loader_factory().SetInterceptor(interceptor); - RevokeResponse status = SendRevokeRequestAndWaitForResponse("xxx", "yyy"); - ASSERT_TRUE(called); - ASSERT_EQ(RevokeResponse::kSuccess, status); -} - -TEST_F(IdpNetworkRequestManagerTest, RevokeError) { - RevokeResponse status = - SendRevokeRequestAndWaitForResponse("xxx", "yyy", net::HTTP_FORBIDDEN); - ASSERT_EQ(RevokeResponse::kError, status); -} - // Tests that we correctly records metrics regarding approved_clients. TEST_F(IdpNetworkRequestManagerTest, RecordApprovedClientsMetrics) { base::HistogramTester histogram_tester;
diff --git a/content/browser/webid/test/mock_idp_network_request_manager.h b/content/browser/webid/test/mock_idp_network_request_manager.h index f57463a..e40ce51 100644 --- a/content/browser/webid/test/mock_idp_network_request_manager.h +++ b/content/browser/webid/test/mock_idp_network_request_manager.h
@@ -37,11 +37,6 @@ const std::string&, TokenRequestCallback)); MOCK_METHOD2(SendLogout, void(const GURL& logout_url, LogoutCallback)); - MOCK_METHOD4(SendRevokeRequest, - void(const GURL&, - const std::string&, - const std::string&, - RevokeCallback)); }; } // namespace content
diff --git a/content/browser/webui/shared_resources_data_source.cc b/content/browser/webui/shared_resources_data_source.cc index 2a7d4c2..f31820a 100644 --- a/content/browser/webui/shared_resources_data_source.cc +++ b/content/browser/webui/shared_resources_data_source.cc
@@ -58,6 +58,7 @@ #if BUILDFLAG(IS_CHROMEOS_ASH) const std::set<int> GetChromeosMojoResourceIds() { return std::set<int>{ + IDR_AUTH_FACTOR_CONFIG_MOJOM_WEBUI_JS, IDR_BLUETOOTH_CONFIG_MOJOM_WEBUI_JS, IDR_IP_ADDRESS_MOJOM_HTML, IDR_IP_ADDRESS_MOJOM_LITE_JS,
diff --git a/content/common/frame.mojom b/content/common/frame.mojom index cc49288..bb431cc 100644 --- a/content/common/frame.mojom +++ b/content/common/frame.mojom
@@ -651,6 +651,19 @@ blink.mojom.PolicyContainer policy_container; }; +// A per-navigation interface passed along with the BeginNavigation call, used +// to listen to the end of the renderer-initiated navigation cancelation window +// for that navigation. See comment below for more details. +interface NavigationRendererCancellationListener { + // Called when the navigation cancellation window for a renderer-initiated + // navigation ended, as the JS task in which the navigation started had + // finished running. Renderer-initiated navigations need to wait for this + // message before they can commit, as those navigations can be canceled by + // script (e.g. through calling window.stop() or document.open()) that runs + // on the same task. See RendererCancellationThrottle for more details. + RendererCancellationWindowEnded(); +}; + // Implemented by the frame server (i.e. the browser process). For messages that // must be associated with the IPC channel. interface FrameHost { @@ -786,13 +799,19 @@ // PolicyContainerHost is kept alive by LocalFrame's PolicyContainer. // TODO(ahemery): |navigation_client| should not be optional. Make it // mandatory. + // |renderer_cancellation_listener| is a per-navigation interface used to + // listen to the end of the renderer-initiated navigation cancelation window + // for this navigation. See comment for NavigationRendererCancellationListener + // for more details. BeginNavigation( blink.mojom.CommonNavigationParams common_params, blink.mojom.BeginNavigationParams begin_params, pending_remote<blink.mojom.BlobURLToken>? blob_url_token, pending_associated_remote<NavigationClient>? navigation_client, pending_remote<blink.mojom.PolicyContainerHostKeepAliveHandle>? - initiator_policy_container_keep_alive_handle); + initiator_policy_container_keep_alive_handle, + pending_receiver<NavigationRendererCancellationListener> + renderer_cancellation_listener); // Sent when a subresource response has started. //
diff --git a/content/public/android/java/src/org/chromium/content/browser/androidoverlay/DialogOverlayImpl.java b/content/public/android/java/src/org/chromium/content/browser/androidoverlay/DialogOverlayImpl.java index 4cc64b1..e89c6c4c 100644 --- a/content/public/android/java/src/org/chromium/content/browser/androidoverlay/DialogOverlayImpl.java +++ b/content/public/android/java/src/org/chromium/content/browser/androidoverlay/DialogOverlayImpl.java
@@ -21,6 +21,7 @@ import org.chromium.media.mojom.AndroidOverlayConfig; import org.chromium.mojo.system.MessagePipeHandle; import org.chromium.mojo.system.MojoException; +import org.chromium.ui.base.WindowAndroid; /** * Default AndroidOverlay impl. Uses a separate (shared) overlay thread to own a Dialog instance, @@ -55,6 +56,9 @@ // Observes the container view to update our location. private ViewTreeObserver mContainerViewViewTreeObserver; + private final AndroidOverlayConfig mConfig; + private final boolean mAsPanel; + /** * @param client Mojo client interface. * @param config initial overlay configuration. @@ -68,8 +72,8 @@ mClient = client; mReleasedRunnable = releasedRunnable; mLastRect = copyRect(config.rect); - - mDialogCore = new DialogOverlayCore(); + mConfig = config; + mAsPanel = asPanel; // Register to get token updates. Note that this may not call us back directly, since // |mDialogCore| hasn't been initialized yet. @@ -82,11 +86,8 @@ return; } - final DialogOverlayCore dialogCore = mDialogCore; - final Context context = ContextUtils.getApplicationContext(); DialogOverlayImplJni.get().getCompositorOffset( mNativeHandle, DialogOverlayImpl.this, config.rect); - dialogCore.initialize(context, config, this, asPanel); DialogOverlayImplJni.get().completeInit(mNativeHandle, DialogOverlayImpl.this); } @@ -186,19 +187,23 @@ } /** - * Callback from native that the window token has changed. + * Callback from native that the window has changed. */ @CalledByNative - public void onWindowToken(final IBinder token) { + public void onWindowAndroid(final WindowAndroid window) { ThreadUtils.assertOnUiThread(); - if (mDialogCore == null) return; + if (mDialogCore == null) { + initializeDialogCore(window); + return; + } // Forward this change. // Note that if we don't have a window token, then we could wait until we do, simply by // skipping sending null if we haven't sent any non-null token yet. If we're transitioning // between windows, that might make the client's job easier. It wouldn't have to guess when // a new token is available. + IBinder token = window != null ? window.getWindowToken() : null; mDialogCore.onWindowToken(token); } @@ -242,6 +247,20 @@ mClient.onPowerEfficientState(isPowerEfficient); } + /** Initialize |mDialogCore| when the window is available. */ + private void initializeDialogCore(WindowAndroid window) { + ThreadUtils.assertOnUiThread(); + + if (window == null) return; + + Context context = window.getContext().get(); + if (ContextUtils.activityFromContext(context) == null) return; + + mDialogCore = new DialogOverlayCore(); + mDialogCore.initialize(context, mConfig, DialogOverlayImpl.this, mAsPanel); + mDialogCore.onWindowToken(window.getWindowToken()); + } + /** * Unregister for callbacks, unregister any surface that we have, and forget about * |mDialogCore|. Multiple calls are okay.
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/androidoverlay/DialogOverlayImplTest.java b/content/public/android/javatests/src/org/chromium/content/browser/androidoverlay/DialogOverlayImplTest.java index 24932a2f0..967ca28 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/androidoverlay/DialogOverlayImplTest.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/androidoverlay/DialogOverlayImplTest.java
@@ -4,6 +4,11 @@ package org.chromium.content.browser.androidoverlay; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import android.content.Context; + import androidx.test.filters.SmallTest; import org.junit.Assert; @@ -15,6 +20,8 @@ import org.chromium.base.test.util.Feature; import org.chromium.content.browser.androidoverlay.DialogOverlayImplTestRule.Client; import org.chromium.content_public.browser.test.util.TestThreadUtils; +import org.chromium.ui.base.ImmutableWeakReference; +import org.chromium.ui.base.WindowAndroid; /** * Tests for DialogOverlayImpl. @@ -147,4 +154,18 @@ }); Assert.assertEquals(Client.TEST_MARKER, mActivityTestRule.getClient().nextEvent().which); } + + @Test + @SmallTest + @Feature({"AndroidOverlay"}) + public void testEmptyWindowAndroidDoesntCrash() { + // Test that receiving a WindowAndroid that doesn't have activity donesn't cause crash. + ImmutableWeakReference<Context> nullContextWeakRef = new ImmutableWeakReference<>(null); + WindowAndroid mockWindowAndroid = mock(WindowAndroid.class); + when(mockWindowAndroid.getContext()).thenReturn(nullContextWeakRef); + final DialogOverlayImpl overlay = mActivityTestRule.createOverlay(0, 0, 10, 10); + + TestThreadUtils.runOnUiThreadBlocking( + () -> { overlay.onWindowAndroid(mockWindowAndroid); }); + } }
diff --git a/content/public/app/content_main_delegate.cc b/content/public/app/content_main_delegate.cc index ce6b8b4..148b1ebe 100644 --- a/content/public/app/content_main_delegate.cc +++ b/content/public/app/content_main_delegate.cc
@@ -14,8 +14,8 @@ namespace content { -bool ContentMainDelegate::BasicStartupComplete(int* exit_code) { - return false; +absl::optional<int> ContentMainDelegate::BasicStartupComplete() { + return absl::nullopt; } absl::variant<int, MainFunctionParams> ContentMainDelegate::RunProcess( @@ -46,6 +46,10 @@ return true; } +absl::optional<int> ContentMainDelegate::PreBrowserMain() { + return absl::nullopt; +} + bool ContentMainDelegate::ShouldCreateFeatureList(InvokedIn invoked_in) { return true; } @@ -55,6 +59,11 @@ return nullptr; } +absl::optional<int> ContentMainDelegate::PostEarlyInitialization( + InvokedIn invoked_in) { + return absl::nullopt; +} + ContentClient* ContentMainDelegate::CreateContentClient() { return new ContentClient(); }
diff --git a/content/public/app/content_main_delegate.h b/content/public/app/content_main_delegate.h index d2fafdaa..f40146c 100644 --- a/content/public/app/content_main_delegate.h +++ b/content/public/app/content_main_delegate.h
@@ -12,6 +12,7 @@ #include "build/build_config.h" #include "content/common/content_export.h" #include "content/public/common/main_function_params.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/abseil-cpp/absl/types/variant.h" namespace variations { @@ -50,11 +51,12 @@ virtual ~ContentMainDelegate() = default; // Tells the embedder that the absolute basic startup has been done, i.e. - // it's now safe to create singletons and check the command line. Return true - // if the process should exit afterwards, and if so, |exit_code| should be - // set. This is the place for embedder to do the things that must happen at - // the start. Most of its startup code should be in the methods below. - virtual bool BasicStartupComplete(int* exit_code); + // it's now safe to create singletons and check the command line. Return an + // error code if the process should exit afterwards. This is the place for + // embedder to do the things that must happen at the start. Most of its + // startup code should be in the methods below, handling of early exit + // command-line switches can wait until PreBrowserMain at the latest. + virtual absl::optional<int> BasicStartupComplete(); // This is where the embedder puts all of its startup code that needs to run // before the sandbox is engaged. @@ -107,8 +109,10 @@ // Allows the embedder to perform platform-specific initialization before // BrowserMain() is invoked (i.e. before BrowserMainRunner, BrowserMainLoop, - // BrowserMainParts, etc. are created). - virtual void PreBrowserMain() {} + // BrowserMainParts, etc. are created). Return an error code if the process + // should exit afterwards. This is the place for embedder to do the things + // that can shortcut browser execution (i.e. command-line switches). + virtual absl::optional<int> PreBrowserMain(); // Returns true if content should create field trials and initialize the // FeatureList instance for this process. Default implementation returns true. @@ -135,8 +139,9 @@ // If ShouldCreateFeatureList() returns true for `invoked_in`, the // field trials and FeatureList have been initialized. Otherwise, the // implementation must initialize the field trials and FeatureList before - // returning from PostEarlyInitialization. - virtual void PostEarlyInitialization(InvokedIn invoked_in) {} + // returning from PostEarlyInitialization. Return an error code if the process + // should exit afterwards. + virtual absl::optional<int> PostEarlyInitialization(InvokedIn invoked_in); #if BUILDFLAG(IS_WIN) // Allows the embedder to indicate that console control events (e.g., Ctrl-C,
diff --git a/content/public/test/browser_test_base.cc b/content/public/test/browser_test_base.cc index 53fa7e6..cb6b283 100644 --- a/content/public/test/browser_test_base.cc +++ b/content/public/test/browser_test_base.cc
@@ -602,8 +602,8 @@ // The delegate should have been set by JNI_OnLoad for the test target. DCHECK(delegate); - bool startup_error = delegate->BasicStartupComplete(/*exit_code=*/nullptr); - DCHECK(!startup_error); + absl::optional<int> startup_error = delegate->BasicStartupComplete(); + ASSERT_FALSE(startup_error.has_value()); InitializeMojo(); @@ -628,7 +628,9 @@ base::ThreadPoolInstance::Create("Browser"); - delegate->PreBrowserMain(); + absl::optional<int> pre_browser_main_exit_code = delegate->PreBrowserMain(); + ASSERT_FALSE(pre_browser_main_exit_code.has_value()); + BrowserTaskExecutor::Create(); auto* provider = delegate->CreateVariationsIdsProvider(); @@ -637,7 +639,9 @@ variations::VariationsIdsProvider::Mode::kUseSignedInState); } - delegate->PostEarlyInitialization(invoked_in_browser); + absl::optional<int> post_early_initialization_exit_code = + delegate->PostEarlyInitialization(invoked_in_browser); + ASSERT_FALSE(post_early_initialization_exit_code.has_value()); StartBrowserThreadPool(); BrowserTaskExecutor::PostFeatureListSetup();
diff --git a/content/public/test/content_browser_test_shell_main_delegate.cc b/content/public/test/content_browser_test_shell_main_delegate.cc index bb72869..31907b0 100644 --- a/content/public/test/content_browser_test_shell_main_delegate.cc +++ b/content/public/test/content_browser_test_shell_main_delegate.cc
@@ -6,6 +6,7 @@ #include "base/test/task_environment.h" #include "content/shell/browser/shell_content_browser_client.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/abseil-cpp/absl/types/variant.h" namespace content { @@ -29,13 +30,15 @@ default; #if BUILDFLAG(IS_CHROMEOS_LACROS) -void ContentBrowserTestShellMainDelegate::PostEarlyInitialization( +absl::optional<int> +ContentBrowserTestShellMainDelegate::PostEarlyInitialization( InvokedIn invoked_in) { if (absl::holds_alternative<InvokedInBrowserProcess>(invoked_in)) { // Browser tests on Lacros requires a non-null LacrosService. lacros_service_ = std::make_unique<chromeos::LacrosService>(); } ShellMainDelegate::PostEarlyInitialization(invoked_in); + return absl::nullopt; } #endif // BUILDFLAG(IS_CHROMEOS_LACROS)
diff --git a/content/public/test/content_browser_test_shell_main_delegate.h b/content/public/test/content_browser_test_shell_main_delegate.h index ed1ffd4..e8ee625d 100644 --- a/content/public/test/content_browser_test_shell_main_delegate.h +++ b/content/public/test/content_browser_test_shell_main_delegate.h
@@ -9,6 +9,7 @@ #include "build/chromeos_buildflags.h" #include "content/shell/app/shell_main_delegate.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #if BUILDFLAG(IS_CHROMEOS_LACROS) // TODO(erikchen): Move #include to .cc file and forward declare @@ -26,7 +27,7 @@ // ContentMainDelegate implementation: #if BUILDFLAG(IS_CHROMEOS_LACROS) - void PostEarlyInitialization(InvokedIn invoked_in) override; + absl::optional<int> PostEarlyInitialization(InvokedIn invoked_in) override; #endif // ShellMainDelegate overrides. content::ContentBrowserClient* CreateContentBrowserClient() override;
diff --git a/content/renderer/accessibility/blink_ax_tree_source.cc b/content/renderer/accessibility/blink_ax_tree_source.cc index df5f6b3..c072fc2 100644 --- a/content/renderer/accessibility/blink_ax_tree_source.cc +++ b/content/renderer/accessibility/blink_ax_tree_source.cc
@@ -261,51 +261,6 @@ load_inline_text_boxes_ids_.insert(id); } -void BlinkAXTreeSource::PopulateAXRelativeBounds(WebAXObject obj, - ui::AXRelativeBounds* bounds, - bool* clips_children) const { - WebAXObject offset_container; - gfx::RectF bounds_in_container; - gfx::Transform container_transform; - obj.GetRelativeBounds(offset_container, bounds_in_container, - container_transform, clips_children); - bounds->bounds = bounds_in_container; - if (!offset_container.IsDetached()) - bounds->offset_container_id = offset_container.AxID(); - - if (content::AXShouldIncludePageScaleFactorInRoot() && obj.Equals(root())) { - const WebView* web_view = render_frame_->GetWebView(); - container_transform.Scale(web_view->PageScaleFactor(), - web_view->PageScaleFactor()); - container_transform.Translate( - -web_view->VisualViewportOffset().OffsetFromOrigin()); - } - - if (!container_transform.IsIdentity()) - bounds->transform = std::make_unique<gfx::Transform>(container_transform); -} - -bool BlinkAXTreeSource::HasCachedBoundingBox(int32_t id) const { - return base::Contains(cached_bounding_boxes_, id); -} - -const ui::AXRelativeBounds& BlinkAXTreeSource::GetCachedBoundingBox( - int32_t id) const { - auto iter = cached_bounding_boxes_.find(id); - DCHECK(iter != cached_bounding_boxes_.end()); - return iter->second; -} - -void BlinkAXTreeSource::SetCachedBoundingBox( - int32_t id, - const ui::AXRelativeBounds& bounds) { - cached_bounding_boxes_[id] = bounds; -} - -size_t BlinkAXTreeSource::GetCachedBoundingBoxCount() const { - return cached_bounding_boxes_.size(); -} - bool BlinkAXTreeSource::GetTreeData(ui::AXTreeData* tree_data) const { CHECK(frozen_); tree_data->doctype = "html"; @@ -471,7 +426,7 @@ } void BlinkAXTreeSource::SerializerClearedNode(int32_t node_id) { - cached_bounding_boxes_.erase(node_id); + GetRoot().SerializerClearedNode(node_id); } void BlinkAXTreeSource::SerializeNode(WebAXObject src, @@ -505,10 +460,6 @@ return; } - // Bounding boxes are needed on all nodes, including ignored, for hit testing. - SerializeBoundingBoxAttributes(src, dst); - cached_bounding_boxes_[dst->id] = dst->relative_bounds; - // Return early. The following attributes are unnecessary for ignored nodes. // Exception: focusable ignored nodes are fully serialized, so that reasonable // verbalizations can be made if they actually receive focus. @@ -540,20 +491,6 @@ } } -void BlinkAXTreeSource::SerializeBoundingBoxAttributes( - WebAXObject src, - ui::AXNodeData* dst) const { - bool clips_children = false; - PopulateAXRelativeBounds(src, &dst->relative_bounds, &clips_children); - if (clips_children) - dst->AddBoolAttribute(ax::mojom::BoolAttribute::kClipsChildren, true); - - if (src.IsLineBreakingObject()) { - dst->AddBoolAttribute(ax::mojom::BoolAttribute::kIsLineBreakingObject, - true); - } -} - blink::WebDocument BlinkAXTreeSource::GetMainDocument() const { CHECK(frozen_); return document_;
diff --git a/content/renderer/accessibility/blink_ax_tree_source.h b/content/renderer/accessibility/blink_ax_tree_source.h index 0d0273a..6a6d82b 100644 --- a/content/renderer/accessibility/blink_ax_tree_source.h +++ b/content/renderer/accessibility/blink_ax_tree_source.h
@@ -98,16 +98,6 @@ bool ShouldLoadInlineTextBoxes(const blink::WebAXObject& obj) const; void SetLoadInlineTextBoxesForId(int32_t id); - void PopulateAXRelativeBounds(blink::WebAXObject obj, - ui::AXRelativeBounds* bounds, - bool* clips_children = nullptr) const; - - // Cached bounding boxes. - bool HasCachedBoundingBox(int32_t id) const; - const ui::AXRelativeBounds& GetCachedBoundingBox(int32_t id) const; - void SetCachedBoundingBox(int32_t id, const ui::AXRelativeBounds& bounds); - size_t GetCachedBoundingBoxCount() const; - // AXTreeSource implementation. bool GetTreeData(ui::AXTreeData* tree_data) const override; blink::WebAXObject GetRoot() const override; @@ -147,8 +137,6 @@ return focus_; } - void SerializeBoundingBoxAttributes(blink::WebAXObject src, - ui::AXNodeData* dst) const; blink::WebAXObject ComputeRoot() const; // Max length for attributes such as aria-label. @@ -197,9 +185,6 @@ // how to turn on automatic image labels is provided only once. mutable absl::optional<int32_t> first_unlabeled_image_id_ = absl::nullopt; - // Current bounding box of every object, so we can detect when it moves. - mutable std::map<int, ui::AXRelativeBounds> cached_bounding_boxes_; - // These are updated when calling |Freeze|. bool frozen_ = false; blink::WebDocument document_;
diff --git a/content/renderer/accessibility/render_accessibility_impl.cc b/content/renderer/accessibility/render_accessibility_impl.cc index 558eba7..d170e36 100644 --- a/content/renderer/accessibility/render_accessibility_impl.cc +++ b/content/renderer/accessibility/render_accessibility_impl.cc
@@ -1103,9 +1103,6 @@ void RenderAccessibilityImpl::SendLocationChanges() { TRACE_EVENT0("accessibility", "RenderAccessibilityImpl::SendLocationChanges"); - - std::vector<blink::mojom::LocationChangesPtr> changes; - // Update layout on the root of the tree. WebAXObject root = tree_source_->GetRoot(); @@ -1114,37 +1111,7 @@ if (!root.MaybeUpdateLayoutAndCheckValidity()) return; - blink::WebVector<WebAXObject> changed_bounds_objects; - root.GetAllObjectsWithChangedBounds(changed_bounds_objects); - for (const WebAXObject& obj : changed_bounds_objects) { - // See if we had a previous location. If not, this whole subtree must - // be new, so no need to update. - int id = obj.AxID(); - if (!tree_source_->HasCachedBoundingBox(id)) - continue; - - // If the location has changed, append it to the IPC message. - ui::AXRelativeBounds new_location; - tree_source_->PopulateAXRelativeBounds(obj, &new_location); - if (new_location != tree_source_->GetCachedBoundingBox(id)) - changes.push_back(blink::mojom::LocationChanges::New(id, new_location)); - - // Save the new location. - tree_source_->SetCachedBoundingBox(id, new_location); - } - - if (changes.empty()) - return; - - // Ensure that the number of cached bounding boxes doesn't exceed the - // number of nodes in the tree, that would indicate the cache could - // grow without bounds. Calls from the serializer to - // BlinkAXTreeSerializer::SerializerClearedNode are supposed to keep the - // cache trimmed to only actual nodes in the tree. - DCHECK_LE(tree_source_->GetCachedBoundingBoxCount(), - serializer_->ClientTreeNodeCount()); - - render_accessibility_manager_->HandleLocationChanges(std::move(changes)); + root.SerializeLocationChanges(); } void RenderAccessibilityImpl::OnAccessibilityEventsHandled() {
diff --git a/content/renderer/accessibility/render_accessibility_impl_browsertest.cc b/content/renderer/accessibility/render_accessibility_impl_browsertest.cc index 6bd7c8c..9bbf224 100644 --- a/content/renderer/accessibility/render_accessibility_impl_browsertest.cc +++ b/content/renderer/accessibility/render_accessibility_impl_browsertest.cc
@@ -166,12 +166,12 @@ void BindRenderAccessibilityHostReceiver( mojo::ScopedMessagePipeHandle handle) { - receiver_.Bind(mojo::PendingReceiver<blink::mojom::RenderAccessibilityHost>( - std::move(handle))); + receiver_.Add(this, + mojo::PendingReceiver<blink::mojom::RenderAccessibilityHost>( + std::move(handle))); - receiver_.set_disconnect_handler(base::BindOnce( - [](mojo::Receiver<blink::mojom::RenderAccessibilityHost>* receiver) { - receiver->reset(); + receiver_.set_disconnect_handler(base::BindRepeating( + [](mojo::ReceiverSet<blink::mojom::RenderAccessibilityHost>* receiver) { }, base::Unretained(&receiver_))); } @@ -209,7 +209,7 @@ private: void BindFrameHostReceiver(mojo::ScopedInterfaceEndpointHandle handle); - mojo::Receiver<blink::mojom::RenderAccessibilityHost> receiver_{this}; + mojo::ReceiverSet<blink::mojom::RenderAccessibilityHost> receiver_; mojo::Remote<blink::mojom::RenderAccessibilityHost> local_frame_host_remote_; std::vector<::ui::AXTreeUpdate> handled_updates_;
diff --git a/content/renderer/accessibility/render_accessibility_manager.cc b/content/renderer/accessibility/render_accessibility_manager.cc index b8eeeb8..8ec2ffb3 100644 --- a/content/renderer/accessibility/render_accessibility_manager.cc +++ b/content/renderer/accessibility/render_accessibility_manager.cc
@@ -103,12 +103,6 @@ std::move(updates_and_events), reset_token, std::move(callback)); } -void RenderAccessibilityManager::HandleLocationChanges( - std::vector<blink::mojom::LocationChangesPtr> changes) { - GetOrCreateRemoteRenderAccessibilityHost()->HandleAXLocationChanges( - std::move(changes)); -} - mojo::Remote<blink::mojom::RenderAccessibilityHost>& RenderAccessibilityManager::GetOrCreateRemoteRenderAccessibilityHost() { if (!render_accessibility_host_) {
diff --git a/content/renderer/accessibility/render_accessibility_manager.h b/content/renderer/accessibility/render_accessibility_manager.h index 88b09a45..e4dd126 100644 --- a/content/renderer/accessibility/render_accessibility_manager.h +++ b/content/renderer/accessibility/render_accessibility_manager.h
@@ -79,8 +79,6 @@ blink::mojom::AXUpdatesAndEventsPtr updates_and_events, int32_t reset_token, blink::mojom::RenderAccessibilityHost::HandleAXEventsCallback callback); - void HandleLocationChanges( - std::vector<blink::mojom::LocationChangesPtr> changes); void CloseConnection();
diff --git a/content/renderer/navigation_client.cc b/content/renderer/navigation_client.cc index b577b6f1..a809e54 100644 --- a/content/renderer/navigation_client.cc +++ b/content/renderer/navigation_client.cc
@@ -7,6 +7,7 @@ #include "base/bind.h" #include "base/callback_helpers.h" #include "base/check.h" +#include "content/common/frame.mojom.h" #include "content/renderer/render_frame_impl.h" #include "services/network/public/mojom/fetch_api.mojom.h" #include "third_party/blink/public/common/loader/resource_type_util.h" @@ -91,9 +92,32 @@ SetDisconnectionHandler(); } -void NavigationClient::MarkWasInitiatedInThisFrame() { +void NavigationClient::SetUpRendererInitiatedNavigation( + mojo::PendingRemote<mojom::NavigationRendererCancellationListener> + renderer_cancellation_listener_remote) { DCHECK(!was_initiated_in_this_frame_); was_initiated_in_this_frame_ = true; + renderer_cancellation_listener_remote_.Bind( + std::move(renderer_cancellation_listener_remote), + render_frame_->GetTaskRunner( + blink::TaskType::kInternalNavigationCancellation)); + + // Renderer-initiated navigations can be canceled from the JS task it was + // initiated from. If we post a task here, the task will run after the JS task + // that started the navigation had finished running. So, we can post a task to + // notify the browser that navigation cancellation is no longer possible from + // here. + render_frame_->GetTaskRunner(blink::TaskType::kInternalNavigationCancellation) + ->PostTask(FROM_HERE, + base::BindOnce( + &NavigationClient::NotifyNavigationCancellationWindowEnded, + weak_ptr_factory_.GetWeakPtr())); +} + +void NavigationClient::NotifyNavigationCancellationWindowEnded() { + DCHECK(was_initiated_in_this_frame_); + renderer_cancellation_listener_remote_->RendererCancellationWindowEnded(); + renderer_cancellation_listener_remote_.reset(); } void NavigationClient::SetDisconnectionHandler() {
diff --git a/content/renderer/navigation_client.h b/content/renderer/navigation_client.h index 7405c48..8432f4db 100644 --- a/content/renderer/navigation_client.h +++ b/content/renderer/navigation_client.h
@@ -5,6 +5,7 @@ #ifndef CONTENT_RENDERER_NAVIGATION_CLIENT_H_ #define CONTENT_RENDERER_NAVIGATION_CLIENT_H_ +#include "content/common/frame.mojom.h" #include "content/common/navigation_client.mojom.h" #include "content/public/common/alternative_error_page_override_info.mojom.h" #include "mojo/public/cpp/bindings/associated_receiver.h" @@ -58,23 +59,39 @@ void Bind(mojo::PendingAssociatedReceiver<mojom::NavigationClient> receiver); // See NavigationState::was_initiated_in_this_frame for details. - void MarkWasInitiatedInThisFrame(); bool was_initiated_in_this_frame() const { return was_initiated_in_this_frame_; } + // Sets up a NavigationClient for a renderer-initiated navigation initiated + // in this frame. This includes setting `was_initiated_in_this_frame_` to + // true and setting up a task to send a navigation-cancellation-window-ended + // notification to the browser. + void SetUpRendererInitiatedNavigation( + mojo::PendingRemote<mojom::NavigationRendererCancellationListener> + renderer_cancellation_listener_remote); + private: // OnDroppedNavigation is bound from BeginNavigation till CommitNavigation. // During this period, it is called when the interface pipe is closed from the - // browser side, leading to the ongoing navigation cancelation. + // browser side, leading to the ongoing navigation cancellation. void OnDroppedNavigation(); void SetDisconnectionHandler(); void ResetDisconnectionHandler(); + // The window of time in which the renderer can cancel this navigation had + // ended, so notify the browser about it. + void NotifyNavigationCancellationWindowEnded(); + mojo::AssociatedReceiver<mojom::NavigationClient> navigation_client_receiver_{ this}; + mojo::Remote<mojom::NavigationRendererCancellationListener> + renderer_cancellation_listener_remote_; RenderFrameImpl* render_frame_; + // See NavigationState::was_initiated_in_this_frame for details. bool was_initiated_in_this_frame_ = false; + + base::WeakPtrFactory<NavigationClient> weak_ptr_factory_{this}; }; } // namespace content
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc index cd5f4e8f..e2e1290 100644 --- a/content/renderer/render_frame_impl.cc +++ b/content/renderer/render_frame_impl.cc
@@ -4143,6 +4143,8 @@ } NotifyObserversOfFailedProvisionalLoad(); // See comment in header for more information of how navigation cleanup works. + // Note: This might not actually cancel the navigation if the navigation is + // already in the process of committing to a different RenderFrame. navigation_client_impl_.reset(); } @@ -5798,7 +5800,10 @@ navigation_client_remote; BindNavigationClient( navigation_client_remote.InitWithNewEndpointAndPassReceiver()); - navigation_client_impl_->MarkWasInitiatedInThisFrame(); + mojo::PendingReceiver<mojom::NavigationRendererCancellationListener> + renderer_cancellation_listener_receiver; + navigation_client_impl_->SetUpRendererInitiatedNavigation( + renderer_cancellation_listener_receiver.InitWithNewPipeAndPassRemote()); bool current_frame_has_download_sandbox_flag = !frame_->IsAllowedToDownload(); bool has_download_sandbox_flag = @@ -5820,7 +5825,8 @@ request_destination), std::move(begin_navigation_params), std::move(blob_url_token), std::move(navigation_client_remote), - std::move(initiator_policy_container_keep_alive_handle)); + std::move(initiator_policy_container_keep_alive_handle), + std::move(renderer_cancellation_listener_receiver)); } void RenderFrameImpl::DecodeDataURL(
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h index 351a3a2..a409fae 100644 --- a/content/renderer/render_frame_impl.h +++ b/content/renderer/render_frame_impl.h
@@ -1289,7 +1289,7 @@ // request NavigationClient // // Note that the initiating RenderFrameImpl does *not* own the request - // NavigationClient. Rather, the RanderFrameImpl that the navigation *targets* + // NavigationClient. Rather, the RenderFrameImpl that the navigation *targets* // is the RenderFrameImpl that owns the request NavigationClient. // // ## Commit NavigationClient ## @@ -1318,8 +1318,11 @@ // Note that using RenderDocument means that all cross-document navigations // will use a provisional RenderFrameImpl: as such, all cross-document // navigations with RenderDocument will ignore cancellation after - // READY_TO_COMMIT. This is a known compatibility issue with RenderDocument - // and will need to eventually be addressed. + // READY_TO_COMMIT. To handle this, all renderer-initiated navigations will + // not enter the READY_TO_COMMIT stage until the task that initiated the + // navigation finishes, to ensure that no renderer-initiated navigation + // cancellation can take place after READY_TO_COMMIT. For more details, see + // RendererCancellationThrottle. std::unique_ptr<NavigationClient> navigation_client_impl_; // Creates various media clients.
diff --git a/content/shell/app/shell_main_delegate.cc b/content/shell/app/shell_main_delegate.cc index 611d8016..f5ae44c 100644 --- a/content/shell/app/shell_main_delegate.cc +++ b/content/shell/app/shell_main_delegate.cc
@@ -134,11 +134,7 @@ ShellMainDelegate::~ShellMainDelegate() { } -bool ShellMainDelegate::BasicStartupComplete(int* exit_code) { - int dummy; - if (!exit_code) - exit_code = &dummy; - +absl::optional<int> ShellMainDelegate::BasicStartupComplete() { base::CommandLine& command_line = *base::CommandLine::ForCurrentProcess(); if (command_line.HasSwitch("run-layout-test")) { std::cerr << std::string(79, '*') << "\n" @@ -184,7 +180,7 @@ RegisterShellPathProvider(); - return false; + return absl::nullopt; } bool ShellMainDelegate::ShouldCreateFeatureList(InvokedIn invoked_in) { @@ -330,17 +326,20 @@ #endif } -void ShellMainDelegate::PreBrowserMain() { +absl::optional<int> ShellMainDelegate::PreBrowserMain() { #if BUILDFLAG(IS_MAC) RegisterShellCrApp(); #endif + return absl::nullopt; } -void ShellMainDelegate::PostEarlyInitialization(InvokedIn invoked_in) { +absl::optional<int> ShellMainDelegate::PostEarlyInitialization( + InvokedIn invoked_in) { if (!ShouldCreateFeatureList(invoked_in)) { // Apply field trial testing configuration since content did not. browser_client_->CreateFeatureListAndFieldTrials(); } + return absl::nullopt; } ContentClient* ShellMainDelegate::CreateContentClient() {
diff --git a/content/shell/app/shell_main_delegate.h b/content/shell/app/shell_main_delegate.h index 7044aea..5777996 100644 --- a/content/shell/app/shell_main_delegate.h +++ b/content/shell/app/shell_main_delegate.h
@@ -9,6 +9,7 @@ #include "build/build_config.h" #include "content/public/app/content_main_delegate.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace content { class ShellContentClient; @@ -31,7 +32,7 @@ ~ShellMainDelegate() override; // ContentMainDelegate implementation: - bool BasicStartupComplete(int* exit_code) override; + absl::optional<int> BasicStartupComplete() override; bool ShouldCreateFeatureList(InvokedIn invoked_in) override; void PreSandboxStartup() override; absl::variant<int, MainFunctionParams> RunProcess( @@ -40,8 +41,8 @@ #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) void ZygoteForked() override; #endif - void PreBrowserMain() override; - void PostEarlyInitialization(InvokedIn invoked_in) override; + absl::optional<int> PreBrowserMain() override; + absl::optional<int> PostEarlyInitialization(InvokedIn invoked_in) override; ContentClient* CreateContentClient() override; ContentBrowserClient* CreateContentBrowserClient() override; ContentGpuClient* CreateContentGpuClient() override;
diff --git a/content/test/data/attribution_reporting/databases/version_34.sql b/content/test/data/attribution_reporting/databases/version_34.sql index 084e377..66806456 100644 --- a/content/test/data/attribution_reporting/databases/version_34.sql +++ b/content/test/data/attribution_reporting/databases/version_34.sql
@@ -48,4 +48,11 @@ CREATE INDEX contribution_aggregation_id_idx ON aggregatable_contributions(aggregation_id); +INSERT INTO sources VALUES(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19); + +INSERT INTO rate_limits VALUES +(1,0,1,4,5,6,7,8,9), +(2,0,3,4,5,6,7,8,9), +(3,1,1,4,5,6,7,8,9); + COMMIT;
diff --git a/content/test/data/attribution_reporting/databases/version_35.sql b/content/test/data/attribution_reporting/databases/version_35.sql new file mode 100644 index 0000000..b2da41a --- /dev/null +++ b/content/test/data/attribution_reporting/databases/version_35.sql
@@ -0,0 +1,51 @@ +PRAGMA foreign_keys=OFF; + +BEGIN TRANSACTION; + +CREATE TABLE sources(source_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,source_event_id INTEGER NOT NULL,source_origin TEXT NOT NULL,destination_origin TEXT NOT NULL,reporting_origin TEXT NOT NULL,source_time INTEGER NOT NULL,expiry_time INTEGER NOT NULL,num_attributions INTEGER NOT NULL,event_level_active INTEGER NOT NULL,aggregatable_active INTEGER NOT NULL,destination_site TEXT NOT NULL,source_type INTEGER NOT NULL,attribution_logic INTEGER NOT NULL,priority INTEGER NOT NULL,source_site TEXT NOT NULL,debug_key INTEGER,aggregatable_budget_consumed INTEGER NOT NULL,aggregatable_source BLOB NOT NULL,filter_data BLOB NOT NULL); + +CREATE TABLE event_level_reports(report_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,source_id INTEGER NOT NULL,trigger_data INTEGER NOT NULL,trigger_time INTEGER NOT NULL,report_time INTEGER NOT NULL,priority INTEGER NOT NULL,failed_send_attempts INTEGER NOT NULL,external_report_id TEXT NOT NULL,debug_key INTEGER); + +CREATE TABLE rate_limits(id INTEGER PRIMARY KEY NOT NULL,scope INTEGER NOT NULL,source_id INTEGER NOT NULL,source_site TEXT NOT NULL,source_origin TEXT NOT NULL,destination_site TEXT NOT NULL,destination_origin TEXT NOT NULL,reporting_origin TEXT NOT NULL,time INTEGER NOT NULL,expiry_time INTEGER NOT NULL); + +CREATE TABLE dedup_keys(source_id INTEGER NOT NULL,dedup_key INTEGER NOT NULL,PRIMARY KEY(source_id,dedup_key))WITHOUT ROWID; + +CREATE TABLE aggregatable_report_metadata(aggregation_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,source_id INTEGER NOT NULL,trigger_time INTEGER NOT NULL,debug_key INTEGER,external_report_id TEXT NOT NULL,report_time INTEGER NOT NULL,failed_send_attempts INTEGER NOT NULL,initial_report_time INTEGER NOT NULL); + +CREATE TABLE aggregatable_contributions(contribution_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,aggregation_id INTEGER NOT NULL,key_high_bits INTEGER NOT NULL,key_low_bits INTEGER NOT NULL,value INTEGER NOT NULL); + +CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY, value LONGVARCHAR); + +INSERT INTO meta VALUES('mmap_status','-1'); +INSERT INTO meta VALUES('version','35'); +INSERT INTO meta VALUES('last_compatible_version','35'); + +CREATE INDEX sources_by_active_destination_site_reporting_origin ON sources(event_level_active,aggregatable_active,destination_site,reporting_origin); + +CREATE INDEX sources_by_expiry_time ON sources(expiry_time); + +CREATE INDEX sources_by_origin ON sources(source_origin); + +CREATE INDEX active_unattributed_sources_by_site_reporting_origin ON sources(source_site,reporting_origin)WHERE event_level_active=1 AND num_attributions=0 AND aggregatable_active=1 AND aggregatable_budget_consumed=0; + +CREATE INDEX event_level_reports_by_report_time ON event_level_reports(report_time); + +CREATE INDEX event_level_reports_by_source_id ON event_level_reports(source_id); + +CREATE INDEX rate_limit_source_site_reporting_origin_idx ON rate_limits(scope,source_site,reporting_origin); + +CREATE INDEX rate_limit_reporting_origin_idx ON rate_limits(scope,destination_site,source_site); + +CREATE INDEX rate_limit_time_idx ON rate_limits(time); + +CREATE INDEX rate_limit_source_id_idx ON rate_limits(source_id); + +CREATE INDEX aggregate_source_id_idx ON aggregatable_report_metadata(source_id); + +CREATE INDEX aggregate_trigger_time_idx ON aggregatable_report_metadata(trigger_time); + +CREATE INDEX aggregate_report_time_idx ON aggregatable_report_metadata(report_time); + +CREATE INDEX contribution_aggregation_id_idx ON aggregatable_contributions(aggregation_id); + +COMMIT;
diff --git a/content/test/data/gpu/pixel_webgpu_canvas_capture_to_video.html b/content/test/data/gpu/pixel_webgpu_canvas_capture_to_video.html deleted file mode 100644 index 3ddd1bcf..0000000 --- a/content/test/data/gpu/pixel_webgpu_canvas_capture_to_video.html +++ /dev/null
@@ -1,139 +0,0 @@ -<!DOCTYPE html> -<html> - -<head> - <title>WebGPU canvas' capture as video stream test</title> - <style type="text/css"> - .nomargin { - margin: 0px auto; - } - </style> - <script type="text/javascript" src="pixel_webgpu_util.js"></script> - <script type="text/javascript"> - var g_swapsBeforeAck = 15; - - async function main() { - loadWebrtc(); - - const gpuCanvas = document.getElementById('canvas_gpu'); - const [device, swapChain] = await webGpuUtils.init(gpuCanvas); - if (!device || !swapChain) { - console.error("Failed to initialize WebGPU - skipping test"); - domAutomationController.send("FAILURE"); - return; - } - - function render() { - const gpuContext = gpuCanvas.getContext('webgpu'); - - webGpuUtils.fourColorsTest(device, swapChain, gpuCanvas.width, - gpuCanvas.height); - - waitForFinish(); - } - - function waitForFinish() { - if (g_swapsBeforeAck == 0) { - domAutomationController.send("SUCCESS"); - } else { - g_swapsBeforeAck--; - window.requestAnimationFrame(render); - } - } - - window.requestAnimationFrame(render); - } - - function loadWebrtc() { - const gpuCanvas = document.getElementById('canvas_gpu'); - const video = document.getElementById('video_player'); - - const stream = gpuCanvas.captureStream(); - - const servers = null; - var pc1 = new RTCPeerConnection(servers); - pc1.onicecandidate = e => onIceCandidate(pc1, e); - var pc2 = new RTCPeerConnection(servers); - pc2.onicecandidate = e => onIceCandidate(pc2, e); - - pc1.oniceconnectionstatechange = e => onIceStateChange(pc1, e); - pc2.oniceconnectionstatechange = e => onIceStateChange(pc2, e); - pc2.ontrack = gotRemoteStream; - - stream.getTracks().forEach( - track => { - pc1.addTrack( - track, - stream - ); - } - ); - - pc1.createOffer(onCreateOfferSuccess, onCreateSessionDescriptionError); - - function onCreateSessionDescriptionError(error) { - console.error(`Failed to create session description: ${error.toString()}`); - } - - function onCreateOfferSuccess(desc) { - pc1.setLocalDescription(desc, () => onSetLocalSuccess(pc1), onSetSessionDescriptionError); - pc2.setRemoteDescription(desc, () => onSetRemoteSuccess(pc2), onSetSessionDescriptionError); - pc2.createAnswer(onCreateAnswerSuccess, onCreateSessionDescriptionError); - } - - function onSetLocalSuccess(pc) { - } - - function onSetRemoteSuccess(pc) { - } - - function onSetSessionDescriptionError(error) { - console.error(`Failed to set session description: ${error.toString()}`); - } - - function gotRemoteStream(e) { - if (video.srcObject !== e.streams[0]) { - video.srcObject = e.streams[0]; - } - } - - function onCreateAnswerSuccess(desc) { - pc2.setLocalDescription(desc, () => onSetLocalSuccess(pc2), onSetSessionDescriptionError); - pc1.setRemoteDescription(desc, () => onSetRemoteSuccess(pc1), onSetSessionDescriptionError); - } - - function onIceCandidate(pc, event) { - getOtherPc(pc).addIceCandidate(event.candidate) - .then( - () => onAddIceCandidateSuccess(pc), - err => onAddIceCandidateError(pc, err) - ); - } - - function onAddIceCandidateSuccess(pc) { - } - - function onAddIceCandidateError(pc, error) { - console.error(`${getName(pc)} failed to add ICE Candidate: ${error.toString()}`); - } - - function onIceStateChange(pc, event) { - } - - function getName(pc) { - return (pc === pc1) ? 'pc1' : 'pc2'; - } - - function getOtherPc(pc) { - return (pc === pc1) ? pc2 : pc1; - } - } - </script> -</head> - -<body onload="main()"> - <video id="video_player" playsinline autoplay muted width="200" height="200" class="nomargin"></video> - <canvas id="canvas_gpu" width="200" height="200" class="nomargin"></canvas> -</body> - -</html> \ No newline at end of file
diff --git a/content/test/frame_host_interceptor.cc b/content/test/frame_host_interceptor.cc index ab0f4c1..beebf24 100644 --- a/content/test/frame_host_interceptor.cc +++ b/content/test/frame_host_interceptor.cc
@@ -51,14 +51,17 @@ mojo::PendingRemote<blink::mojom::BlobURLToken> blob_url_token, mojo::PendingAssociatedRemote<mojom::NavigationClient> navigation_client, mojo::PendingRemote<blink::mojom::PolicyContainerHostKeepAliveHandle> - initiator_policy_container_keep_alive_handle) override { + initiator_policy_container_keep_alive_handle, + mojo::PendingReceiver<mojom::NavigationRendererCancellationListener> + renderer_cancellation_listener) override { if (interceptor_->WillDispatchBeginNavigation( rfhi_, &common_params, &begin_params, &blob_url_token, &navigation_client)) { GetForwardingInterface()->BeginNavigation( std::move(common_params), std::move(begin_params), std::move(blob_url_token), std::move(navigation_client), - std::move(initiator_policy_container_keep_alive_handle)); + std::move(initiator_policy_container_keep_alive_handle), + std::move(renderer_cancellation_listener)); } }
diff --git a/content/test/gpu/gpu_tests/pixel_integration_test.py b/content/test/gpu/gpu_tests/pixel_integration_test.py index 372aa580..011db874 100644 --- a/content/test/gpu/gpu_tests/pixel_integration_test.py +++ b/content/test/gpu/gpu_tests/pixel_integration_test.py
@@ -77,7 +77,6 @@ pages += namespace.ExperimentalCanvasFeaturesPages(cls.test_base_name) pages += namespace.LowLatencyPages(cls.test_base_name) pages += namespace.WebGPUPages(cls.test_base_name) - pages += namespace.WebGPUCanvasCapturePages(cls.test_base_name) pages += namespace.PaintWorkletPages(cls.test_base_name) # pages += namespace.NoGpuProcessPages(cls.test_base_name) # The following pages should run only on platforms where SwiftShader is
diff --git a/content/test/gpu/gpu_tests/pixel_test_pages.py b/content/test/gpu/gpu_tests/pixel_test_pages.py index 8e306360..a6419bd 100644 --- a/content/test/gpu/gpu_tests/pixel_test_pages.py +++ b/content/test/gpu/gpu_tests/pixel_test_pages.py
@@ -39,13 +39,6 @@ edge_threshold=0, ignored_border_thickness=1) -# The optimizer script spat out pretty similar values for most MP4 tests, so -# combine into a single set of parameters. -GENERAL_MP4_ALGO = algo.SobelMatchingAlgorithm(max_different_pixels=56300, - pixel_delta_threshold=35, - edge_threshold=80, - ignored_border_thickness=1) - BrowserArgType = typing.List[str] @@ -158,6 +151,13 @@ sw_compositing_args = [cba.DISABLE_GPU_COMPOSITING] browser_args_DXVA = [cba.DISABLE_FEATURES_D3D11_VIDEO_DECODER] + # The optimizer script spat out pretty similar values for most MP4 tests, so + # combine into a single set of parameters. + general_mp4_algo = algo.SobelMatchingAlgorithm(max_different_pixels=56300, + pixel_delta_threshold=35, + edge_threshold=80, + ignored_border_thickness=1) + return [ PixelTestPage('pixel_background_image.html', base_name + '_BackgroundImage', @@ -216,7 +216,7 @@ # Most images are actually very similar, but Pixel 2 # tends to produce images with all colors shifted by a # small amount. - matching_algorithm=GENERAL_MP4_ALGO), + matching_algorithm=general_mp4_algo), # Surprisingly stable, does not appear to require inexact matching. PixelTestPage('pixel_video_mp4.html?width=240&height=135&use_timer=1', base_name + '_Video_MP4_DXVA', @@ -237,19 +237,19 @@ '?width=270&height=240&use_timer=1', base_name + '_Video_MP4_FourColors_Rot_90', test_rect=[0, 0, 270, 240], - matching_algorithm=GENERAL_MP4_ALGO), + matching_algorithm=general_mp4_algo), PixelTestPage( 'pixel_video_mp4_four_colors_rot_180.html' '?width=240&height=135&use_timer=1', base_name + '_Video_MP4_FourColors_Rot_180', test_rect=[0, 0, 240, 135], - matching_algorithm=GENERAL_MP4_ALGO), + matching_algorithm=general_mp4_algo), PixelTestPage( 'pixel_video_mp4_four_colors_rot_270.htm' 'l?width=270&height=240&use_timer=1', base_name + '_Video_MP4_FourColors_Rot_270', test_rect=[0, 0, 270, 240], - matching_algorithm=GENERAL_MP4_ALGO), + matching_algorithm=general_mp4_algo), PixelTestPage( 'pixel_video_mp4_rounded_corner.html' '?width=240&height=135&use_timer=1', @@ -489,37 +489,6 @@ webgpu_pages_helper(base_name, mode=Mode.WEBGPU_SWIFTSHADER) + webgpu_pages_helper(base_name, mode=Mode.VULKAN_SWIFTSHADER)) - @staticmethod - def WebGPUCanvasCapturePages(base_name): - webgpu_args = [ - cba.ENABLE_UNSAFE_WEBGPU, cba.ENABLE_EXPERIMENTAL_WEB_PLATFORM_FEATURES - ] - - browser_args_canvas_one_copy_capture = webgpu_args + [ - '--enable-features=OneCopyCanvasCapture' - ] - other_args_canvas_one_copy_capture = {'one_copy': True} - - browser_args_canvas_disable_one_copy_capture = webgpu_args + [ - '--disable-features=OneCopyCanvasCapture' - ] - other_args_canvas_disable_one_copy_capture = {'one_copy': False} - - return [ - PixelTestPage('pixel_webgpu_canvas_capture_to_video.html', - base_name + '_WebGPUCanvasOneCopyCapture', - test_rect=[0, 0, 400, 200], - matching_algorithm=GENERAL_MP4_ALGO, - browser_args=browser_args_canvas_one_copy_capture, - other_args=other_args_canvas_one_copy_capture), - PixelTestPage('pixel_webgpu_canvas_capture_to_video.html', - base_name + '_WebGPUCanvasDisableOneCopyCapture', - test_rect=[0, 0, 400, 200], - matching_algorithm=GENERAL_MP4_ALGO, - browser_args=browser_args_canvas_disable_one_copy_capture, - other_args=other_args_canvas_disable_one_copy_capture), - ] - # Pages that should be run with GPU rasterization enabled. @staticmethod
diff --git a/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt index a3f1dd2..bf2e40f 100644 --- a/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
@@ -408,14 +408,6 @@ # Vulkan Swiftshader WebGPU interop - missing source image crbug.com/1307787 [ linux skia-renderer-vulkan ] Pixel_VulkanSwiftShader_WebGPUImportVideoFrameUnacceleratedOffscreenCanvas [ Failure ] -# WebGPU canvas capture tests - missing source image -crbug.com/1345560 [ win ] Pixel_WebGPUCanvasOneCopyCapture [ Failure ] -crbug.com/1345560 [ win ] Pixel_WebGPUCanvasDisableOneCopyCapture [ Failure ] -crbug.com/1345560 [ mac ] Pixel_WebGPUCanvasOneCopyCapture [ Failure ] -crbug.com/1345560 [ mac ] Pixel_WebGPUCanvasDisableOneCopyCapture [ Failure ] -crbug.com/1345560 [ linux ] Pixel_WebGPUCanvasOneCopyCapture [ Failure ] -crbug.com/1345560 [ linux ] Pixel_WebGPUCanvasDisableOneCopyCapture [ Failure ] - # Flakes on Android crbug.com/1203317 [ android android-shield-android-tv no-passthrough ] Pixel_OffscreenCanvasWebGLPaintAfterResize [ RetryOnFailure ] crbug.com/1203317 [ android android-pixel-2 no-passthrough ] Pixel_OffscreenCanvasWebGLPaintAfterResize [ RetryOnFailure ]
diff --git a/content/test/gpu/gpu_tests/test_expectations/trace_test_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/trace_test_expectations.txt index 94811f5..b467564 100644 --- a/content/test/gpu/gpu_tests/test_expectations/trace_test_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/trace_test_expectations.txt
@@ -192,15 +192,6 @@ crbug.com/1340081 [ linux release amd-0x7340 ] TraceTest_WebGLGreenTriangle_NoAA_NoAlpha [ RetryOnFailure ] -# WebGPU is only supported on Win10, Mac, and Linux+SkiaRenderer+Vulkan. -crbug.com/852089 [ android ] WebGPUTraceTest_* [ Skip ] -crbug.com/852089 [ linux ] WebGPUTraceTest_* [ Skip ] -crbug.com/852089 [ chromeos ] WebGPUTraceTest_* [ Skip ] -crbug.com/852089 [ fuchsia ] WebGPUTraceTest_* [ Skip ] - -# one copy feature is only supported on mac for now. -crbug.com/1298812 [ win ] WebGPUTraceTest_WebGPUCanvasOneCopyCapture [ Failure ] - ####################################################################### # Automated Entries After This Point - Do Not Manually Add Below Here # #######################################################################
diff --git a/content/test/gpu/gpu_tests/trace_integration_test.py b/content/test/gpu/gpu_tests/trace_integration_test.py index 8df1f31..174a88d 100644 --- a/content/test/gpu/gpu_tests/trace_integration_test.py +++ b/content/test/gpu/gpu_tests/trace_integration_test.py
@@ -110,9 +110,6 @@ _SUPPORTED_WIN_AMD_GPUS_WITH_NV12_ROTATED_OVERLAYS = [0x7340] -_HTML_CANVAS_NOTIFY_LISTENERS_CANVAS_CHANGED_EVENT_NAME =\ - 'HTMLCanvasElement::NotifyListenersCanvasChanged' - class _TraceTestArguments(): """Struct-like object for passing trace test arguments instead of dicts.""" @@ -194,16 +191,6 @@ success_eval_func='CheckMainSwapChainPath', other_args=p.other_args) ]) - for p in namespace.WebGPUCanvasCapturePages('WebGPUTraceTest'): - yield (p.name, posixpath.join(gpu_data_relative_path, p.url), [ - _TraceTestArguments( - browser_args=p.browser_args, - category='blink', - test_harness_script=basic_test_harness_script, - finish_js_condition='domAutomationController._finished', - success_eval_func='CheckWebGPUCanvasCapture', - other_args=p.other_args) - ]) def RunActualGpuTest(self, test_path: str, args: ct.TestArgs) -> None: test_params = args[0] @@ -552,31 +539,6 @@ (_PRESENT_MAIN_SWAP_CHAIN_EVENT_NAME, 'full damage' if expect_full_damage else 'partial damage')) - def _EvaluateSuccess_CheckWebGPUCanvasCapture(self, category: str, - event_iterator: typing.Iterator, - other_args: dict) -> None: - expected_one_copy = other_args.get('one_copy', False) - found_one_copy_event = False - # Verify expectations through captured trace events. - for event in event_iterator: - if event.category != category: - continue - if event.name != _HTML_CANVAS_NOTIFY_LISTENERS_CANVAS_CHANGED_EVENT_NAME: - continue - detected_one_copy = event.args.get('OneCopyCanvasCapture', None) - if detected_one_copy is None: - detected_one_copy = False - else: - found_one_copy_event = True - - if expected_one_copy != detected_one_copy: - self.fail('OneCopyCanvasCapture mismatch, expected %s got %s' % - (expected_one_copy, detected_one_copy)) - - if expected_one_copy and found_one_copy_event is False: - self.fail('%s events with OneCopyCanvasCapture were not found' % - _HTML_CANVAS_NOTIFY_LISTENERS_CANVAS_CHANGED_EVENT_NAME) - @classmethod def ExpectationsFiles(cls) -> typing.List[str]: return [
diff --git a/content/test/navigation_simulator_impl.cc b/content/test/navigation_simulator_impl.cc index 6a3b0ff..768592b 100644 --- a/content/test/navigation_simulator_impl.cc +++ b/content/test/navigation_simulator_impl.cc
@@ -767,11 +767,15 @@ "NavigationSimulatorImpl::Commit or " "NavigationSimulatorImpl::CommitErrorPage."; - if (state_ < READY_TO_COMMIT) + if (state_ < READY_TO_COMMIT) { was_aborted_prior_to_ready_to_commit_ = true; - - request_->RendererAbortedNavigationForTesting(); - state_ = FINISHED; + request_->RendererRequestedNavigationCancellationForTesting(); + state_ = FINISHED; + } else { + // Calling RendererRequestedNavigationCancellationForTesting() after the + // READY_TO_COMMIT stage will get ignored, so call AbortCommit() instead. + AbortCommit(); + } CHECK_EQ(1, num_did_finish_navigation_called_); } @@ -1342,7 +1346,8 @@ navigation_client_remote.InitWithNewEndpointAndPassReceiver(); render_frame_host_->frame_host_receiver_for_testing().impl()->BeginNavigation( std::move(common_params), std::move(begin_params), mojo::NullRemote(), - std::move(navigation_client_remote), mojo::NullRemote()); + std::move(navigation_client_remote), mojo::NullRemote(), + mojo::NullReceiver()); NavigationRequest* request = render_frame_host_->frame_tree_node()->navigation_request();
diff --git a/content/test/test_render_frame.cc b/content/test/test_render_frame.cc index 3faee1ed..70d6875a 100644 --- a/content/test/test_render_frame.cc +++ b/content/test/test_render_frame.cc
@@ -192,7 +192,8 @@ blink::mojom::BeginNavigationParamsPtr begin_params, mojo::PendingRemote<blink::mojom::BlobURLToken> blob_url_token, mojo::PendingAssociatedRemote<mojom::NavigationClient>, - mojo::PendingRemote<blink::mojom::PolicyContainerHostKeepAliveHandle>) + mojo::PendingRemote<blink::mojom::PolicyContainerHostKeepAliveHandle>, + mojo::PendingReceiver<mojom::NavigationRendererCancellationListener>) override {} void SubresourceResponseStarted(const url::SchemeHostPort& final_response_url,
diff --git a/content/test/test_render_frame_host.cc b/content/test/test_render_frame_host.cc index 77df4e0..3c4cf8a 100644 --- a/content/test/test_render_frame_host.cc +++ b/content/test/test_render_frame_host.cc
@@ -402,7 +402,7 @@ navigation_client_remote.InitWithNewEndpointAndPassReceiver()); BeginNavigation(std::move(common_params), std::move(begin_params), mojo::NullRemote(), std::move(navigation_client_remote), - mojo::NullRemote()); + mojo::NullRemote(), mojo::NullReceiver()); } void TestRenderFrameHost::SimulateDidChangeOpener(
diff --git a/device/fido/authenticator_get_info_response.cc b/device/fido/authenticator_get_info_response.cc index 68ae03e1..9e5a50f 100644 --- a/device/fido/authenticator_get_info_response.cc +++ b/device/fido/authenticator_get_info_response.cc
@@ -104,6 +104,14 @@ 0x08, base::strict_cast<int64_t>(*response.max_credential_id_length)); } + if (response.transports) { + std::vector<cbor::Value> transport_values; + for (FidoTransportProtocol transport : *response.transports) { + transport_values.emplace_back(ToString(transport)); + } + device_info_map.emplace(0x09, std::move(transport_values)); + } + if (response.remaining_discoverable_credentials) { device_info_map.emplace(0x14, base::strict_cast<int64_t>(
diff --git a/device/fido/authenticator_get_info_response.h b/device/fido/authenticator_get_info_response.h index a670cac..49df86b 100644 --- a/device/fido/authenticator_get_info_response.h +++ b/device/fido/authenticator_get_info_response.h
@@ -14,6 +14,7 @@ #include "base/containers/flat_set.h" #include "device/fido/authenticator_supported_options.h" #include "device/fido/fido_constants.h" +#include "device/fido/fido_transport_protocol.h" #include "device/fido/fido_types.h" #include "third_party/abseil-cpp/absl/types/optional.h" @@ -57,6 +58,7 @@ absl::optional<uint32_t> remaining_discoverable_credentials; absl::optional<bool> force_pin_change; absl::optional<uint32_t> min_pin_length; + absl::optional<base::flat_set<FidoTransportProtocol>> transports; // max_cred_blob_length is the maximum size credBlob that the authenticator // supports per credential, or nullopt if credBlob is not supported. If
diff --git a/device/fido/authenticator_make_credential_response.h b/device/fido/authenticator_make_credential_response.h index 85b0b32..9aae4db5 100644 --- a/device/fido/authenticator_make_credential_response.h +++ b/device/fido/authenticator_make_credential_response.h
@@ -11,6 +11,7 @@ #include <vector> #include "base/component_export.h" +#include "base/containers/flat_set.h" #include "base/containers/span.h" #include "device/fido/attestation_object.h" #include "device/fido/fido_constants.h" @@ -96,6 +97,10 @@ // |AuthenticatorCommon| based on enterprise policy. bool attestation_should_be_filtered = false; + // transports contains the full set of transports supported by the + // authenticator, if known. + absl::optional<base::flat_set<FidoTransportProtocol>> transports; + private: AttestationObject attestation_object_;
diff --git a/device/fido/cros/authenticator.cc b/device/fido/cros/authenticator.cc index a3375fbe..06ecbb3 100644 --- a/device/fido/cros/authenticator.cc +++ b/device/fido/cros/authenticator.cc
@@ -229,11 +229,14 @@ auto statement = std::make_unique<OpaqueAttestationStatement>( response->attestation_format(), std::move(*statement_map)); + AuthenticatorMakeCredentialResponse fido_response( + FidoTransportProtocol::kInternal, + AttestationObject(std::move(*authenticator_data), std::move(statement))); + fido_response.transports.emplace(); + fido_response.transports->insert(FidoTransportProtocol::kInternal); + std::move(callback).Run(CtapDeviceResponseCode::kSuccess, - AuthenticatorMakeCredentialResponse( - FidoTransportProtocol::kInternal, - AttestationObject(std::move(*authenticator_data), - std::move(statement)))); + std::move(fido_response)); } void ChromeOSAuthenticator::GetAssertion(CtapGetAssertionRequest request,
diff --git a/device/fido/device_response_converter.cc b/device/fido/device_response_converter.cc index f61d2aa8..6bd096a 100644 --- a/device/fido/device_response_converter.cc +++ b/device/fido/device_response_converter.cc
@@ -22,6 +22,7 @@ #include "device/fido/authenticator_supported_options.h" #include "device/fido/features.h" #include "device/fido/fido_constants.h" +#include "device/fido/fido_transport_protocol.h" #include "device/fido/opaque_attestation_statement.h" #include "third_party/abseil-cpp/absl/types/optional.h" @@ -527,6 +528,24 @@ base::saturated_cast<uint32_t>(it->second.GetUnsigned()); } + it = response_map.find(CBOR(0x09)); + if (it != response_map.end()) { + if (!it->second.is_array()) + return absl::nullopt; + + response.transports.emplace(); + for (const auto& transport_str : it->second.GetArray()) { + if (!transport_str.is_string()) + return absl::nullopt; + + absl::optional<FidoTransportProtocol> maybe_transport( + ConvertToFidoTransportProtocol(transport_str.GetString())); + if (maybe_transport.has_value()) { + response.transports->insert(*maybe_transport); + } + } + } + it = response_map.find(CBOR(0x0a)); if (it != response_map.end()) { if (!it->second.is_array()) {
diff --git a/device/fido/mac/make_credential_operation.mm b/device/fido/mac/make_credential_operation.mm index b9cf467..d93bed2 100644 --- a/device/fido/mac/make_credential_operation.mm +++ b/device/fido/mac/make_credential_operation.mm
@@ -151,6 +151,8 @@ CoseAlgorithmIdentifier::kEs256, std::move(*signature), /*x509_certificates=*/std::vector<std::vector<uint8_t>>()))); response.is_resident_key = request_.resident_key_required; + response.transports.emplace(); + response.transports->insert(FidoTransportProtocol::kInternal); std::move(callback_).Run(CtapDeviceResponseCode::kSuccess, std::move(response)); }
diff --git a/device/fido/make_credential_task.cc b/device/fido/make_credential_task.cc index 33fbccc..1f58abb 100644 --- a/device/fido/make_credential_task.cc +++ b/device/fido/make_credential_task.cc
@@ -97,6 +97,10 @@ } } + if (device->device_info() && device->device_info()->transports) { + response->transports = *device->device_info()->transports; + } + return response; }
diff --git a/device/fido/virtual_ctap2_device.cc b/device/fido/virtual_ctap2_device.cc index 714ade8e..591b1ac 100644 --- a/device/fido/virtual_ctap2_device.cc +++ b/device/fido/virtual_ctap2_device.cc
@@ -661,6 +661,10 @@ device_info_->min_pin_length = mutable_state()->min_pin_length; device_info_->force_pin_change = mutable_state()->force_pin_change; } + + if (!config.transports_in_get_info.empty()) { + device_info_->transports = config.transports_in_get_info; + } } VirtualCtap2Device::~VirtualCtap2Device() = default; @@ -1260,8 +1264,9 @@ if (config_.always_return_enterprise_attestation) { enterprise_attestation_requested = true; } - attestation_cert = - GenerateAttestationCertificate(enterprise_attestation_requested); + attestation_cert = GenerateAttestationCertificate( + enterprise_attestation_requested, + config_.include_transports_in_attestation_certificate); if (!attestation_cert) { DLOG(ERROR) << "Failed to generate attestation certificate."; return CtapDeviceResponseCode::kCtap2ErrOther;
diff --git a/device/fido/virtual_ctap2_device.h b/device/fido/virtual_ctap2_device.h index 49517912..c0a1d0c 100644 --- a/device/fido/virtual_ctap2_device.h +++ b/device/fido/virtual_ctap2_device.h
@@ -83,6 +83,13 @@ // as a fixed size area for the large blob. size_t available_large_blob_storage = 1024; bool cred_blob_support = false; + // include_transports_in_attestation_certificate controls whether a + // transports extension will be included in the attestation certificate + // returned from a makeCredential operation. + bool include_transports_in_attestation_certificate = true; + // transports_in_get_info, if not empty, contains the transports that will + // be reported via getInfo. + std::vector<FidoTransportProtocol> transports_in_get_info; IncludeCredential include_credential_in_assertion_response = IncludeCredential::ONLY_IF_NEEDED;
diff --git a/device/fido/virtual_fido_device.cc b/device/fido/virtual_fido_device.cc index ab7a8b9..22fcc9b 100644 --- a/device/fido/virtual_fido_device.cc +++ b/device/fido/virtual_fido_device.cc
@@ -515,7 +515,8 @@ absl::optional<std::vector<uint8_t>> VirtualFidoDevice::GenerateAttestationCertificate( - bool individual_attestation_requested) const { + bool individual_attestation_requested, + bool include_transports) const { std::unique_ptr<crypto::ECPrivateKey> attestation_private_key = crypto::ECPrivateKey::CreateFromPrivateKeyInfo(GetAttestationKey()); constexpr uint32_t kAttestationCertSerialNumber = 1; @@ -560,10 +561,13 @@ 0x00, // zero bytes long }; - const std::vector<net::x509_util::Extension> extensions = { - {kTransportTypesOID, /*critical=*/false, kTransportTypesContents}, + std::vector<net::x509_util::Extension> extensions = { {kBasicContraintsOID, /*critical=*/true, kBasicContraintsContents}, }; + if (include_transports) { + extensions.push_back( + {kTransportTypesOID, /*critical=*/false, kTransportTypesContents}); + } // https://w3c.github.io/webauthn/#sctn-packed-attestation-cert-requirements // Make the certificate expire about 20 years from now.
diff --git a/device/fido/virtual_fido_device.h b/device/fido/virtual_fido_device.h index 90524983..71333bb 100644 --- a/device/fido/virtual_fido_device.h +++ b/device/fido/virtual_fido_device.h
@@ -348,7 +348,8 @@ // attestation statement and FIDO-U2F attestation statement. // https://w3c.github.io/webauthn/#defined-attestation-formats absl::optional<std::vector<uint8_t>> GenerateAttestationCertificate( - bool individual_attestation_requested) const; + bool individual_attestation_requested, + bool include_transports) const; void StoreNewKey(base::span<const uint8_t> key_handle, VirtualFidoDevice::RegistrationData registration_data);
diff --git a/device/fido/virtual_u2f_device.cc b/device/fido/virtual_u2f_device.cc index 6224a7d0..1e306d6 100644 --- a/device/fido/virtual_u2f_device.cc +++ b/device/fido/virtual_u2f_device.cc
@@ -176,8 +176,8 @@ // The spec says that the other bits of P1 should be zero. However, Chrome // sends Test User Presence (0x03) so we ignore those bits. bool individual_attestation_requested = p1 & kP1IndividualAttestation; - const auto attestation_cert = - GenerateAttestationCertificate(individual_attestation_requested); + const auto attestation_cert = GenerateAttestationCertificate( + individual_attestation_requested, /*include_transports=*/true); if (!attestation_cert) return ErrorStatus(apdu::ApduResponse::Status::SW_INS_NOT_SUPPORTED);
diff --git a/docs/linux/chromium_packages.md b/docs/linux/chromium_packages.md index 4f48363..771ed60 100644 --- a/docs/linux/chromium_packages.md +++ b/docs/linux/chromium_packages.md
@@ -34,7 +34,7 @@ | **System** | **Contact** | **URL for packages** | **URL for patches** | |:-----------|:------------|:---------------------|:--------------------| -| FreeBSD | http://lists.freebsd.org/mailman/listinfo/freebsd-chromium | http://wiki.freebsd.org/Chromium | https://svnweb.freebsd.org/ports/head/www/chromium/files/ | +| FreeBSD | freebsd-chromium@freebsd.org | https://wiki.freebsd.org/Chromium | https://cgit.freebsd.org/ports/tree/www/chromium/files | | OpenBSD | Robert Nagy `robert@openbsd.org` | http://openports.se/www/chromium | http://www.openbsd.org/cgi-bin/cvsweb/ports/www/chromium/patches/ | ## Updating the list
diff --git a/extensions/shell/app/shell_main_delegate.cc b/extensions/shell/app/shell_main_delegate.cc index e13a55e..d691da9 100644 --- a/extensions/shell/app/shell_main_delegate.cc +++ b/extensions/shell/app/shell_main_delegate.cc
@@ -123,7 +123,7 @@ ShellMainDelegate::~ShellMainDelegate() { } -bool ShellMainDelegate::BasicStartupComplete(int* exit_code) { +absl::optional<int> ShellMainDelegate::BasicStartupComplete() { InitLogging(); #if BUILDFLAG(IS_CHROMEOS_ASH) @@ -136,7 +136,7 @@ nacl::RegisterPathProvider(); #endif extensions::RegisterPathProvider(); - return false; + return absl::nullopt; } void ShellMainDelegate::PreSandboxStartup() {
diff --git a/extensions/shell/app/shell_main_delegate.h b/extensions/shell/app/shell_main_delegate.h index 8117ae4..dd2dc23 100644 --- a/extensions/shell/app/shell_main_delegate.h +++ b/extensions/shell/app/shell_main_delegate.h
@@ -12,6 +12,7 @@ #include "build/build_config.h" #include "build/chromeos_buildflags.h" #include "content/public/app/content_main_delegate.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace content { class ContentBrowserClient; @@ -31,7 +32,7 @@ ~ShellMainDelegate() override; // ContentMainDelegate implementation: - bool BasicStartupComplete(int* exit_code) override; + absl::optional<int> BasicStartupComplete() override; void PreSandboxStartup() override; content::ContentClient* CreateContentClient() override; content::ContentBrowserClient* CreateContentBrowserClient() override; @@ -42,7 +43,7 @@ delegates) override; #endif #if BUILDFLAG(IS_MAC) - void PreBrowserMain() override; + absl::optional<int> PreBrowserMain() override; #endif private:
diff --git a/extensions/shell/app/shell_main_delegate_mac.mm b/extensions/shell/app/shell_main_delegate_mac.mm index ffc4cdb4..211382cb 100644 --- a/extensions/shell/app/shell_main_delegate_mac.mm +++ b/extensions/shell/app/shell_main_delegate_mac.mm
@@ -8,7 +8,7 @@ namespace extensions { -void ShellMainDelegate::PreBrowserMain() { +absl::optional<int> ShellMainDelegate::PreBrowserMain() { // Force the NSApplication subclass to be used. [ShellCrApplication sharedApplication]; @@ -16,6 +16,8 @@ // will not be a ShellCrApplication, but will instead be an NSApplication. // This is undesirable and we must enforce that this doesn't happen. CHECK([NSApp isKindOfClass:[ShellCrApplication class]]); + + return absl::nullopt; } } // namespace extensions
diff --git a/extensions/shell/browser/shell_browser_main_parts.cc b/extensions/shell/browser/shell_browser_main_parts.cc index de2c738..baa0d28 100644 --- a/extensions/shell/browser/shell_browser_main_parts.cc +++ b/extensions/shell/browser/shell_browser_main_parts.cc
@@ -13,7 +13,6 @@ #include "base/memory/ref_counted.h" #include "build/build_config.h" #include "build/chromeos_buildflags.h" -#include "chromeos/ash/components/dbus/hermes/hermes_clients.h" #include "components/keyed_service/content/browser_context_dependency_manager.h" #include "components/nacl/common/buildflags.h" #include "components/prefs/pref_service.h" @@ -55,31 +54,28 @@ #include "device/bluetooth/dbus/dbus_bluez_manager_wrapper_linux.h" #endif -#if BUILDFLAG(IS_CHROMEOS_ASH) -#include "ash/components/audio/audio_devices_pref_handler_impl.h" -#include "ash/components/audio/cras_audio_handler.h" -#include "ash/components/disks/disk_mount_manager.h" -#include "chromeos/ash/components/network/network_handler.h" -#include "extensions/shell/browser/shell_audio_controller_chromeos.h" -#include "extensions/shell/browser/shell_network_controller_chromeos.h" -#endif - #if BUILDFLAG(IS_CHROMEOS) #include "device/bluetooth/bluetooth_adapter_factory.h" #include "device/bluetooth/dbus/bluez_dbus_manager.h" #endif #if BUILDFLAG(IS_CHROMEOS_ASH) +#include "ash/components/audio/audio_devices_pref_handler_impl.h" +#include "ash/components/audio/cras_audio_handler.h" +#include "ash/components/disks/disk_mount_manager.h" #include "chromeos/ash/components/dbus/audio/cras_audio_client.h" +#include "chromeos/ash/components/dbus/hermes/hermes_clients.h" +#include "chromeos/ash/components/network/network_handler.h" #include "chromeos/dbus/cros_disks/cros_disks_client.h" #include "chromeos/dbus/dbus_thread_manager.h" #include "chromeos/dbus/power/power_manager_client.h" -#elif BUILDFLAG(IS_CHROMEOS) -#include "device/bluetooth/dbus/bluez_dbus_thread_manager.h" +#include "extensions/shell/browser/shell_audio_controller_chromeos.h" +#include "extensions/shell/browser/shell_network_controller_chromeos.h" #endif #if BUILDFLAG(IS_CHROMEOS_LACROS) #include "chromeos/lacros/dbus/lacros_dbus_thread_manager.h" +#include "device/bluetooth/dbus/bluez_dbus_thread_manager.h" #endif #if BUILDFLAG(ENABLE_NACL)
diff --git a/extensions/shell/test/test_shell_main_delegate.cc b/extensions/shell/test/test_shell_main_delegate.cc index d802142..53b92cd 100644 --- a/extensions/shell/test/test_shell_main_delegate.cc +++ b/extensions/shell/test/test_shell_main_delegate.cc
@@ -50,12 +50,15 @@ TestShellMainDelegate::~TestShellMainDelegate() {} #if BUILDFLAG(IS_CHROMEOS_LACROS) -void TestShellMainDelegate::PostEarlyInitialization(InvokedIn invoked_in) { +absl::optional<int> TestShellMainDelegate::PostEarlyInitialization( + InvokedIn invoked_in) { if (absl::holds_alternative<InvokedInBrowserProcess>(invoked_in)) { // Browser tests on Lacros requires a non-null LacrosService. lacros_service_ = std::make_unique<chromeos::LacrosService>(); } extensions::ShellMainDelegate::PostEarlyInitialization(invoked_in); + + return absl::nullopt; } #endif // BUILDFLAG(IS_CHROMEOS_LACROS)
diff --git a/extensions/shell/test/test_shell_main_delegate.h b/extensions/shell/test/test_shell_main_delegate.h index e569f087..58d7af9 100644 --- a/extensions/shell/test/test_shell_main_delegate.h +++ b/extensions/shell/test/test_shell_main_delegate.h
@@ -10,6 +10,7 @@ #include "build/build_config.h" #include "build/chromeos_buildflags.h" #include "extensions/shell/app/shell_main_delegate.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #if BUILDFLAG(IS_CHROMEOS_LACROS) // TODO(erikchen): Move #include to .cc file and forward declare @@ -34,7 +35,7 @@ // ContentMainDelegate implementation: #if BUILDFLAG(IS_CHROMEOS_LACROS) - void PostEarlyInitialization(InvokedIn invoked_in) override; + absl::optional<int> PostEarlyInitialization(InvokedIn invoked_in) override; #endif protected:
diff --git a/fuchsia_web/webengine/renderer/web_engine_content_renderer_client.cc b/fuchsia_web/webengine/renderer/web_engine_content_renderer_client.cc index 29e4805..763fdcb 100644 --- a/fuchsia_web/webengine/renderer/web_engine_content_renderer_client.cc +++ b/fuchsia_web/webengine/renderer/web_engine_content_renderer_client.cc
@@ -26,6 +26,7 @@ #include "media/base/video_codecs.h" #include "services/network/public/cpp/features.h" #include "services/service_manager/public/cpp/binder_registry.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/blink/public/common/associated_interfaces/associated_interface_registry.h" #include "third_party/blink/public/common/browser_interface_broker_proxy.h" #include "third_party/blink/public/web/web_view.h" @@ -68,21 +69,23 @@ return supported_codecs_; } - media::EmeConfigRule GetRobustnessConfigRule( + absl::optional<media::EmeConfigRule> GetRobustnessConfigRule( const std::string& /*key_system*/, media::EmeMediaType /*media_type*/, const std::string& requested_robustness, const bool* /*hw_secure_requirement*/) const override { // Only empty robustness string is currently supported. if (requested_robustness.empty()) { - return media::EmeConfigRule::HW_SECURE_CODECS_REQUIRED; + return media::EmeConfigRule{.hw_secure_codecs = + media::EmeConfigRuleState::kRequired}; } - return media::EmeConfigRule::NOT_SUPPORTED; + return absl::nullopt; } - media::EmeConfigRule GetPersistentLicenseSessionSupport() const override { - return media::EmeConfigRule::NOT_SUPPORTED; + absl::optional<media::EmeConfigRule> GetPersistentLicenseSessionSupport() + const override { + return absl::nullopt; } media::EmeFeatureSupport GetPersistentStateSupport() const override { @@ -93,13 +96,13 @@ return media::EmeFeatureSupport::ALWAYS_ENABLED; } - media::EmeConfigRule GetEncryptionSchemeConfigRule( + absl::optional<media::EmeConfigRule> GetEncryptionSchemeConfigRule( media::EncryptionScheme encryption_mode) const override { if (encryption_mode == ::media::EncryptionScheme::kCenc) { - return media::EmeConfigRule::SUPPORTED; + return media::EmeConfigRule(); } - return media::EmeConfigRule::NOT_SUPPORTED; + return absl::nullopt; } private:
diff --git a/fuchsia_web/webengine/web_engine_main_delegate.cc b/fuchsia_web/webengine/web_engine_main_delegate.cc index 2948552..58a37cbf 100644 --- a/fuchsia_web/webengine/web_engine_main_delegate.cc +++ b/fuchsia_web/webengine/web_engine_main_delegate.cc
@@ -72,12 +72,11 @@ WebEngineMainDelegate::~WebEngineMainDelegate() = default; -bool WebEngineMainDelegate::BasicStartupComplete(int* exit_code) { +absl::optional<int> WebEngineMainDelegate::BasicStartupComplete() { base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); if (!InitLoggingFromCommandLine(*command_line)) { - *exit_code = 1; - return true; + return 1; } if (command_line->HasSwitch(switches::kGoogleApiKey)) { @@ -90,7 +89,7 @@ switches::kCorsExemptHeaders), ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY)); - return false; + return absl::nullopt; } void WebEngineMainDelegate::PreSandboxStartup() {
diff --git a/fuchsia_web/webengine/web_engine_main_delegate.h b/fuchsia_web/webengine/web_engine_main_delegate.h index 165d07e0..6a2efff 100644 --- a/fuchsia_web/webengine/web_engine_main_delegate.h +++ b/fuchsia_web/webengine/web_engine_main_delegate.h
@@ -12,6 +12,7 @@ #include "content/public/app/content_main_delegate.h" #include "fuchsia_web/webengine/web_engine_export.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace content { class ContentClient; @@ -35,7 +36,7 @@ } // ContentMainDelegate implementation. - bool BasicStartupComplete(int* exit_code) override; + absl::optional<int> BasicStartupComplete() override; void PreSandboxStartup() override; absl::variant<int, content::MainFunctionParams> RunProcess( const std::string& process_type,
diff --git a/headless/lib/headless_content_main_delegate.cc b/headless/lib/headless_content_main_delegate.cc index ab8f57a8..7e9cd3f 100644 --- a/headless/lib/headless_content_main_delegate.cc +++ b/headless/lib/headless_content_main_delegate.cc
@@ -177,7 +177,7 @@ g_current_headless_content_main_delegate = nullptr; } -bool HeadlessContentMainDelegate::BasicStartupComplete(int* exit_code) { +absl::optional<int> HeadlessContentMainDelegate::BasicStartupComplete() { base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); // Make sure all processes know that we're in headless mode. @@ -222,7 +222,7 @@ #endif content::Profiling::ProcessStarted(); - return false; + return absl::nullopt; } void HeadlessContentMainDelegate::InitLogging( @@ -468,10 +468,10 @@ return utility_client_.get(); } -void HeadlessContentMainDelegate::PostEarlyInitialization( +absl::optional<int> HeadlessContentMainDelegate::PostEarlyInitialization( InvokedIn invoked_in) { if (absl::holds_alternative<InvokedInChildProcess>(invoked_in)) - return; + return absl::nullopt; if (base::FeatureList::IsEnabled(features::kVirtualTime)) { // Only pass viz flags into the virtual time mode. @@ -497,6 +497,8 @@ for (const auto* flag : switches) base::CommandLine::ForCurrentProcess()->AppendSwitch(flag); } + + return absl::nullopt; } } // namespace headless
diff --git a/headless/lib/headless_content_main_delegate.h b/headless/lib/headless_content_main_delegate.h index aac7b78..7bc062d 100644 --- a/headless/lib/headless_content_main_delegate.h +++ b/headless/lib/headless_content_main_delegate.h
@@ -17,6 +17,7 @@ #include "headless/lib/headless_content_client.h" #include "headless/public/headless_browser.h" #include "headless/public/headless_export.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace base { class CommandLine; @@ -41,20 +42,20 @@ ~HeadlessContentMainDelegate() override; // content::ContentMainDelegate implementation: - bool BasicStartupComplete(int* exit_code) override; + absl::optional<int> BasicStartupComplete() override; void PreSandboxStartup() override; absl::variant<int, content::MainFunctionParams> RunProcess( const std::string& process_type, content::MainFunctionParams main_function_params) override; #if BUILDFLAG(IS_MAC) - void PreBrowserMain() override; + absl::optional<int> PreBrowserMain() override; #endif content::ContentClient* CreateContentClient() override; content::ContentBrowserClient* CreateContentBrowserClient() override; content::ContentUtilityClient* CreateContentUtilityClient() override; content::ContentRendererClient* CreateContentRendererClient() override; - void PostEarlyInitialization(InvokedIn invoked_in) override; + absl::optional<int> PostEarlyInitialization(InvokedIn invoked_in) override; HeadlessBrowserImpl* browser() const { return browser_.get(); }
diff --git a/headless/lib/headless_content_main_delegate_mac.mm b/headless/lib/headless_content_main_delegate_mac.mm index dedad4b..65839b1 100644 --- a/headless/lib/headless_content_main_delegate_mac.mm +++ b/headless/lib/headless_content_main_delegate_mac.mm
@@ -8,7 +8,7 @@ namespace headless { -void HeadlessContentMainDelegate::PreBrowserMain() { +absl::optional<int> HeadlessContentMainDelegate::PreBrowserMain() { // Force the NSApplication subclass to be used. [HeadlessShellCrApplication sharedApplication]; @@ -17,6 +17,8 @@ // NSApplication. This is undesirable and we must enforce that this doesn't // happen. CHECK([NSApp isKindOfClass:[HeadlessShellCrApplication class]]); + + return absl::nullopt; } } // namespace headless
diff --git a/infra/config/generated/luci/cr-buildbucket.cfg b/infra/config/generated/luci/cr-buildbucket.cfg index 6f32e46..3d288f8 100644 --- a/infra/config/generated/luci/cr-buildbucket.cfg +++ b/infra/config/generated/luci/cr-buildbucket.cfg
@@ -3041,12 +3041,12 @@ name: "Comparison Android (reclient)" swarming_host: "chromium-swarm.appspot.com" dimensions: "builderless:1" - dimensions: "cores:8" + dimensions: "cores:16" dimensions: "cpu:x86-64" dimensions: "free_space:standard" dimensions: "os:Ubuntu-18.04" dimensions: "pool:luci.chromium.ci" - dimensions: "ssd:0" + dimensions: "ssd:1" exe { cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build" cipd_version: "refs/heads/main" @@ -3116,6 +3116,7 @@ use_invocation_timestamp: true } } + description_html: "This builder measures Android build performance with goma vs reclient.<br/>The bot specs should be in sync with <a href=\"https://ci.chromium.org/p/chromium/builders/ci/Deterministic%20Android%20(dbg)\">Deterministic Android (dbg)</a>." } builders { name: "Comparison Android (reclient)(CQ)" @@ -56387,11 +56388,10 @@ builders { name: "chromeos-amd64-generic-rel" swarming_host: "chromium-swarm.appspot.com" - dimensions: "builder:chromeos-amd64-generic-rel" dimensions: "cores:2" dimensions: "cpu:x86-64" dimensions: "os:Ubuntu-18.04" - dimensions: "pool:luci.chromium.try" + dimensions: "pool:luci.chromium.try.orchestrator" exe { cipd_package: "infra/chromium/bootstrapper/${platform}" cipd_version: "latest" @@ -56428,6 +56428,10 @@ seconds: 120 } caches { + name: "unused_builder_cache" + path: "builder" + } + caches { name: "win_toolchain" path: "win_toolchain" } @@ -67201,11 +67205,10 @@ builders { name: "linux-chromeos-rel" swarming_host: "chromium-swarm.appspot.com" - dimensions: "builder:linux-chromeos-rel" dimensions: "cores:2" dimensions: "cpu:x86-64" dimensions: "os:Ubuntu-18.04" - dimensions: "pool:luci.chromium.try" + dimensions: "pool:luci.chromium.try.orchestrator" exe { cipd_package: "infra/chromium/bootstrapper/${platform}" cipd_version: "latest" @@ -67242,6 +67245,10 @@ seconds: 120 } caches { + name: "unused_builder_cache" + path: "builder" + } + caches { name: "win_toolchain" path: "win_toolchain" }
diff --git a/infra/config/generated/luci/project.cfg b/infra/config/generated/luci/project.cfg index bddd90a..4c731471 100644 --- a/infra/config/generated/luci/project.cfg +++ b/infra/config/generated/luci/project.cfg
@@ -7,7 +7,7 @@ name: "chromium" access: "group:all" lucicfg { - version: "1.31.4" + version: "1.31.5" package_dir: "../.." config_dir: "generated/luci" entry_point: "main.star"
diff --git a/infra/config/subprojects/chromium/ci/chromium.fyi.star b/infra/config/subprojects/chromium/ci/chromium.fyi.star index 5ff89cf..2862834 100644 --- a/infra/config/subprojects/chromium/ci/chromium.fyi.star +++ b/infra/config/subprojects/chromium/ci/chromium.fyi.star
@@ -840,6 +840,10 @@ category = "android", short_name = "cmp", ), + description_html = """\ +This builder measures Android build performance with goma vs reclient.<br/>\ +The bot specs should be in sync with <a href="https://ci.chromium.org/p/chromium/builders/ci/Deterministic%20Android%20(dbg)">Deterministic Android (dbg)</a>.\ +""", goma_jobs = 250, executable = "recipe:reclient_goma_comparison", execution_timeout = 15 * time.hour, @@ -847,6 +851,9 @@ reclient_instance = rbe_instance.DEFAULT, reclient_jobs = 250, os = os.LINUX_DEFAULT, + # Target luci-chromium-ci-bionic-us-central1-b-ssd-16-*. + ssd = True, + cores = 16, ) ci.builder(
diff --git a/infra/config/subprojects/chromium/try/tryserver.chromium.chromiumos.star b/infra/config/subprojects/chromium/try/tryserver.chromium.chromiumos.star index 65e82480..5b46913 100644 --- a/infra/config/subprojects/chromium/try/tryserver.chromium.chromiumos.star +++ b/infra/config/subprojects/chromium/try/tryserver.chromium.chromiumos.star
@@ -60,6 +60,7 @@ experiments = { "remove_src_checkout_experiment": 100, }, + use_orchestrator_pool = True, ) try_.compilator_builder( @@ -206,6 +207,7 @@ experiments = { "remove_src_checkout_experiment": 100, }, + use_orchestrator_pool = True, ) try_.compilator_builder(
diff --git a/ios/chrome/browser/discover_feed/BUILD.gn b/ios/chrome/browser/discover_feed/BUILD.gn index 66f84ce..f3185836 100644 --- a/ios/chrome/browser/discover_feed/BUILD.gn +++ b/ios/chrome/browser/discover_feed/BUILD.gn
@@ -19,6 +19,7 @@ ] deps = [ "//components/keyed_service/core", + "//ios/chrome/browser:utils", "//ios/public/provider/chrome/browser/signin:signin_sso_api", ] public_deps = [
diff --git a/ios/chrome/browser/discover_feed/discover_feed_service.h b/ios/chrome/browser/discover_feed/discover_feed_service.h index dac1d3e..2cb746f 100644 --- a/ios/chrome/browser/discover_feed/discover_feed_service.h +++ b/ios/chrome/browser/discover_feed/discover_feed_service.h
@@ -12,6 +12,7 @@ #include "ios/chrome/browser/discover_feed/discover_feed_view_controller_configuration.h" #include "ios/chrome/browser/discover_feed/feed_constants.h" #include "ios/chrome/browser/discover_feed/feed_model_configuration.h" +#import "ios/chrome/browser/procedural_block_types.h" @class FeedMetricsRecorder; @@ -69,6 +70,22 @@ // update all ViewControllers returned by NewFeedViewController. virtual void RefreshFeed() = 0; + // Performs a background refresh for the feed. `completion` is called + // after success, failure, or timeout. The BOOL argument indicates whether the + // refresh was successful or a failure. + // TODO(crbug.com/1343695): Make this a pure virtual function. + virtual void PerformBackgroundRefreshes(ProceduralBlockWithBool completion); + + // Stops the background refresh task and cleans up any temporary objects. This + // is called by the OS when the task is taking too long. + // TODO(crbug.com/1343695): Make this a pure virtual function. + virtual void HandleBackgroundRefreshTaskExpiration(); + + // The earliest datetime at which the next background refresh should be + // scheduled. + // TODO(crbug.com/1343695): Make this a pure virtual function. + virtual NSDate* GetEarliestBackgroundRefreshBeginDate(); + // Returns whether the Following feed model has unseen content. virtual BOOL GetFollowingFeedHasUnseenContent() = 0;
diff --git a/ios/chrome/browser/discover_feed/discover_feed_service.mm b/ios/chrome/browser/discover_feed/discover_feed_service.mm index 29da5a2..73c5b95 100644 --- a/ios/chrome/browser/discover_feed/discover_feed_service.mm +++ b/ios/chrome/browser/discover_feed/discover_feed_service.mm
@@ -30,3 +30,15 @@ observer.OnDiscoverFeedModelRecreated(); } } + +// TODO(crbug.com/1343695): Make this a pure virtual function. +void DiscoverFeedService::PerformBackgroundRefreshes( + ProceduralBlockWithBool completion) {} + +// TODO(crbug.com/1343695): Make this a pure virtual function. +void DiscoverFeedService::HandleBackgroundRefreshTaskExpiration() {} + +// TODO(crbug.com/1343695): Make this a pure virtual function. +NSDate* DiscoverFeedService::GetEarliestBackgroundRefreshBeginDate() { + return nil; +}
diff --git a/ios/chrome/browser/flags/about_flags.mm b/ios/chrome/browser/flags/about_flags.mm index 104cd8e..61d7d73 100644 --- a/ios/chrome/browser/flags/about_flags.mm +++ b/ios/chrome/browser/flags/about_flags.mm
@@ -336,6 +336,50 @@ std::size(kStartSurfaceOneHourHideShortcutsReturnToRecentTab), nullptr}, }; +// Feed Background Refresh Feature Params + +const FeatureEntry::FeatureParam kOneHourIntervalOnce[] = { + {kEnableServerDrivenBackgroundRefreshSchedule, "false"}, + {kEnableRecurringBackgroundRefreshSchedule, "false"}, + {kBackgroundRefreshIntervalInSeconds, /* 60*60= */ "3600"}}; +const FeatureEntry::FeatureParam kFourHourIntervalOnce[] = { + {kEnableServerDrivenBackgroundRefreshSchedule, "false"}, + {kEnableRecurringBackgroundRefreshSchedule, "false"}, + {kBackgroundRefreshIntervalInSeconds, /* 4*60*60= */ "14400"}}; +const FeatureEntry::FeatureParam kOneHourIntervalRecurring[] = { + {kEnableServerDrivenBackgroundRefreshSchedule, "false"}, + {kEnableRecurringBackgroundRefreshSchedule, "true"}, + {kBackgroundRefreshIntervalInSeconds, /* 60*60= */ "3600"}}; +const FeatureEntry::FeatureParam kFourHourIntervalRecurring[] = { + {kEnableServerDrivenBackgroundRefreshSchedule, "false"}, + {kEnableRecurringBackgroundRefreshSchedule, "true"}, + {kBackgroundRefreshIntervalInSeconds, /* 4*60*60= */ "14400"}}; +const FeatureEntry::FeatureParam kServerDrivenOnce[] = { + {kEnableServerDrivenBackgroundRefreshSchedule, "true"}, + {kEnableRecurringBackgroundRefreshSchedule, "false"}, + {kBackgroundRefreshIntervalInSeconds, /* 60*60= */ "3600"}}; +const FeatureEntry::FeatureParam kServerDrivenRecurring[] = { + {kEnableServerDrivenBackgroundRefreshSchedule, "true"}, + {kEnableRecurringBackgroundRefreshSchedule, "true"}, + {kBackgroundRefreshIntervalInSeconds, /* 60*60= */ "3600"}}; + +// Feed Background Refresh Feature Variations + +const FeatureEntry::FeatureVariation kFeedBackgroundRefreshVariations[] = { + {"1hr Interval Once", kOneHourIntervalOnce, std::size(kOneHourIntervalOnce), + nullptr}, + {"4hr Interval Once", kFourHourIntervalOnce, + std::size(kFourHourIntervalOnce), nullptr}, + {"1hr Interval Recurring", kOneHourIntervalRecurring, + std::size(kOneHourIntervalRecurring), nullptr}, + {"4hr Interval Recurring", kFourHourIntervalRecurring, + std::size(kFourHourIntervalRecurring), nullptr}, + {"Server Driven Once", kServerDrivenOnce, std::size(kServerDrivenOnce), + nullptr}, + {"Server Driven Recurring", kServerDrivenRecurring, + std::size(kServerDrivenRecurring), nullptr}, +}; + const FeatureEntry::FeatureParam kFREDefaultBrowserPromoDefaultDelay[] = { {kFREDefaultBrowserPromoParam, kFREDefaultBrowserPromoDefaultDelayParam}}; const FeatureEntry::FeatureParam kFREDefaultBrowserPromoFirstRunOnly[] = { @@ -1040,7 +1084,9 @@ {"feed-background-refresh-ios", flag_descriptions::kFeedBackgroundRefreshName, flag_descriptions::kFeedBackgroundRefreshDescription, flags_ui::kOsIos, - FEATURE_VALUE_TYPE(kEnableFeedBackgroundRefresh)}, + FEATURE_WITH_PARAMS_VALUE_TYPE(kEnableFeedBackgroundRefresh, + kFeedBackgroundRefreshVariations, + "FeedBackgroundRefresh")}, }; bool SkipConditionalFeatureEntry(const flags_ui::FeatureEntry& entry) {
diff --git a/ios/chrome/browser/ntp/BUILD.gn b/ios/chrome/browser/ntp/BUILD.gn index 1cac006..8ddd533 100644 --- a/ios/chrome/browser/ntp/BUILD.gn +++ b/ios/chrome/browser/ntp/BUILD.gn
@@ -30,9 +30,10 @@ source_set("features") { sources = [ - "features.cc", "features.h", + "features.mm", ] + configs += [ "//build/config/compiler:enable_arc" ] deps = [ "//base" ] }
diff --git a/ios/chrome/browser/ntp/features.cc b/ios/chrome/browser/ntp/features.cc deleted file mode 100644 index 8505005..0000000 --- a/ios/chrome/browser/ntp/features.cc +++ /dev/null
@@ -1,22 +0,0 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ios/chrome/browser/ntp/features.h" - -const base::Feature kBlockNewTabPagePendingLoad{ - "BlockNewTabPagePendingLoad", base::FEATURE_DISABLED_BY_DEFAULT}; - -const base::Feature kEnableWebChannels{"EnableWebChannels", - base::FEATURE_DISABLED_BY_DEFAULT}; - -const base::Feature kEnableFeedBackgroundRefresh{ - "EnableFeedBackgroundRefresh", base::FEATURE_DISABLED_BY_DEFAULT}; - -bool IsWebChannelsEnabled() { - return base::FeatureList::IsEnabled(kEnableWebChannels); -} - -bool IsFeedBackgroundRefreshEnabled() { - return base::FeatureList::IsEnabled(kEnableFeedBackgroundRefresh); -}
diff --git a/ios/chrome/browser/ntp/features.h b/ios/chrome/browser/ntp/features.h index 742b9d6..079b8350 100644 --- a/ios/chrome/browser/ntp/features.h +++ b/ios/chrome/browser/ntp/features.h
@@ -18,10 +18,32 @@ // Use IsWebChannelsEnabled() instead of this constant directly. extern const base::Feature kEnableWebChannels; +// Feature param under `kEnableFeedBackgroundRefresh` to enable server driven +// background refresh schedule. +extern const char kEnableServerDrivenBackgroundRefreshSchedule[]; + +// Feature param under `kEnableFeedBackgroundRefresh` to enable recurring +// background refresh schedule. +extern const char kEnableRecurringBackgroundRefreshSchedule[]; + +// Feature param under `kEnableFeedBackgroundRefresh` for the background refresh +// interval in seconds. +extern const char kBackgroundRefreshIntervalInSeconds[]; + // Whether the Following Feed is enabled on NTP. bool IsWebChannelsEnabled(); // Whether feed background refresh is enabled. bool IsFeedBackgroundRefreshEnabled(); +// Whether the background refresh schedule should be driven by server values. +bool IsServerDrivenBackgroundRefreshScheduleEnabled(); + +// Whether a new refresh should be scheduled after completion of a previous +// background refresh. +bool IsRecurringBackgroundRefreshScheduleEnabled(); + +// The earliest interval to refresh if server value is not used. +double GetBackgroundRefreshIntervalInSeconds(); + #endif // IOS_CHROME_BROWSER_NTP_FEATURES_H_
diff --git a/ios/chrome/browser/ntp/features.mm b/ios/chrome/browser/ntp/features.mm new file mode 100644 index 0000000..a9c7249 --- /dev/null +++ b/ios/chrome/browser/ntp/features.mm
@@ -0,0 +1,55 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/chrome/browser/ntp/features.h" + +#import <Foundation/Foundation.h> + +#import "base/metrics/field_trial_params.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +const base::Feature kBlockNewTabPagePendingLoad{ + "BlockNewTabPagePendingLoad", base::FEATURE_DISABLED_BY_DEFAULT}; + +const base::Feature kEnableWebChannels{"EnableWebChannels", + base::FEATURE_DISABLED_BY_DEFAULT}; + +const base::Feature kEnableFeedBackgroundRefresh{ + "EnableFeedBackgroundRefresh", base::FEATURE_DISABLED_BY_DEFAULT}; + +const char kEnableServerDrivenBackgroundRefreshSchedule[] = + "server_driven_schedule"; +const char kEnableRecurringBackgroundRefreshSchedule[] = + "recurring_refresh_schedule"; +const char kBackgroundRefreshIntervalInSeconds[] = + "refresh_interval_in_seconds"; + +bool IsWebChannelsEnabled() { + return base::FeatureList::IsEnabled(kEnableWebChannels); +} + +bool IsFeedBackgroundRefreshEnabled() { + return base::FeatureList::IsEnabled(kEnableFeedBackgroundRefresh); +} + +bool IsServerDrivenBackgroundRefreshScheduleEnabled() { + return base::GetFieldTrialParamByFeatureAsBool( + kEnableFeedBackgroundRefresh, + kEnableServerDrivenBackgroundRefreshSchedule, /*default=*/false); +} + +bool IsRecurringBackgroundRefreshScheduleEnabled() { + return base::GetFieldTrialParamByFeatureAsBool( + kEnableFeedBackgroundRefresh, kEnableRecurringBackgroundRefreshSchedule, + /*default=*/false); +} + +double GetBackgroundRefreshIntervalInSeconds() { + return base::GetFieldTrialParamByFeatureAsDouble( + kEnableFeedBackgroundRefresh, kBackgroundRefreshIntervalInSeconds, + /*default=*/60 * 60); +}
diff --git a/ios/chrome/browser/providers/discover_feed/chromium_discover_feed.mm b/ios/chrome/browser/providers/discover_feed/chromium_discover_feed.mm index 59cc64d..02ac288 100644 --- a/ios/chrome/browser/providers/discover_feed/chromium_discover_feed.mm +++ b/ios/chrome/browser/providers/discover_feed/chromium_discover_feed.mm
@@ -33,6 +33,11 @@ void UpdateTheme() final {} void RefreshFeedIfNeeded() final {} void RefreshFeed() final {} + + void PerformBackgroundRefreshes(ProceduralBlockWithBool completion) final {} + void HandleBackgroundRefreshTaskExpiration() final {} + NSDate* GetEarliestBackgroundRefreshBeginDate() final { return nil; } + BOOL GetFollowingFeedHasUnseenContent() final { return NO; } void SetFollowingFeedContentSeen() final {} };
diff --git a/ios/chrome/browser/ui/first_run/BUILD.gn b/ios/chrome/browser/ui/first_run/BUILD.gn index fc8980e..87917ce3 100644 --- a/ios/chrome/browser/ui/first_run/BUILD.gn +++ b/ios/chrome/browser/ui/first_run/BUILD.gn
@@ -244,9 +244,11 @@ "//components/policy/core/common:common_constants", "//components/policy/test_support:test_support", "//components/signin/ios/browser:features", + "//ios/chrome/app/strings", "//ios/chrome/app/strings:ios_chromium_strings_grit", "//ios/chrome/app/strings:ios_strings_grit", "//ios/chrome/browser/policy:eg_test_support+eg2", + "//ios/chrome/browser/policy:policy_util", "//ios/chrome/browser/ui:feature_flags", "//ios/chrome/browser/ui/authentication:authentication_constants", "//ios/chrome/browser/ui/authentication:eg_test_support+eg2",
diff --git a/ios/chrome/browser/ui/first_run/first_run_two_steps_egtest.mm b/ios/chrome/browser/ui/first_run/first_run_two_steps_egtest.mm index c60c14fc..b7039ba 100644 --- a/ios/chrome/browser/ui/first_run/first_run_two_steps_egtest.mm +++ b/ios/chrome/browser/ui/first_run/first_run_two_steps_egtest.mm
@@ -2,7 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#import "base/i18n/number_formatting.h" +#import "base/strings/string_util.h" +#import "base/strings/sys_string_conversions.h" +#import "components/policy/core/common/policy_loader_ios_constants.h" +#import "components/policy/policy_constants.h" #import "components/signin/ios/browser/features.h" +#import "ios/chrome/browser/policy/policy_earl_grey_utils.h" +#import "ios/chrome/browser/policy/policy_util.h" #import "ios/chrome/browser/ui/authentication/signin_earl_grey.h" #import "ios/chrome/browser/ui/authentication/signin_earl_grey_ui_test_util.h" #import "ios/chrome/browser/ui/authentication/signin_matchers.h" @@ -14,6 +21,7 @@ #import "ios/chrome/browser/ui/ui_feature_flags.h" #import "ios/chrome/common/ui/promo_style/constants.h" #import "ios/chrome/common/ui/table_view/table_view_cells_constants.h" +#import "ios/chrome/grit/ios_google_chrome_strings.h" #import "ios/chrome/grit/ios_strings.h" #import "ios/chrome/test/earl_grey/chrome_actions.h" #import "ios/chrome/test/earl_grey/chrome_earl_grey.h" @@ -23,7 +31,9 @@ #import "ios/chrome/test/earl_grey/test_switches.h" #import "ios/public/provider/chrome/browser/signin/fake_chrome_identity.h" #import "ios/testing/earl_grey/app_launch_configuration.h" +#import "ios/testing/earl_grey/app_launch_manager.h" #import "ios/testing/earl_grey/earl_grey_test.h" +#import "ui/base/l10n/l10n_util.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." @@ -31,6 +41,18 @@ namespace { +// Type of FRE sign-in screen intent. +typedef NS_ENUM(NSUInteger, FRESigninIntent) { + // FRE without enterprise policy. + FRESigninIntentRegular, + // FRE without forced sign-in policy. + FRESigninIntentSigninForcedByPolicy, + // FRE without disabled sign-in policy. + FRESigninIntentSigninDisabledByPolicy, + // FRE with an enterprise policy. + FRESigninIntentSigninWithPolicy, +}; + NSString* const kSyncPassphrase = @"hello"; // Returns matcher for the primary action button. @@ -104,7 +126,8 @@ // Tests FRE with UMA default value and without sign-in. - (void)testWithUMACheckedAndNoSignin { // Verify 2 step FRE. - [self verifyWelcomeScreenIsDisplayed]; + [self verifyEnterpriseWelcomeScreenIsDisplayedWithFRESigninIntent: + FRESigninIntentRegular]; // Skip sign-in. [[self elementInteractionWithGreyMatcher:PromoStyleSecondaryActionButtonMatcher() @@ -122,7 +145,8 @@ // Tests FRE with UMA off and without sign-in. - (void)testWithUMAUncheckedAndNoSignin { // Verify 2 step FRE. - [self verifyWelcomeScreenIsDisplayed]; + [self verifyEnterpriseWelcomeScreenIsDisplayedWithFRESigninIntent: + FRESigninIntentRegular]; // Scroll down and open the UMA dialog. [[self elementInteractionWithGreyMatcher:grey_allOf( ManageUMALinkMatcher(), @@ -158,7 +182,8 @@ // Tests FRE with UMA off, reopen UMA dialog and close the FRE without sign-in. - (void)testUMAUncheckedWhenOpenedSecondTime { // Verify 2 step FRE. - [self verifyWelcomeScreenIsDisplayed]; + [self verifyEnterpriseWelcomeScreenIsDisplayedWithFRESigninIntent: + FRESigninIntentRegular]; // Scroll down and open the UMA dialog. id<GREYMatcher> manageUMALinkMatcher = grey_allOf(ManageUMALinkMatcher(), grey_sufficientlyVisible(), nil); @@ -210,7 +235,8 @@ // Tests to turn off UMA, and open the UMA dialog to turn it back on. - (void)testUMAUncheckedAndCheckItAgain { // Verify 2 step FRE. - [self verifyWelcomeScreenIsDisplayed]; + [self verifyEnterpriseWelcomeScreenIsDisplayedWithFRESigninIntent: + FRESigninIntentRegular]; // Scroll down and open the UMA dialog. id<GREYMatcher> manageUMALinkMatcher = grey_allOf(ManageUMALinkMatcher(), grey_sufficientlyVisible(), nil); @@ -265,7 +291,8 @@ FakeChromeIdentity* fakeIdentity = [FakeChromeIdentity fakeIdentity1]; [SigninEarlGrey addFakeIdentity:fakeIdentity]; // Verify 2 step FRE. - [self verifyWelcomeScreenIsDisplayed]; + [self verifyEnterpriseWelcomeScreenIsDisplayedWithFRESigninIntent: + FRESigninIntentRegular]; // Scroll down and open the UMA dialog. [[self elementInteractionWithGreyMatcher:grey_allOf( ManageUMALinkMatcher(), @@ -313,7 +340,8 @@ FakeChromeIdentity* fakeIdentity = [FakeChromeIdentity fakeIdentity1]; [SigninEarlGrey addFakeIdentity:fakeIdentity]; // Verify 2 step FRE. - [self verifyWelcomeScreenIsDisplayed]; + [self verifyEnterpriseWelcomeScreenIsDisplayedWithFRESigninIntent: + FRESigninIntentRegular]; // Accept sign-in. [[self elementInteractionWithGreyMatcher:PromoStylePrimaryActionButtonMatcher() @@ -343,7 +371,8 @@ FakeChromeIdentity* fakeIdentity = [FakeChromeIdentity fakeIdentity1]; [SigninEarlGrey addFakeIdentity:fakeIdentity]; // Verify 2 step FRE. - [self verifyWelcomeScreenIsDisplayed]; + [self verifyEnterpriseWelcomeScreenIsDisplayedWithFRESigninIntent: + FRESigninIntentRegular]; // Accept sign-in. [[self elementInteractionWithGreyMatcher:PromoStylePrimaryActionButtonMatcher() @@ -373,7 +402,8 @@ FakeChromeIdentity* fakeIdentity = [FakeChromeIdentity fakeIdentity1]; [SigninEarlGrey addFakeIdentity:fakeIdentity]; // Verify 2 step FRE. - [self verifyWelcomeScreenIsDisplayed]; + [self verifyEnterpriseWelcomeScreenIsDisplayedWithFRESigninIntent: + FRESigninIntentRegular]; // Accept sign-in. [[self elementInteractionWithGreyMatcher:PromoStylePrimaryActionButtonMatcher() @@ -453,7 +483,8 @@ FakeChromeIdentity* fakeIdentity = [FakeChromeIdentity fakeIdentity1]; [SigninEarlGrey addFakeIdentity:fakeIdentity]; // Verify 2 step FRE. - [self verifyWelcomeScreenIsDisplayed]; + [self verifyEnterpriseWelcomeScreenIsDisplayedWithFRESigninIntent: + FRESigninIntentRegular]; // Accept sign-in. [[self elementInteractionWithGreyMatcher:PromoStylePrimaryActionButtonMatcher() @@ -486,14 +517,323 @@ [SigninEarlGrey verifySyncUIEnabled:YES]; } +#pragma mark - Enterprise + +// Tests FRE with disabled sign-in policy. +- (void)testSignInDisabledByPolicy { + // Configure the policy to disable SignIn. + [self relaunchAppWithBrowserSigninMode:BrowserSigninMode::kDisabled]; + // Verify 2 step FRE with disabled sign-in policy. + [self verifyEnterpriseWelcomeScreenIsDisplayedWithFRESigninIntent: + FRESigninIntentSigninDisabledByPolicy]; + // Accept FRE. + [[self + elementInteractionWithGreyMatcher:PromoStylePrimaryActionButtonMatcher() + scrollViewIdentifier: + kPromoStyleScrollViewAccessibilityIdentifier] + performAction:grey_tap()]; + // Check that UMA is on. + GREYAssertTrue( + [FirstRunAppInterface isUMACollectionEnabled], + @"kMetricsReportingEnabled pref was unexpectedly false by default."); + // Check signed out. + [SigninEarlGrey verifySignedOut]; +} + +// Tests forced sign-in policy, and accept sync. +- (void)testForceSigninByPolicy { + // Configure the policy to force sign-in. + [self relaunchAppWithBrowserSigninMode:BrowserSigninMode::kForced]; + // Add identity. + FakeChromeIdentity* fakeIdentity = [FakeChromeIdentity fakeIdentity1]; + [SigninEarlGrey addFakeIdentity:fakeIdentity]; + // Verify 2 step FRE with forced sign-in policy. + [self verifyEnterpriseWelcomeScreenIsDisplayedWithFRESigninIntent: + FRESigninIntentSigninForcedByPolicy]; + // Accept sign-in. + [[self + elementInteractionWithGreyMatcher:PromoStylePrimaryActionButtonMatcher() + scrollViewIdentifier: + kPromoStyleScrollViewAccessibilityIdentifier] + performAction:grey_tap()]; + // Accept sync. + [[self + elementInteractionWithGreyMatcher:PromoStylePrimaryActionButtonMatcher() + scrollViewIdentifier: + kPromoStyleScrollViewAccessibilityIdentifier] + performAction:grey_tap()]; + // Check that UMA is on. + GREYAssertTrue( + [FirstRunAppInterface isUMACollectionEnabled], + @"kMetricsReportingEnabled pref was unexpectedly false by default."); + // Check signed in. + [SigninEarlGrey verifySignedInWithFakeIdentity:fakeIdentity]; + // Check sync is on. + [ChromeEarlGreyUI openSettingsMenu]; + [SigninEarlGrey verifySyncUIEnabled:YES]; + // Close settings. + [[EarlGrey selectElementWithMatcher:chrome_test_util::SettingsDoneButton()] + performAction:grey_tap()]; +} + +// Tests forced sign-in policy, and refuse sync. +- (void)testForceSigninByPolicyWithoutSync { + // Configure the policy to force sign-in. + [self relaunchAppWithBrowserSigninMode:BrowserSigninMode::kForced]; + // Add identity. + FakeChromeIdentity* fakeIdentity = [FakeChromeIdentity fakeIdentity1]; + [SigninEarlGrey addFakeIdentity:fakeIdentity]; + // Verify 2 step FRE with forced sign-in policy. + [self verifyEnterpriseWelcomeScreenIsDisplayedWithFRESigninIntent: + FRESigninIntentSigninForcedByPolicy]; + // Accept sign-in. + [[self + elementInteractionWithGreyMatcher:PromoStylePrimaryActionButtonMatcher() + scrollViewIdentifier: + kPromoStyleScrollViewAccessibilityIdentifier] + performAction:grey_tap()]; + // Refuse sync. + [[self + elementInteractionWithGreyMatcher:PromoStyleSecondaryActionButtonMatcher() + scrollViewIdentifier: + kPromoStyleScrollViewAccessibilityIdentifier] + performAction:grey_tap()]; + // Check that UMA is on. + GREYAssertTrue( + [FirstRunAppInterface isUMACollectionEnabled], + @"kMetricsReportingEnabled pref was unexpectedly false by default."); + // Check signed in. + [SigninEarlGrey verifySignedInWithFakeIdentity:fakeIdentity]; + // Check sync is on. + [ChromeEarlGreyUI openSettingsMenu]; + [SigninEarlGrey verifySyncUIEnabled:NO]; + // Close settings. + [[EarlGrey selectElementWithMatcher:chrome_test_util::SettingsDoneButton()] + performAction:grey_tap()]; +} + +// Tests sign-in with sync disabled policy. +- (void)testSyncDisabledByPolicy { + [self relaunchAppWithPolicyKey:policy::key::kSyncDisabled + xmlPolicyValue:"<true/>"]; + // Add identity. + FakeChromeIdentity* fakeIdentity = [FakeChromeIdentity fakeIdentity1]; + [SigninEarlGrey addFakeIdentity:fakeIdentity]; + // Verify 2 step FRE with forced sign-in policy. + [self verifyEnterpriseWelcomeScreenIsDisplayedWithFRESigninIntent: + FRESigninIntentSigninWithPolicy]; + // Accept sign-in. + [[self + elementInteractionWithGreyMatcher:PromoStylePrimaryActionButtonMatcher() + scrollViewIdentifier: + kPromoStyleScrollViewAccessibilityIdentifier] + performAction:grey_tap()]; + // Check that UMA is on. + GREYAssertTrue( + [FirstRunAppInterface isUMACollectionEnabled], + @"kMetricsReportingEnabled pref was unexpectedly false by default."); + // Check signed in. + [SigninEarlGrey verifySignedInWithFakeIdentity:fakeIdentity]; + // Check sync is on. + [ChromeEarlGreyUI openSettingsMenu]; + [SigninEarlGrey verifySyncUIEnabled:NO]; +} + +// Tests sign-in and no sync with forced policy. +- (void)testSigninWithOnlyBookmarkSyncDataTypeEnabled { + // Configure the policy to force sign-in. + [self relaunchAppWithPolicyKey:policy::key::kSyncTypesListDisabled + xmlPolicyValue:"<array><string>bookmarks</string></array>"]; + // Add identity. + FakeChromeIdentity* fakeIdentity = [FakeChromeIdentity fakeIdentity1]; + [SigninEarlGrey addFakeIdentity:fakeIdentity]; + // Verify 2 step FRE with forced sign-in policy. + [self verifyEnterpriseWelcomeScreenIsDisplayedWithFRESigninIntent: + FRESigninIntentSigninWithPolicy]; + // Accept sign-in. + [[self + elementInteractionWithGreyMatcher:PromoStylePrimaryActionButtonMatcher() + scrollViewIdentifier: + kPromoStyleScrollViewAccessibilityIdentifier] + performAction:grey_tap()]; + // Open advanced sync settings. + [[EarlGrey selectElementWithMatcher:GetSyncSettings()] + performAction:grey_tap()]; + // Check "Sync Everything" is off + [[EarlGrey selectElementWithMatcher: + grey_allOf(grey_accessibilityID( + kSyncEverythingItemAccessibilityIdentifier), + grey_descendant(grey_text( + l10n_util::GetNSString(IDS_IOS_SETTING_OFF))), + nil)] assertWithMatcher:grey_notNil()]; + // Check "Bookmarks" is off + [[EarlGrey selectElementWithMatcher:grey_allOf(grey_accessibilityID( + kSyncBookmarksIdentifier), + grey_descendant(grey_text( + l10n_util::GetNSString( + IDS_IOS_SETTING_OFF))), + nil)] + assertWithMatcher:grey_notNil()]; + // Close the advanced sync settings. + [[EarlGrey selectElementWithMatcher: + chrome_test_util::AdvancedSyncSettingsDoneButtonMatcher()] + performAction:grey_tap()]; + // Accept sync. + [[self + elementInteractionWithGreyMatcher:PromoStylePrimaryActionButtonMatcher() + scrollViewIdentifier: + kPromoStyleScrollViewAccessibilityIdentifier] + performAction:grey_tap()]; + // Check that UMA is on. + GREYAssertTrue( + [FirstRunAppInterface isUMACollectionEnabled], + @"kMetricsReportingEnabled pref was unexpectedly false by default."); + // Check signed in. + [SigninEarlGrey verifySignedInWithFakeIdentity:fakeIdentity]; + // Check sync is on. + [ChromeEarlGreyUI openSettingsMenu]; + [SigninEarlGrey verifySyncUIEnabled:YES]; +} + +// Tests enterprise policy wording on FRE when incognito policy is set. +- (void)testIncognitoPolicy { + // Configure the policy to force sign-in. + [self relaunchAppWithPolicyKey:policy::key::kIncognitoModeAvailability + xmlPolicyValue:"<integer>1</integer>"]; + // Add identity. + FakeChromeIdentity* fakeIdentity = [FakeChromeIdentity fakeIdentity1]; + [SigninEarlGrey addFakeIdentity:fakeIdentity]; + // Verify 2 step FRE with forced sign-in policy. + [self verifyEnterpriseWelcomeScreenIsDisplayedWithFRESigninIntent: + FRESigninIntentSigninWithPolicy]; + // Refuse sign-in. + [[self + elementInteractionWithGreyMatcher:PromoStyleSecondaryActionButtonMatcher() + scrollViewIdentifier: + kPromoStyleScrollViewAccessibilityIdentifier] + performAction:grey_tap()]; + // Check that UMA is on. + GREYAssertTrue( + [FirstRunAppInterface isUMACollectionEnabled], + @"kMetricsReportingEnabled pref was unexpectedly false by default."); + // Check signed out. + [SigninEarlGrey verifySignedOut]; +} + #pragma mark Helper -// Checks that the sign-in screen is displayed. -- (void)verifyWelcomeScreenIsDisplayed { +- (void)relaunchAppWithBrowserSigninMode:(BrowserSigninMode)mode { + std::string xmlPolicyValue("<integer>"); + xmlPolicyValue += std::to_string(static_cast<int>(mode)); + xmlPolicyValue += "</integer>"; + [self relaunchAppWithPolicyKey:policy::key::kBrowserSignin + xmlPolicyValue:xmlPolicyValue]; +} + +// Sets policy value and relaunches the app. +- (void)relaunchAppWithPolicyKey:(std::string)policyKey + xmlPolicyValue:(std::string)xmlPolicyValue { + std::string policyData = std::string("<dict><key>") + policyKey + "</key>" + + xmlPolicyValue + "</dict>"; + // Configure the policy to force sign-in. + AppLaunchConfiguration config = self.appConfigurationForTestCase; + config.additional_args.push_back( + "-" + base::SysNSStringToUTF8(kPolicyLoaderIOSConfigurationKey)); + config.additional_args.push_back(policyData); + // Relaunch the app to take the configuration into account. + [[AppLaunchManager sharedManager] ensureAppLaunchedWithConfiguration:config]; +} + +// Checks that the sign-in screen for enterprise is displayed. +- (void)verifyEnterpriseWelcomeScreenIsDisplayedWithFRESigninIntent: + (FRESigninIntent)FRESigninIntent { [[EarlGrey selectElementWithMatcher: grey_accessibilityID( first_run::kFirstRunSignInScreenAccessibilityIdentifier)] assertWithMatcher:grey_notNil()]; + NSString* title = nil; + NSString* subtitle = nil; + NSMutableArray* disclaimerStrings = [NSMutableArray array]; + switch (FRESigninIntent) { + case FRESigninIntentRegular: + title = l10n_util::GetNSString(IDS_IOS_FIRST_RUN_SIGNIN_TITLE); + subtitle = + l10n_util::GetNSString(IDS_IOS_FIRST_RUN_SIGNIN_SUBTITLE_SHORT); + break; + case FRESigninIntentSigninForcedByPolicy: + title = + l10n_util::GetNSString(IDS_IOS_FIRST_RUN_SIGNIN_TITLE_SIGNIN_FORCED); + subtitle = l10n_util::GetNSString( + IDS_IOS_FIRST_RUN_SIGNIN_SUBTITLE_SIGNIN_FORCED); + [disclaimerStrings + addObject:l10n_util::GetNSString( + IDS_IOS_FIRST_RUN_WELCOME_SCREEN_BROWSER_MANAGED)]; + break; + case FRESigninIntentSigninDisabledByPolicy: + if ([ChromeEarlGrey isIPadIdiom]) { + title = + l10n_util::GetNSString(IDS_IOS_FIRST_RUN_WELCOME_SCREEN_TITLE_IPAD); + } else { + title = l10n_util::GetNSString( + IDS_IOS_FIRST_RUN_WELCOME_SCREEN_TITLE_IPHONE); + } + subtitle = + l10n_util::GetNSString(IDS_IOS_FIRST_RUN_WELCOME_SCREEN_SUBTITLE); + [disclaimerStrings + addObject:l10n_util::GetNSString( + IDS_IOS_FIRST_RUN_WELCOME_SCREEN_BROWSER_MANAGED)]; + break; + case FRESigninIntentSigninWithPolicy: + title = l10n_util::GetNSString(IDS_IOS_FIRST_RUN_SIGNIN_TITLE); + subtitle = + l10n_util::GetNSString(IDS_IOS_FIRST_RUN_SIGNIN_SUBTITLE_SHORT); + [disclaimerStrings + addObject:l10n_util::GetNSString( + IDS_IOS_FIRST_RUN_WELCOME_SCREEN_BROWSER_MANAGED)]; + break; + } + [disclaimerStrings + addObject:l10n_util::GetNSString( + IDS_IOS_FIRST_RUN_WELCOME_SCREEN_TERMS_OF_SERVICE)]; + [disclaimerStrings + addObject:l10n_util::GetNSString( + IDS_IOS_FIRST_RUN_WELCOME_SCREEN_METRIC_REPORTING)]; + // Validate the Title text. + [[self elementInteractionWithGreyMatcher:grey_allOf( + grey_text(title), + grey_sufficientlyVisible(), nil) + scrollViewIdentifier: + kPromoStyleScrollViewAccessibilityIdentifier] + assertWithMatcher:grey_notNil()]; + // Validate the Subtitle text. + [[self elementInteractionWithGreyMatcher:grey_allOf( + grey_text(subtitle), + grey_sufficientlyVisible(), nil) + scrollViewIdentifier: + kPromoStyleScrollViewAccessibilityIdentifier] + assertWithMatcher:grey_notNil()]; + // Validate the Managed text. + [self verifyDisclaimerFooterWithStrings:disclaimerStrings]; +} + +// Checks the disclaimer footer with the list of strings. |strings| can contain +// "BEGIN_LINK" and "END_LINK" for URL tags. +- (void)verifyDisclaimerFooterWithStrings:(NSArray*)strings { + NSString* disclaimerText = [strings componentsJoinedByString:@" "]; + // Remove URL tags. + disclaimerText = + [disclaimerText stringByReplacingOccurrencesOfString:@"BEGIN_LINK" + withString:@""]; + disclaimerText = + [disclaimerText stringByReplacingOccurrencesOfString:@"END_LINK" + withString:@""]; + // Check the footer. + [[self elementInteractionWithGreyMatcher:grey_allOf( + grey_text(disclaimerText), + grey_sufficientlyVisible(), nil) + scrollViewIdentifier: + kPromoStyleScrollViewAccessibilityIdentifier] + assertWithMatcher:grey_notNil()]; } // Returns GREYElementInteraction for `matcher`, using `scrollViewMatcher` to
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 index f44ad23..fcb5d77 100644 --- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -70174f942cb394e749ae50d35f144175fb9bc865 \ No newline at end of file +5a22ae7e156c6d3bbee8f14a9051bd82655aef38 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 index 5e81cf7..0a2dc443 100644 --- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -f2457cb8b78f584d8597cd51264795f5c8596670 \ No newline at end of file +695bfa5d83ee40f45dd04abcfa772cc13941f17a \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 index 7746f2a6..9a6f005a 100644 --- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -d6da5d371949a3eeab09ba47640aed12dadb68d9 \ No newline at end of file +069522c9aad31d61dbf0dd5c4d192ee39087e04b \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 index 2056615..b8040a9 100644 --- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -59cc12e8eb4a524b8bed3f70690bbaab3074016d \ No newline at end of file +53dcb38023d5b4e50418da5e9d2c20e496933586 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1 index a07fa41..bad25fb 100644 --- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -33f56970f0d08374788bf55033eb781dde3a01aa \ No newline at end of file +46f1347d191bb8805f12f55ad60b9f7d18cb6db1 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1 index 66c7db6..dac92fca 100644 --- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -cb42f35fcb4b45fa94b869a3b11e4e4b6772d76a \ No newline at end of file +34b0e6555fbc60dca4a9d05fad9ba9abc08c372a \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 index 4431c21..70688f2b 100644 --- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -9e723141b3317e9cb3dbaffbe5c8fb7d1421ad3d \ No newline at end of file +7991932307909cfc1283230ae3ae45b20c92c60f \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 index 8a3dbb1..4f6242d 100644 --- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -76ccdda6d65e2b3c095d6d5db68ac96da7206e57 \ No newline at end of file +f68d628527e49e768855fe1d065755e6ec8fe444 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 index a5b6ce0..791b6ab3 100644 --- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -7999df39e1dd7dd7ee385e714d7442dae445d948 \ No newline at end of file +aca876528cd4c3ce0c19987ba213f2e51a38e412 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 index f38aa12..4a44112 100644 --- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -eab519fb8ae46c5232127a4df66c3c6f1c3a5815 \ No newline at end of file +f4d3130ba4d97003cc162231b569d2d93dcc7aec \ No newline at end of file
diff --git a/ios/web/public/js_messaging/resources/gcrweb.ts b/ios/web/public/js_messaging/resources/gcrweb.ts index f4ac663..c94ffe9 100644 --- a/ios/web/public/js_messaging/resources/gcrweb.ts +++ b/ios/web/public/js_messaging/resources/gcrweb.ts
@@ -27,6 +27,6 @@ (window as GCRWebType).__gCrWeb = {}; } -const gCrWeb: any = (window as GCRWebType).__gCrWeb = {}; +const gCrWeb: any = (window as GCRWebType).__gCrWeb; -export {gCrWeb}; \ No newline at end of file +export {gCrWeb};
diff --git a/media/PRESUBMIT.py b/media/PRESUBMIT.py index d3c636d6..7e5ba9c 100644 --- a/media/PRESUBMIT.py +++ b/media/PRESUBMIT.py
@@ -54,11 +54,16 @@ # base::Time class. We want to prevent these from triggerring a warning. base_time_konstant_pattern = r'(^|\W)Time::k\w+' + # Regular expression to detect usage of openscreen clock types, which are + # allowed depending on DEPS rules. + openscreen_time_pattern = r'(^|\W)openscreen::Clock\s*' + problem_re = input_api.re.compile( r'(' + base_time_type_pattern + r')|(' + base_time_member_pattern + r')') exception_re = input_api.re.compile( r'(' + using_base_time_decl_pattern + r')|(' + - base_time_konstant_pattern + r')') + base_time_konstant_pattern + r')|(' + + openscreen_time_pattern + r')') problems = [] for f in input_api.AffectedSourceFiles(_FilterFile): for line_number, line in f.ChangedContents():
diff --git a/media/base/eme_constants.h b/media/base/eme_constants.h index 039fff44..c243e83 100644 --- a/media/base/eme_constants.h +++ b/media/base/eme_constants.h
@@ -7,6 +7,7 @@ #include <stdint.h> +#include "media/base/media_export.h" #include "media/media_buildflags.h" namespace media { @@ -146,59 +147,41 @@ VIDEO, }; -// Configuration rules indicate the configuration state required to support a -// configuration option (note: a configuration option may be disallowing a -// feature). Configuration rules are used to answer queries about distinctive -// identifier, persistent state, and robustness requirements, as well as to -// describe support for different session types. -// -// If in the future there are reasons to request user permission other than -// access to a distinctive identifier, then additional rules should be added. -// Rules are implemented in ConfigState and are otherwise opaque. -enum class EmeConfigRule { - // The configuration option is not supported. - NOT_SUPPORTED, +enum class EmeConfigRuleState { + // To correctly identify the EmeConfigRule as Supported, + // we use the enum value kUnset for each of the rules so + // that it is easy to check for, and cannot be confused. + kUnset, - // The configuration option prevents use of a distinctive identifier. - IDENTIFIER_NOT_ALLOWED, + // Not Allowed represents when the rule in the collection of + // EmeConfigRules is not allowed by the current system. + kNotAllowed, - // The configuration option is supported if a distinctive identifier is - // available. - IDENTIFIER_REQUIRED, + // Recommended represents when the rule in the collection of + // EmeConfigRules is recommended by the current system. In + // our design, the recommended takes a second priority and + // cannot override the NotAllowed or Required value. + kRecommended, - // The configuration option is supported, but the user experience may be - // improved if a distinctive identifier is available. - IDENTIFIER_RECOMMENDED, - - // The configuration option prevents use of persistent state. - PERSISTENCE_NOT_ALLOWED, - - // The configuration option is supported if persistent state is available. - PERSISTENCE_REQUIRED, - - // The configuration option is supported if both a distinctive identifier and - // persistent state are available. - IDENTIFIER_AND_PERSISTENCE_REQUIRED, - - // The configuration option prevents use of hardware-secure codecs. - HW_SECURE_CODECS_NOT_ALLOWED, - - // The configuration option is supported if hardware-secure codecs are used. - HW_SECURE_CODECS_REQUIRED, - - // The configuration option is supported on platforms where hardware-secure - // codecs are used and an identifier is also required (i.e. ChromeOS). - IDENTIFIER_AND_HW_SECURE_CODECS_REQUIRED, - - // The configuration option is supported on platforms where hardware-secure - // codecs are used and both identifier and persistent state are required (i.e. - // Windows). - IDENTIFIER_PERSISTENCE_AND_HW_SECURE_CODECS_REQUIRED, - - // The configuration option is supported without conditions. - SUPPORTED, + // Required represents when the rule in the collection of + // EmeConfigRules is required by the current system. + kRequired, }; +struct MEDIA_EXPORT EmeConfigRule { + // Refer to the EME spec for definitions on what + // identifier, persistence, and hw_secure_codecs represent. + EmeConfigRuleState identifier = EmeConfigRuleState::kUnset; + EmeConfigRuleState persistence = EmeConfigRuleState::kUnset; + EmeConfigRuleState hw_secure_codecs = EmeConfigRuleState::kUnset; +}; + +inline bool operator==(EmeConfigRule const& lhs, EmeConfigRule const& rhs) { + return lhs.persistence == rhs.persistence && + lhs.identifier == rhs.identifier && + lhs.hw_secure_codecs == rhs.hw_secure_codecs; +} + } // namespace media #endif // MEDIA_BASE_EME_CONSTANTS_H_
diff --git a/media/base/key_system_properties.h b/media/base/key_system_properties.h index 1d2b81c..0ade370 100644 --- a/media/base/key_system_properties.h +++ b/media/base/key_system_properties.h
@@ -12,6 +12,7 @@ #include "media/base/decrypt_config.h" #include "media/base/eme_constants.h" #include "media/base/media_export.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { @@ -38,7 +39,7 @@ EmeInitDataType init_data_type) const = 0; // Returns the configuration rule for supporting |encryption_scheme|. - virtual EmeConfigRule GetEncryptionSchemeConfigRule( + virtual absl::optional<EmeConfigRule> GetEncryptionSchemeConfigRule( EncryptionScheme encryption_scheme) const = 0; // Returns the codecs supported by this key system. @@ -58,7 +59,7 @@ // must be applied. // TODO(crbug.com/1204284): Refactor this and remove the // `hw_secure_requirement` argument. - virtual EmeConfigRule GetRobustnessConfigRule( + virtual absl::optional<EmeConfigRule> GetRobustnessConfigRule( const std::string& key_system, EmeMediaType media_type, const std::string& requested_robustness, @@ -71,7 +72,8 @@ // explicitly. // TODO(crbug.com/1324262): Refactor `EmeConfigRule` to make it easier to // express combinations of requirements. - virtual EmeConfigRule GetPersistentLicenseSessionSupport() const = 0; + virtual absl::optional<EmeConfigRule> GetPersistentLicenseSessionSupport() + const = 0; // Returns the support this key system provides for persistent state. virtual EmeFeatureSupport GetPersistentStateSupport() const = 0;
diff --git a/media/base/key_systems.cc b/media/base/key_systems.cc index ccfd3bcd..f1e0672 100644 --- a/media/base/key_systems.cc +++ b/media/base/key_systems.cc
@@ -19,6 +19,7 @@ #include "base/strings/string_util.h" #include "base/threading/thread_checker.h" #include "build/build_config.h" +#include "media/base/eme_constants.h" #include "media/base/key_system_names.h" #include "media/base/key_system_properties.h" #include "media/base/media.h" @@ -148,17 +149,18 @@ init_data_type == EmeInitDataType::KEYIDS; } - media::EmeConfigRule GetEncryptionSchemeConfigRule( + absl::optional<EmeConfigRule> GetEncryptionSchemeConfigRule( media::EncryptionScheme encryption_scheme) const final { switch (encryption_scheme) { case media::EncryptionScheme::kCenc: - case media::EncryptionScheme::kCbcs: - return media::EmeConfigRule::SUPPORTED; + case media::EncryptionScheme::kCbcs: { + return EmeConfigRule(); + } case media::EncryptionScheme::kUnencrypted: break; } NOTREACHED(); - return media::EmeConfigRule::NOT_SUPPORTED; + return absl::nullopt; } SupportedCodecs GetSupportedCodecs() const final { @@ -168,17 +170,21 @@ return EME_CODEC_WEBM_ALL | EME_CODEC_MP4_ALL; } - EmeConfigRule GetRobustnessConfigRule( + absl::optional<EmeConfigRule> GetRobustnessConfigRule( const std::string& key_system, EmeMediaType media_type, const std::string& requested_robustness, const bool* /*hw_secure_requirement*/) const final { - return requested_robustness.empty() ? EmeConfigRule::SUPPORTED - : EmeConfigRule::NOT_SUPPORTED; + if (requested_robustness.empty()) { + return EmeConfigRule(); + } else { + return absl::nullopt; + } } - EmeConfigRule GetPersistentLicenseSessionSupport() const final { - return EmeConfigRule::NOT_SUPPORTED; + absl::optional<EmeConfigRule> GetPersistentLicenseSessionSupport() + const final { + return absl::nullopt; } EmeFeatureSupport GetPersistentStateSupport() const final { @@ -282,20 +288,20 @@ bool CanUseAesDecryptor(const std::string& key_system) const override; bool IsSupportedInitDataType(const std::string& key_system, EmeInitDataType init_data_type) const override; - EmeConfigRule GetEncryptionSchemeConfigRule( + absl::optional<EmeConfigRule> GetEncryptionSchemeConfigRule( const std::string& key_system, EncryptionScheme encryption_scheme) const override; - EmeConfigRule GetContentTypeConfigRule( + absl::optional<EmeConfigRule> GetContentTypeConfigRule( const std::string& key_system, EmeMediaType media_type, const std::string& container_mime_type, const std::vector<std::string>& codecs) const override; - EmeConfigRule GetRobustnessConfigRule( + absl::optional<EmeConfigRule> GetRobustnessConfigRule( const std::string& key_system, EmeMediaType media_type, const std::string& requested_robustness, const bool* hw_secure_requirement) const override; - EmeConfigRule GetPersistentLicenseSessionSupport( + absl::optional<EmeConfigRule> GetPersistentLicenseSessionSupport( const std::string& key_system) const override; EmeFeatureSupport GetPersistentStateSupport( const std::string& key_system) const override; @@ -501,8 +507,7 @@ // sessions. if (properties->GetPersistentStateSupport() == EmeFeatureSupport::NOT_SUPPORTED) { - DCHECK(properties->GetPersistentLicenseSessionSupport() == - EmeConfigRule::NOT_SUPPORTED); + DCHECK(!properties->GetPersistentLicenseSessionSupport().has_value()); } if (!CanBlock(*properties)) { @@ -580,7 +585,7 @@ return properties->IsSupportedInitDataType(init_data_type); } -EmeConfigRule KeySystemsImpl::GetEncryptionSchemeConfigRule( +absl::optional<EmeConfigRule> KeySystemsImpl::GetEncryptionSchemeConfigRule( const std::string& key_system, EncryptionScheme encryption_scheme) const { DCHECK(thread_checker_.CalledOnValidThread()); @@ -588,7 +593,7 @@ const auto* properties = GetKeySystemProperties(key_system); if (!properties) { NOTREACHED(); - return EmeConfigRule::NOT_SUPPORTED; + return absl::nullopt; } return properties->GetEncryptionSchemeConfigRule(encryption_scheme); @@ -657,7 +662,7 @@ return properties->UseAesDecryptor(); } -EmeConfigRule KeySystemsImpl::GetContentTypeConfigRule( +absl::optional<EmeConfigRule> KeySystemsImpl::GetContentTypeConfigRule( const std::string& key_system, EmeMediaType media_type, const std::string& container_mime_type, @@ -668,13 +673,15 @@ switch (media_type) { case EmeMediaType::AUDIO: if (!base::StartsWith(container_mime_type, "audio/", - base::CompareCase::SENSITIVE)) - return EmeConfigRule::NOT_SUPPORTED; + base::CompareCase::SENSITIVE)) { + return absl::nullopt; + } break; case EmeMediaType::VIDEO: if (!base::StartsWith(container_mime_type, "video/", - base::CompareCase::SENSITIVE)) - return EmeConfigRule::NOT_SUPPORTED; + base::CompareCase::SENSITIVE)) { + return absl::nullopt; + } break; } @@ -682,7 +689,7 @@ const auto* properties = GetKeySystemProperties(key_system); if (!properties) { NOTREACHED() << "Key system support should have been checked"; - return EmeConfigRule::NOT_SUPPORTED; + return absl::nullopt; } // Look up the key system's supported codecs and secure codecs. @@ -697,7 +704,7 @@ if ((key_system_codec_mask & mime_type_codec_mask) == 0) { DVLOG(2) << "Container " << container_mime_type << " not supported by " << key_system; - return EmeConfigRule::NOT_SUPPORTED; + return absl::nullopt; } // Check that the codecs are supported by the key system and container based @@ -707,13 +714,13 @@ // yes | no | HW_SECURE_CODECS_NOT_ALLOWED // no | yes | HW_SECURE_CODECS_REQUIRED // no | no | NOT_SUPPORTED - EmeConfigRule support = EmeConfigRule::SUPPORTED; - for (size_t i = 0; i < codecs.size(); i++) { + auto to_support = EmeConfigRule(); + for (auto& codec_iterator : codecs) { EmeCodec codec = - GetEmeCodecForString(media_type, container_mime_type, codecs[i]); + GetEmeCodecForString(media_type, container_mime_type, codec_iterator); if (codec == EME_CODEC_NONE) { - DVLOG(2) << "Unsupported codec string \"" << codecs[i] << "\""; - return EmeConfigRule::NOT_SUPPORTED; + DVLOG(2) << "Unsupported codec string \"" << codec_iterator << "\""; + return absl::nullopt; } // Currently all EmeCodecs only have one bit set. In case there could be @@ -724,31 +731,35 @@ (codec & key_system_hw_secure_codec_mask & mime_type_codec_mask) != codec) { DVLOG(2) << "Container/codec pair (" << container_mime_type << " / " - << codecs[i] << ") not supported by " << key_system; - return EmeConfigRule::NOT_SUPPORTED; + << codec_iterator << ") not supported by " << key_system; + return absl::nullopt; } // Check whether the codec supports a hardware-secure mode (any level). if ((codec & key_system_hw_secure_codec_mask) != codec) { DCHECK_EQ(codec & key_system_codec_mask, codec); - if (support == EmeConfigRule::HW_SECURE_CODECS_REQUIRED) - return EmeConfigRule::NOT_SUPPORTED; - support = EmeConfigRule::HW_SECURE_CODECS_NOT_ALLOWED; + if (to_support.hw_secure_codecs == EmeConfigRuleState::kRequired) { + return absl::nullopt; + } + + to_support.hw_secure_codecs = EmeConfigRuleState::kNotAllowed; } // Check whether the codec requires a hardware-secure mode (any level). if ((codec & key_system_codec_mask) != codec) { DCHECK_EQ(codec & key_system_hw_secure_codec_mask, codec); - if (support == EmeConfigRule::HW_SECURE_CODECS_NOT_ALLOWED) - return EmeConfigRule::NOT_SUPPORTED; - support = EmeConfigRule::HW_SECURE_CODECS_REQUIRED; + if (to_support.hw_secure_codecs == EmeConfigRuleState::kNotAllowed) { + return absl::nullopt; + } + + to_support.hw_secure_codecs = EmeConfigRuleState::kRequired; } } - return support; + return to_support; } -EmeConfigRule KeySystemsImpl::GetRobustnessConfigRule( +absl::optional<EmeConfigRule> KeySystemsImpl::GetRobustnessConfigRule( const std::string& key_system, EmeMediaType media_type, const std::string& requested_robustness, @@ -758,21 +769,22 @@ const auto* properties = GetKeySystemProperties(key_system); if (!properties) { NOTREACHED(); - return EmeConfigRule::NOT_SUPPORTED; + return absl::nullopt; } return properties->GetRobustnessConfigRule( key_system, media_type, requested_robustness, hw_secure_requirement); } -EmeConfigRule KeySystemsImpl::GetPersistentLicenseSessionSupport( +absl::optional<EmeConfigRule> +KeySystemsImpl::GetPersistentLicenseSessionSupport( const std::string& key_system) const { DCHECK(thread_checker_.CalledOnValidThread()); const auto* properties = GetKeySystemProperties(key_system); if (!properties) { NOTREACHED(); - return EmeConfigRule::NOT_SUPPORTED; + return absl::nullopt; } return properties->GetPersistentLicenseSessionSupport();
diff --git a/media/base/key_systems.h b/media/base/key_systems.h index 3635e8d..ed002d7 100644 --- a/media/base/key_systems.h +++ b/media/base/key_systems.h
@@ -55,13 +55,13 @@ EmeInitDataType init_data_type) const = 0; // Returns the configuration rule for supporting |encryption_scheme|. - virtual EmeConfigRule GetEncryptionSchemeConfigRule( + virtual absl::optional<EmeConfigRule> GetEncryptionSchemeConfigRule( const std::string& key_system, EncryptionScheme encryption_scheme) const = 0; // Returns the configuration rule for supporting a container and a list of // codecs. - virtual EmeConfigRule GetContentTypeConfigRule( + virtual absl::optional<EmeConfigRule> GetContentTypeConfigRule( const std::string& key_system, EmeMediaType media_type, const std::string& container_mime_type, @@ -75,14 +75,14 @@ // must be applied. // TODO(crbug.com/1204284): Refactor this and remove the // `hw_secure_requirement` argument. - virtual EmeConfigRule GetRobustnessConfigRule( + virtual absl::optional<EmeConfigRule> GetRobustnessConfigRule( const std::string& key_system, EmeMediaType media_type, const std::string& requested_robustness, const bool* hw_secure_requirement) const = 0; // Returns the support |key_system| provides for persistent-license sessions. - virtual EmeConfigRule GetPersistentLicenseSessionSupport( + virtual absl::optional<EmeConfigRule> GetPersistentLicenseSessionSupport( const std::string& key_system) const = 0; // Returns the support |key_system| provides for persistent state.
diff --git a/media/base/key_systems_unittest.cc b/media/base/key_systems_unittest.cc index fc4df1bc..823dc327 100644 --- a/media/base/key_systems_unittest.cc +++ b/media/base/key_systems_unittest.cc
@@ -24,6 +24,7 @@ #include "media/base/media_client.h" #include "media/media_buildflags.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/widevine/cdm/widevine_cdm_common.h" namespace media { @@ -76,13 +77,15 @@ return EME_CODEC_WEBM_ALL | TEST_CODEC_FOO_AUDIO | TEST_CODEC_FOO_VIDEO; } - EmeConfigRule GetRobustnessConfigRule( + absl::optional<EmeConfigRule> GetRobustnessConfigRule( const std::string& key_system, EmeMediaType media_type, const std::string& requested_robustness, const bool* /*hw_secure_requirement*/) const override { - return requested_robustness.empty() ? EmeConfigRule::SUPPORTED - : EmeConfigRule::NOT_SUPPORTED; + if (requested_robustness.empty()) { + return EmeConfigRule(); + } + return absl::nullopt; } }; @@ -92,16 +95,18 @@ std::string GetBaseKeySystemName() const override { return name_; } - EmeConfigRule GetEncryptionSchemeConfigRule( + absl::optional<EmeConfigRule> GetEncryptionSchemeConfigRule( EncryptionScheme encryption_scheme) const override { - return (encryption_scheme == EncryptionScheme::kUnencrypted || - encryption_scheme == EncryptionScheme::kCenc) - ? EmeConfigRule::SUPPORTED - : EmeConfigRule::NOT_SUPPORTED; + if ((encryption_scheme == EncryptionScheme::kUnencrypted || + encryption_scheme == EncryptionScheme::kCenc)) { + return EmeConfigRule(); + } + return absl::nullopt; } - EmeConfigRule GetPersistentLicenseSessionSupport() const override { - return EmeConfigRule::NOT_SUPPORTED; + absl::optional<EmeConfigRule> GetPersistentLicenseSessionSupport() + const override { + return absl::nullopt; } EmeFeatureSupport GetPersistentStateSupport() const override { @@ -124,17 +129,18 @@ // Pretend clear (unencrypted) and 'cenc' content are always supported. But // 'cbcs' is not supported by hardware secure codecs. - EmeConfigRule GetEncryptionSchemeConfigRule( + absl::optional<EmeConfigRule> GetEncryptionSchemeConfigRule( EncryptionScheme encryption_scheme) const override { switch (encryption_scheme) { case media::EncryptionScheme::kUnencrypted: case media::EncryptionScheme::kCenc: - return media::EmeConfigRule::SUPPORTED; + return EmeConfigRule(); case media::EncryptionScheme::kCbcs: - return media::EmeConfigRule::HW_SECURE_CODECS_NOT_ALLOWED; + return EmeConfigRule{.hw_secure_codecs = + EmeConfigRuleState::kNotAllowed}; } NOTREACHED(); - return media::EmeConfigRule::NOT_SUPPORTED; + return absl::nullopt; } // We have hardware secure codec support for FOO_VIDEO and FOO_SECURE_VIDEO. @@ -142,24 +148,26 @@ return TEST_CODEC_FOO_VIDEO | TEST_CODEC_FOO_SECURE_VIDEO; } - EmeConfigRule GetRobustnessConfigRule( + absl::optional<EmeConfigRule> GetRobustnessConfigRule( const std::string& key_system, EmeMediaType media_type, const std::string& requested_robustness, const bool* /*hw_secure_requirement*/) const override { - if (requested_robustness == kRobustnessSupported) - return EmeConfigRule::SUPPORTED; - else if (requested_robustness == kRobustnessSecureCodecsRequired) - return EmeConfigRule::HW_SECURE_CODECS_REQUIRED; - else if (requested_robustness == kRobustnessNotSupported) - return EmeConfigRule::NOT_SUPPORTED; - else + if (requested_robustness == kRobustnessSupported) { + return EmeConfigRule(); + } else if (requested_robustness == kRobustnessSecureCodecsRequired) { + return EmeConfigRule{.hw_secure_codecs = EmeConfigRuleState::kRequired}; + } else if (requested_robustness == kRobustnessNotSupported) { + return absl::nullopt; + } else { NOTREACHED(); - return EmeConfigRule::NOT_SUPPORTED; + return absl::nullopt; + } } - EmeConfigRule GetPersistentLicenseSessionSupport() const override { - return EmeConfigRule::SUPPORTED; + absl::optional<EmeConfigRule> GetPersistentLicenseSessionSupport() + const override { + return absl::nullopt; } EmeFeatureSupport GetPersistentStateSupport() const override { @@ -171,15 +179,16 @@ } }; -void ExpectEncryptionSchemeConfigRule(const std::string& key_system, - EncryptionScheme encryption_scheme, - EmeConfigRule expected_rule) { +void ExpectEncryptionSchemeConfigRule( + const std::string& key_system, + EncryptionScheme encryption_scheme, + absl::optional<EmeConfigRule> expected_rule) { EXPECT_EQ(expected_rule, KeySystems::GetInstance()->GetEncryptionSchemeConfigRule( key_system, encryption_scheme)); } -EmeConfigRule GetVideoContentTypeConfigRule( +absl::optional<EmeConfigRule> GetVideoContentTypeConfigRule( const std::string& mime_type, const std::vector<std::string>& codecs, const std::string& key_system) { @@ -193,24 +202,26 @@ const std::string& mime_type, const std::vector<std::string>& codecs, const std::string& key_system) { - return (GetVideoContentTypeConfigRule(mime_type, codecs, key_system) != - EmeConfigRule::NOT_SUPPORTED); + return ( + GetVideoContentTypeConfigRule(mime_type, codecs, key_system).has_value()); } bool IsSupportedKeySystemWithAudioMimeType( const std::string& mime_type, const std::vector<std::string>& codecs, const std::string& key_system) { - return (KeySystems::GetInstance()->GetContentTypeConfigRule( - key_system, EmeMediaType::AUDIO, mime_type, codecs) != - EmeConfigRule::NOT_SUPPORTED); + return (KeySystems::GetInstance() + ->GetContentTypeConfigRule(key_system, EmeMediaType::AUDIO, + mime_type, codecs) + .has_value()); } bool IsSupportedKeySystem(const std::string& key_system) { return KeySystems::GetInstance()->IsSupportedKeySystem(key_system); } -EmeConfigRule GetRobustnessConfigRule(const std::string& requested_robustness) { +absl::optional<EmeConfigRule> GetRobustnessConfigRule( + const std::string& requested_robustness) { return KeySystems::GetInstance()->GetRobustnessConfigRule( kExternal, EmeMediaType::VIDEO, requested_robustness, nullptr); } @@ -621,12 +632,14 @@ TEST_F(KeySystemsTest, IsSupportedKeySystem_UsesAesDecryptor_EncryptionSchemes) { + auto supported = EmeConfigRule(); + auto not_supported = absl::nullopt; ExpectEncryptionSchemeConfigRule(kUsesAes, EncryptionScheme::kUnencrypted, - EmeConfigRule::SUPPORTED); + supported); ExpectEncryptionSchemeConfigRule(kUsesAes, EncryptionScheme::kCenc, - EmeConfigRule::SUPPORTED); + supported); ExpectEncryptionSchemeConfigRule(kUsesAes, EncryptionScheme::kCbcs, - EmeConfigRule::NOT_SUPPORTED); + not_supported); } // @@ -743,12 +756,15 @@ TEST_F(KeySystemsTest, IsSupportedKeySystem_ExternalDecryptor_EncryptionSchemes) { + auto supported = EmeConfigRule(); + auto hw_secure_codecs_not_allowed = + EmeConfigRule{.hw_secure_codecs = EmeConfigRuleState::kNotAllowed}; ExpectEncryptionSchemeConfigRule(kExternal, EncryptionScheme::kUnencrypted, - EmeConfigRule::SUPPORTED); + supported); ExpectEncryptionSchemeConfigRule(kExternal, EncryptionScheme::kCenc, - EmeConfigRule::SUPPORTED); + supported); ExpectEncryptionSchemeConfigRule(kExternal, EncryptionScheme::kCbcs, - EmeConfigRule::HW_SECURE_CODECS_NOT_ALLOWED); + hw_secure_codecs_not_allowed); } TEST_F(KeySystemsTest, KeySystemNameForUMA) { @@ -788,31 +804,38 @@ } TEST_F(KeySystemsTest, GetContentTypeConfigRule) { - EXPECT_EQ(EmeConfigRule::SUPPORTED, - GetRobustnessConfigRule(kRobustnessSupported)); - EXPECT_EQ(EmeConfigRule::NOT_SUPPORTED, - GetRobustnessConfigRule(kRobustnessNotSupported)); - EXPECT_EQ(EmeConfigRule::HW_SECURE_CODECS_REQUIRED, - GetRobustnessConfigRule(kRobustnessSecureCodecsRequired)); + auto supported = EmeConfigRule(); + auto not_supported = absl::nullopt; + auto hw_secure_codecs_required = + EmeConfigRule{.hw_secure_codecs = EmeConfigRuleState::kRequired}; + EXPECT_EQ(supported, GetRobustnessConfigRule(kRobustnessSupported)); + EXPECT_EQ(not_supported, GetRobustnessConfigRule(kRobustnessNotSupported)); + EXPECT_TRUE(hw_secure_codecs_required == + GetRobustnessConfigRule(kRobustnessSecureCodecsRequired)); } TEST_F(KeySystemsTest, HardwareSecureCodecs) { - EXPECT_EQ(EmeConfigRule::HW_SECURE_CODECS_NOT_ALLOWED, + auto supported = EmeConfigRule(); + auto not_supported = absl::nullopt; + auto hw_secure_codecs_required = + EmeConfigRule{.hw_secure_codecs = EmeConfigRuleState::kRequired}; + auto hw_secure_codecs_not_allowed = + EmeConfigRule{.hw_secure_codecs = EmeConfigRuleState::kNotAllowed}; + + EXPECT_EQ(hw_secure_codecs_not_allowed, GetVideoContentTypeConfigRule(kVideoWebM, vp8_codec(), kUsesAes)); EXPECT_EQ( - EmeConfigRule::HW_SECURE_CODECS_NOT_ALLOWED, + hw_secure_codecs_not_allowed, GetVideoContentTypeConfigRule(kVideoFoo, foovideo_codec(), kUsesAes)); - EXPECT_EQ(EmeConfigRule::NOT_SUPPORTED, - GetVideoContentTypeConfigRule(kVideoFoo, securefoovideo_codec(), - kUsesAes)); + EXPECT_EQ(not_supported, GetVideoContentTypeConfigRule( + kVideoFoo, securefoovideo_codec(), kUsesAes)); - EXPECT_EQ(EmeConfigRule::HW_SECURE_CODECS_NOT_ALLOWED, + EXPECT_EQ(hw_secure_codecs_not_allowed, GetVideoContentTypeConfigRule(kVideoWebM, vp8_codec(), kExternal)); - EXPECT_EQ( - EmeConfigRule::SUPPORTED, - GetVideoContentTypeConfigRule(kVideoFoo, foovideo_codec(), kExternal)); + EXPECT_EQ(supported, GetVideoContentTypeConfigRule( + kVideoFoo, foovideo_codec(), kExternal)); - EXPECT_EQ(EmeConfigRule::HW_SECURE_CODECS_REQUIRED, + EXPECT_EQ(hw_secure_codecs_required, GetVideoContentTypeConfigRule(kVideoFoo, securefoovideo_codec(), kExternal)); }
diff --git a/media/cast/BUILD.gn b/media/cast/BUILD.gn index 02b5b2f2..7107ce8 100644 --- a/media/cast/BUILD.gn +++ b/media/cast/BUILD.gn
@@ -27,9 +27,9 @@ "common/encoded_frame.cc", "common/encoded_frame.h", "common/expanded_value_base.h", - "common/frame_id.cc", "common/frame_id.h", - "common/rtp_time.cc", + "common/openscreen_conversion_helpers.cc", + "common/openscreen_conversion_helpers.h", "common/rtp_time.h", "common/sender_encoded_frame.cc", "common/sender_encoded_frame.h", @@ -61,6 +61,7 @@ ":logging_proto", "//base", "//crypto", + "//media", "//net", "//third_party/zlib", ] @@ -69,6 +70,9 @@ # The generated headers reference headers within protobuf_lite, so # dependencies must be able to find those headers too. ":logging_proto", + "//components/openscreen_platform:openscreen_platform_network_service", + "//third_party/openscreen/src/cast/streaming:common", + "//third_party/openscreen/src/cast/streaming:sender", ] } @@ -200,6 +204,8 @@ "sender/frame_sender.h", "sender/frame_sender_impl.cc", "sender/frame_sender_impl.h", + "sender/openscreen_frame_sender.cc", + "sender/openscreen_frame_sender.h", "sender/performance_metrics_overlay.cc", "sender/performance_metrics_overlay.h", "sender/video_sender.cc", @@ -211,8 +217,10 @@ ":encoding", ":net", "//base", + "//components/openscreen_platform:openscreen_platform_network_service", "//media", "//media/capture:capture_base", + "//third_party/openscreen/src/cast/streaming:sender", "//ui/gfx/geometry", ] @@ -301,6 +309,7 @@ ] deps = [ + ":common", ":net", ":sender", ":test_receiver", @@ -330,7 +339,7 @@ sources = [ "common/expanded_value_base_unittest.cc", - "common/rtp_time_unittest.cc", + "common/openscreen_conversion_helpers_unittest.cc", "encoding/audio_encoder_unittest.cc", "encoding/external_video_encoder_unittest.cc", "encoding/video_encoder_unittest.cc", @@ -375,12 +384,14 @@ "//base", "//base:cfi_buildflags", "//base/test:test_support", + "//components/openscreen_platform:openscreen_platform_network_service", "//media:test_support", "//media/test:run_all_unittests", "//mojo/public/cpp/bindings", "//net", "//testing/gmock", "//testing/gtest", + "//third_party/openscreen/src/cast/streaming:sender", "//third_party/opus", ] @@ -499,6 +510,7 @@ "//base", "//build/win:default_exe_manifest", "//net", + "//third_party/openscreen/src/cast/streaming:common", ] } } else { # !(is_win || is_mac || is_linux || is_chromeos_lacros) @@ -512,6 +524,7 @@ sources = [ "test/utility/tap_proxy.cc" ] deps = [ + ":common", ":test_support", "//base", "//base/test:test_support",
diff --git a/media/cast/DEPS b/media/cast/DEPS index 3582fc3..d6ef61f 100644 --- a/media/cast/DEPS +++ b/media/cast/DEPS
@@ -5,6 +5,8 @@ "+net", "+third_party/libyuv", "+third_party/libaom", + "+third_party/openscreen/src/cast/streaming", + "+third_party/openscreen/src/platform/api", "+third_party/zlib", "+ui/base", "+ui/gfx",
diff --git a/media/cast/common/frame_id.cc b/media/cast/common/frame_id.cc deleted file mode 100644 index f6ddadc..0000000 --- a/media/cast/common/frame_id.cc +++ /dev/null
@@ -1,18 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "media/cast/common/frame_id.h" - -namespace media { -namespace cast { - -std::ostream& operator<<(std::ostream& out, const FrameId rhs) { - out << "F"; - if (rhs.is_null()) - return out << "<null>"; - return out << rhs.value(); -} - -} // namespace cast -} // namespace media
diff --git a/media/cast/common/frame_id.h b/media/cast/common/frame_id.h index 7a13513..398f3fab 100644 --- a/media/cast/common/frame_id.h +++ b/media/cast/common/frame_id.h
@@ -5,106 +5,14 @@ #ifndef MEDIA_CAST_COMMON_FRAME_ID_H_ #define MEDIA_CAST_COMMON_FRAME_ID_H_ -#include <stdint.h> +#include "third_party/openscreen/src/cast/streaming/frame_id.h" -#include <sstream> +namespace media::cast { -#include "media/cast/common/expanded_value_base.h" +// TODO(https://crbug.com/1343116): this typedef should be removed and +// the openscreen type used directly. +using FrameId = openscreen::cast::FrameId; -namespace media { -namespace cast { - -// Forward declaration (see below). -class FrameId; - -// Convenience operator overloads for logging. -std::ostream& operator<<(std::ostream& out, const FrameId rhs); - -// Unique identifier for a frame in a RTP media stream. FrameIds are truncated -// to 8-bit values in RTP and RTCP headers, and then expanded back by the other -// endpoint when parsing the headers. -// -// Usage example: -// -// // Distance/offset math. -// FrameId first = FrameId::first(); -// FrameId second = first + 1; -// FrameId third = second + 1; -// int64_t offset = third - first; -// FrameId fourth = second + offset; -// -// // Logging convenience. -// DLOG(INFO) << "The current frame is " << fourth; -class FrameId : public ExpandedValueBase<int64_t, FrameId> { - public: - // The "null" FrameId constructor. Represents a FrameId field that has not - // been set and/or a "not applicable" indicator. - FrameId() : FrameId(std::numeric_limits<int64_t>::min()) {} - - // Allow copy construction and assignment. - FrameId(const FrameId&) = default; - FrameId& operator=(const FrameId&) = default; - - // Returns true if this is the special value representing null. - bool is_null() const { return *this == FrameId(); } - - // Distance operator. - int64_t operator-(FrameId rhs) const { - DCHECK(!is_null()); - DCHECK(!rhs.is_null()); - return value_ - rhs.value_; - } - - // Operators to compute advancement by incremental amounts. - FrameId operator+(int64_t rhs) const { - DCHECK(!is_null()); - return FrameId(value_ + rhs); - } - FrameId operator-(int64_t rhs) const { - DCHECK(!is_null()); - return FrameId(value_ - rhs); - } - FrameId& operator+=(int64_t rhs) { - DCHECK(!is_null()); - return (*this = (*this + rhs)); - } - FrameId& operator-=(int64_t rhs) { - DCHECK(!is_null()); - return (*this = (*this - rhs)); - } - FrameId& operator++() { - DCHECK(!is_null()); - ++value_; - return *this; - } - FrameId& operator--() { - DCHECK(!is_null()); - --value_; - return *this; - } - FrameId operator++(int) { - DCHECK(!is_null()); - return FrameId(value_++); - } - FrameId operator--(int) { - DCHECK(!is_null()); - return FrameId(value_--); - } - - // The identifier for the first frame in a stream. - static FrameId first() { return FrameId(0); } - - private: - friend class ExpandedValueBase<int64_t, FrameId>; - friend std::ostream& operator<<(std::ostream& out, const FrameId rhs); - - explicit FrameId(int64_t value) : ExpandedValueBase(value) {} - - // Accessor used by ostream output function. - int64_t value() const { return value_; } -}; - -} // namespace cast -} // namespace media +} // namespace media::cast #endif // MEDIA_CAST_COMMON_FRAME_ID_H_
diff --git a/media/cast/common/openscreen_conversion_helpers.cc b/media/cast/common/openscreen_conversion_helpers.cc new file mode 100644 index 0000000..4c34f4b --- /dev/null +++ b/media/cast/common/openscreen_conversion_helpers.cc
@@ -0,0 +1,82 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "media/cast/common/openscreen_conversion_helpers.h" + +namespace media::cast { + +openscreen::Clock::time_point ToOpenscreenTimePoint(base::TimeTicks ticks) { + static_assert(sizeof(openscreen::Clock::time_point::rep) >= + sizeof(base::TimeTicks::Max())); + return openscreen::Clock::time_point( + std::chrono::microseconds(ticks.since_origin().InMicroseconds())); +} + +// Returns the tick count in the given timebase nearest to the base::TimeDelta. +int64_t TimeDeltaToTicks(base::TimeDelta delta, int timebase) { + DCHECK_GT(timebase, 0); + const double ticks = delta.InSecondsF() * timebase + 0.5 /* rounding */; + return base::checked_cast<int64_t>(ticks); +} + +openscreen::cast::RtpTimeTicks ToRtpTimeTicks(base::TimeDelta delta, + int timebase) { + return openscreen::cast::RtpTimeTicks(TimeDeltaToTicks(delta, timebase)); +} + +openscreen::cast::RtpTimeDelta ToRtpTimeDelta(base::TimeDelta delta, + int timebase) { + return openscreen::cast::RtpTimeDelta::FromTicks( + TimeDeltaToTicks(delta, timebase)); +} + +base::TimeDelta ToTimeDelta(openscreen::cast::RtpTimeDelta rtp_delta, + int timebase) { + DCHECK_GT(timebase, 0); + return base::Microseconds( + rtp_delta.ToDuration<std::chrono::microseconds>(timebase).count()); +} + +base::TimeDelta ToTimeDelta(openscreen::cast::RtpTimeTicks rtp_ticks, + int timebase) { + DCHECK_GT(timebase, 0); + return ToTimeDelta(rtp_ticks - openscreen::cast::RtpTimeTicks{}, timebase); +} + +base::TimeDelta ToTimeDelta(openscreen::Clock::duration tp) { + return base::Microseconds( + std::chrono::duration_cast<std::chrono::microseconds>(tp).count()); +} + +openscreen::cast::EncodedFrame::Dependency ToOpenscreenDependency( + media::cast::EncodedFrame::Dependency dependency) { + switch (dependency) { + case media::cast::EncodedFrame::Dependency::UNKNOWN_DEPENDENCY: + return openscreen::cast::EncodedFrame::Dependency::UNKNOWN_DEPENDENCY; + case media::cast::EncodedFrame::Dependency::DEPENDENT: + return openscreen::cast::EncodedFrame::Dependency::DEPENDS_ON_ANOTHER; + case media::cast::EncodedFrame::Dependency::INDEPENDENT: + return openscreen::cast::EncodedFrame::Dependency:: + INDEPENDENTLY_DECODABLE; + case media::cast::EncodedFrame::Dependency::KEY: + return openscreen::cast::EncodedFrame::Dependency::KEY_FRAME; + default: + NOTREACHED(); + break; + } +} +const openscreen::cast::EncodedFrame ToOpenscreenEncodedFrame( + const SenderEncodedFrame& encoded_frame) { + return openscreen::cast::EncodedFrame( + ToOpenscreenDependency(encoded_frame.dependency), encoded_frame.frame_id, + encoded_frame.referenced_frame_id, encoded_frame.rtp_timestamp, + ToOpenscreenTimePoint(encoded_frame.reference_time), + std::chrono::milliseconds(encoded_frame.new_playout_delay_ms), + // We return a const EncodedFrame, so this is safe even though weird. + absl::Span<uint8_t>(const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>( + encoded_frame.data.data())), + encoded_frame.data.size())); +} + +} // namespace media::cast
diff --git a/media/cast/common/openscreen_conversion_helpers.h b/media/cast/common/openscreen_conversion_helpers.h new file mode 100644 index 0000000..3eb3475 --- /dev/null +++ b/media/cast/common/openscreen_conversion_helpers.h
@@ -0,0 +1,42 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MEDIA_CAST_COMMON_OPENSCREEN_CONVERSION_HELPERS_H_ +#define MEDIA_CAST_COMMON_OPENSCREEN_CONVERSION_HELPERS_H_ + +#include "media/cast/common/sender_encoded_frame.h" +#include "third_party/openscreen/src/cast/streaming/rtp_time.h" +#include "third_party/openscreen/src/cast/streaming/sender.h" +#include "third_party/openscreen/src/platform/api/time.h" + +// Conversion methods for common Open Screen media cast types. Note that many +// of these types are nearly identical in implementation. +namespace media::cast { + +openscreen::Clock::time_point ToOpenscreenTimePoint(base::TimeTicks ticks); + +openscreen::cast::RtpTimeTicks ToRtpTimeTicks(base::TimeDelta delta, + int timebase); + +openscreen::cast::RtpTimeDelta ToRtpTimeDelta(base::TimeDelta delta, + int timebase); + +base::TimeDelta ToTimeDelta(openscreen::cast::RtpTimeDelta rtp_delta, + int timebase); +base::TimeDelta ToTimeDelta(openscreen::cast::RtpTimeTicks rtp_ticks, + int timebase); +base::TimeDelta ToTimeDelta(openscreen::Clock::duration tp); + +// TODO(https://crbug.com/1343116): as part of libcast implementation, we +// should remove media::cast::EncodedFrame::Dependency in favor of using +// the openscreen type throughout. +openscreen::cast::EncodedFrame::Dependency ToOpenscreenDependency( + media::cast::EncodedFrame::Dependency dependency); + +const openscreen::cast::EncodedFrame ToOpenscreenEncodedFrame( + const SenderEncodedFrame& encoded_frame); + +} // namespace media::cast + +#endif // MEDIA_CAST_COMMON_OPENSCREEN_CONVERSION_HELPERS_H_
diff --git a/media/cast/common/openscreen_conversion_helpers_unittest.cc b/media/cast/common/openscreen_conversion_helpers_unittest.cc new file mode 100644 index 0000000..fe61ca7c --- /dev/null +++ b/media/cast/common/openscreen_conversion_helpers_unittest.cc
@@ -0,0 +1,53 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "media/cast/common/openscreen_conversion_helpers.h" + +#include "media/cast/cast_config.h" +#include "media/cast/cast_sender.h" +#include "media/cast/common/sender_encoded_frame.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/openscreen/src/cast/streaming/encoded_frame.h" +#include "third_party/openscreen/src/cast/streaming/rtp_time.h" +#include "third_party/openscreen/src/cast/streaming/sender.h" +#include "third_party/openscreen/src/platform/api/time.h" + +namespace media::cast { + +TEST(OpenscreenConversionHelpersTest, EncodedFrameConversions) { + SenderEncodedFrame original; + original.encoder_utilization = 0.6f; + original.encoder_bitrate = 12345; + original.lossiness = 0.5f; + original.encode_completion_time = + base::TimeTicks() + base::Milliseconds(1337); + original.dependency = EncodedFrame::Dependency::INDEPENDENT; + original.frame_id = FrameId::first(); + original.rtp_timestamp = ToRtpTimeTicks(base::Seconds(3), 9000); + original.reference_time = base::TimeTicks() + base::Milliseconds(1338); + original.new_playout_delay_ms = 564; + original.data = "i am actually a very complex video image!"; + + const openscreen::cast::EncodedFrame converted = + ToOpenscreenEncodedFrame(original); + EXPECT_EQ(openscreen::cast::EncodedFrame::Dependency::INDEPENDENTLY_DECODABLE, + converted.dependency); + EXPECT_EQ(openscreen::cast::FrameId(0), converted.frame_id); + EXPECT_EQ(openscreen::cast::RtpTimeTicks(27000), converted.rtp_timestamp); + EXPECT_EQ(openscreen::Clock::time_point() + std::chrono::milliseconds(1338), + converted.reference_time); + EXPECT_EQ(std::chrono::milliseconds(564), converted.new_playout_delay); + EXPECT_STREQ(reinterpret_cast<char*>(converted.data.data()), + original.data.data()); +} + +TEST(OpenscreenConversionHelpersTest, TimeConversions) { + EXPECT_EQ(openscreen::Clock::time_point() + std::chrono::milliseconds(42), + ToOpenscreenTimePoint(base::TimeTicks() + base::Milliseconds(42))); + + EXPECT_EQ(base::Milliseconds(300), + ToTimeDelta(std::chrono::milliseconds(300))); +} + +} // namespace media::cast
diff --git a/media/cast/common/rtp_time.cc b/media/cast/common/rtp_time.cc deleted file mode 100644 index 28fc3a0..0000000 --- a/media/cast/common/rtp_time.cc +++ /dev/null
@@ -1,74 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "media/cast/common/rtp_time.h" - -#include <limits> -#include <sstream> - -namespace media { -namespace cast { - -namespace { - -// Returns the base::TimeDelta nearest to the time represented by a tick count -// in the given timebase. -base::TimeDelta TicksToTimeDelta(int64_t ticks, int timebase) { - DCHECK_GT(timebase, 0); - const double micros = static_cast<double>(ticks) / timebase * - base::Time::kMicrosecondsPerSecond + - 0.5 /* rounding */; - DCHECK_LT(micros, static_cast<double>(std::numeric_limits<int64_t>::max())); - return base::Microseconds(static_cast<int64_t>(micros)); -} - -// Returns the tick count in the given timebase nearest to the base::TimeDelta. -int64_t TimeDeltaToTicks(base::TimeDelta delta, int timebase) { - DCHECK_GT(timebase, 0); - const double ticks = delta.InSecondsF() * timebase + 0.5 /* rounding */; - DCHECK_LT(ticks, static_cast<double>(std::numeric_limits<int64_t>::max())); - return static_cast<int64_t>(ticks); -} - -} // namespace - -std::ostream& operator<<(std::ostream& out, const RtpTimeDelta rhs) { - if (rhs.value_ >= 0) - out << "RTP+"; - else - out << "RTP"; - return out << rhs.value_; -} - -std::ostream& operator<<(std::ostream& out, const RtpTimeTicks rhs) { - return out << "RTP@" << rhs.value_; -} - -base::TimeDelta RtpTimeDelta::ToTimeDelta(int rtp_timebase) const { - return TicksToTimeDelta(value_, rtp_timebase); -} - -// static -RtpTimeDelta RtpTimeDelta::FromTimeDelta(base::TimeDelta delta, - int rtp_timebase) { - return RtpTimeDelta(TimeDeltaToTicks(delta, rtp_timebase)); -} - -// static -RtpTimeDelta RtpTimeDelta::FromTicks(int64_t ticks) { - return RtpTimeDelta(ticks); -} - -base::TimeDelta RtpTimeTicks::ToTimeDelta(int rtp_timebase) const { - return TicksToTimeDelta(value_, rtp_timebase); -} - -// static -RtpTimeTicks RtpTimeTicks::FromTimeDelta(base::TimeDelta delta, - int rtp_timebase) { - return RtpTimeTicks(TimeDeltaToTicks(delta, rtp_timebase)); -} - -} // namespace cast -} // namespace media
diff --git a/media/cast/common/rtp_time.h b/media/cast/common/rtp_time.h index 79e625b..88beee8d 100644 --- a/media/cast/common/rtp_time.h +++ b/media/cast/common/rtp_time.h
@@ -5,193 +5,15 @@ #ifndef MEDIA_CAST_COMMON_RTP_TIME_H_ #define MEDIA_CAST_COMMON_RTP_TIME_H_ -#include <stdint.h> +#include "third_party/openscreen/src/cast/streaming/rtp_time.h" -#include <limits> -#include <sstream> +namespace media::cast { -#include "base/time/time.h" -#include "media/cast/common/expanded_value_base.h" +// TODO(https://crbug.com/1343116): this typedef should be removed and +// the openscreen type used directly. +using RtpTimeDelta = openscreen::cast::RtpTimeDelta; +using RtpTimeTicks = openscreen::cast::RtpTimeTicks; -namespace media { -namespace cast { - -// Forward declarations (see below). -class RtpTimeDelta; -class RtpTimeTicks; - -// Convenience operator overloads for logging. -std::ostream& operator<<(std::ostream& out, const RtpTimeDelta rhs); -std::ostream& operator<<(std::ostream& out, const RtpTimeTicks rhs); - -// The difference between two RtpTimeTicks values. This data type is modeled -// off of base::TimeDelta, and used for performing compiler-checked arithmetic -// with RtpTimeTicks. -// -// This data type wraps a value, providing only the meaningful set of math -// operations that may be performed on the value. RtpTimeDeltas may be -// added/subtracted with other RtpTimeDeltas to produce a RtpTimeDelta holding -// the sum/difference. RtpTimeDeltas may also be multiplied or divided by -// integer amounts. Finally, RtpTimeDeltas may be divided by other -// RtpTimeDeltas to compute a number of periods (floor'ed to an integer), or -// modulo each other to determine a time period remainder. -// -// The base class provides bit truncation/extension features for -// wire-formatting, and also the comparison operators. -// -// Usage example: -// -// // Time math. -// RtpTimeDelta zero; -// RtpTimeDelta one_second_later = -// zero + RtpTimeDelta::FromTicks(kAudioSamplingRate); -// RtpTimeDelta ten_seconds_later = one_second_later * 10; -// int64_t ten_periods = ten_seconds_later / one_second_later; -// -// // Logging convenience. -// DLOG(INFO) << "The RTP time offset is " << ten_seconds_later; -// -// // Convert (approximately!) between RTP timebase and microsecond timebase: -// base::TimeDelta nine_seconds_offset = -// (ten_seconds_later - one_second_later).ToTimeDelta(kAudioSamplingRate); -// RtpTimeDelta nine_seconds_rtp = -// RtpTimeDelta::FromTimeDelta(nine_seconds_offset, kAudioSamplingRate); -class RtpTimeDelta : public ExpandedValueBase<int64_t, RtpTimeDelta> { - public: - RtpTimeDelta() : ExpandedValueBase(0) {} - - // Arithmetic operators (with other deltas). - RtpTimeDelta operator+(RtpTimeDelta rhs) const { - return RtpTimeDelta(value_ + rhs.value_); - } - RtpTimeDelta operator-(RtpTimeDelta rhs) const { - return RtpTimeDelta(value_ - rhs.value_); - } - RtpTimeDelta& operator+=(RtpTimeDelta rhs) { return (*this = (*this + rhs)); } - RtpTimeDelta& operator-=(RtpTimeDelta rhs) { return (*this = (*this - rhs)); } - RtpTimeDelta operator-() const { return RtpTimeDelta(-value_); } - - // Multiplicative operators (with other deltas). - int64_t operator/(RtpTimeDelta rhs) const { return value_ / rhs.value_; } - RtpTimeDelta operator%(RtpTimeDelta rhs) const { - return RtpTimeDelta(value_ % rhs.value_); - } - RtpTimeDelta& operator%=(RtpTimeDelta rhs) { return (*this = (*this % rhs)); } - - // Multiplicative operators (with integer types). - template <typename IntType> - RtpTimeDelta operator*(IntType rhs) const { - static_assert(std::numeric_limits<IntType>::is_integer, - "|rhs| must be a POD integer type"); - return RtpTimeDelta(value_ * rhs); - } - template <typename IntType> - RtpTimeDelta operator/(IntType rhs) const { - static_assert(std::numeric_limits<IntType>::is_integer, - "|rhs| must be a POD integer type"); - return RtpTimeDelta(value_ / rhs); - } - template <typename IntType> - RtpTimeDelta& operator*=(IntType rhs) { return (*this = (*this * rhs)); } - template <typename IntType> - RtpTimeDelta& operator/=(IntType rhs) { return (*this = (*this / rhs)); } - - // Maps this RtpTimeDelta to an approximate TimeDelta using the given - // RTP timebase. Assumes a zero-valued TimeDelta corresponds to a zero-valued - // RtpTimeDelta. - base::TimeDelta ToTimeDelta(int rtp_timebase) const; - - // Maps the TimeDelta to an approximate RtpTimeDelta using the given RTP - // timebase. Assumes a zero-valued TimeDelta corresponds to a zero-valued - // RtpTimeDelta. - static RtpTimeDelta FromTimeDelta(base::TimeDelta delta, int rtp_timebase); - - // Construct a RtpTimeDelta from an exact number of ticks. - static RtpTimeDelta FromTicks(int64_t ticks); - - private: - friend class ExpandedValueBase<int64_t, RtpTimeDelta>; - friend class RtpTimeTicks; - friend std::ostream& operator<<(std::ostream& out, const RtpTimeDelta rhs); - - explicit RtpTimeDelta(int64_t ticks) : ExpandedValueBase(ticks) {} - - int64_t value() const { return value_; } -}; - -// A media timestamp whose timebase matches the periodicity of the content -// (e.g., for audio, the timebase would be the sampling frequency). This data -// type is modeled off of base::TimeTicks. -// -// This data type wraps a value, providing only the meaningful set of math -// operations that may be performed on the value. The difference between two -// RtpTimeTicks is a RtpTimeDelta. Likewise, adding or subtracting a -// RtpTimeTicks with a RtpTimeDelta produces an off-set RtpTimeTicks. -// -// The base class provides bit truncation/extension features for -// wire-formatting, and also the comparison operators. -// -// Usage example: -// -// // Time math. -// RtpTimeTicks origin; -// RtpTimeTicks at_one_second = -// origin + RtpTimeDelta::FromTicks(kAudioSamplingRate); -// RtpTimeTicks at_two_seconds = -// at_one_second + RtpTimeDelta::FromTicks(kAudioSamplingRate); -// RtpTimeDelta elasped_in_between = at_two_seconds - at_one_second; -// RtpTimeDelta thrice_as_much_elasped = elasped_in_between * 3; -// RtpTimeTicks at_four_seconds = at_one_second + thrice_as_much_elasped; -// -// // Logging convenience. -// DLOG(INFO) << "The RTP timestamp is " << at_four_seconds; -// -// // Convert (approximately!) between RTP timebase and media timestamps in -// // microsecond timebase: -// base::TimeDelta four_seconds_timestamp = -// at_four_seconds.ToTimeDelta(kAudioSamplingRate); -// video_frame->set_timestamp(four_seconds_timestamp); -// RtpTimeTicks four_seconds_rtp = RtpTimeDelta::FromTimeDelta( -// video_frame->timestamp(), kAudioSamplingRate); -class RtpTimeTicks : public ExpandedValueBase<int64_t, RtpTimeTicks> { - public: - RtpTimeTicks() : ExpandedValueBase(0) {} - - // Compute the difference between two RtpTimeTickses. - RtpTimeDelta operator-(RtpTimeTicks rhs) const { - return RtpTimeDelta(value_ - rhs.value_); - } - - // Return a new RtpTimeTicks before or after this one. - RtpTimeTicks operator+(RtpTimeDelta rhs) const { - return RtpTimeTicks(value_ + rhs.value()); - } - RtpTimeTicks operator-(RtpTimeDelta rhs) const { - return RtpTimeTicks(value_ - rhs.value()); - } - RtpTimeTicks& operator+=(RtpTimeDelta rhs) { return (*this = (*this + rhs)); } - RtpTimeTicks& operator-=(RtpTimeDelta rhs) { return (*this = (*this - rhs)); } - - // Maps this RtpTimeTicks to an approximate TimeDelta using the given - // RTP timebase. Assumes a zero-valued TimeDelta corresponds to a zero-valued - // RtpTimeTicks. - base::TimeDelta ToTimeDelta(int rtp_timebase) const; - - // Maps the TimeDelta to an approximate RtpTimeTicks using the given RTP - // timebase. Assumes a zero-valued TimeDelta corresponds to a zero-valued - // RtpTimeTicks. - static RtpTimeTicks FromTimeDelta(base::TimeDelta delta, int rtp_timebase); - - private: - friend class ExpandedValueBase<int64_t, RtpTimeTicks>; - friend std::ostream& operator<<(std::ostream& out, const RtpTimeTicks rhs); - - explicit RtpTimeTicks(int64_t value) : ExpandedValueBase(value) {} - - int64_t value() const { return value_; } -}; - -} // namespace cast -} // namespace media +} // namespace media::cast #endif // MEDIA_CAST_COMMON_RTP_TIME_H_
diff --git a/media/cast/common/rtp_time_unittest.cc b/media/cast/common/rtp_time_unittest.cc deleted file mode 100644 index 3841215..0000000 --- a/media/cast/common/rtp_time_unittest.cc +++ /dev/null
@@ -1,69 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "media/cast/common/rtp_time.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace media { -namespace cast { - -// Tests that conversions between base::TimeDelta and RtpTimeDelta are accurate. -// Note that this implicitly tests the conversions to/from RtpTimeTicks as well -// due to shared implementation. -TEST(RtpTimeDeltaTest, ConversionToAndFromTimeDelta) { - const int kTimebase = 48000; - - // Origin in both timelines is equivalent. - ASSERT_EQ(RtpTimeDelta(), RtpTimeDelta::FromTicks(0)); - ASSERT_EQ(RtpTimeDelta(), - RtpTimeDelta::FromTimeDelta(base::TimeDelta(), kTimebase)); - ASSERT_EQ(base::TimeDelta(), - RtpTimeDelta::FromTicks(0).ToTimeDelta(kTimebase)); - - // Conversions that are exact (i.e., do not require rounding). - ASSERT_EQ(RtpTimeDelta::FromTicks(480), - RtpTimeDelta::FromTimeDelta(base::Milliseconds(10), kTimebase)); - ASSERT_EQ(RtpTimeDelta::FromTicks(96000), - RtpTimeDelta::FromTimeDelta(base::Seconds(2), kTimebase)); - ASSERT_EQ(base::Milliseconds(10), - RtpTimeDelta::FromTicks(480).ToTimeDelta(kTimebase)); - ASSERT_EQ(base::Seconds(2), - RtpTimeDelta::FromTicks(96000).ToTimeDelta(kTimebase)); - - // Conversions that are approximate (i.e., are rounded). - for (int error_us = -3; error_us <= +3; ++error_us) { - ASSERT_EQ(RtpTimeDelta::FromTicks(0), - RtpTimeDelta::FromTimeDelta(base::Microseconds(0 + error_us), - kTimebase)); - ASSERT_EQ(RtpTimeDelta::FromTicks(1), - RtpTimeDelta::FromTimeDelta(base::Microseconds(21 + error_us), - kTimebase)); - ASSERT_EQ(RtpTimeDelta::FromTicks(2), - RtpTimeDelta::FromTimeDelta(base::Microseconds(42 + error_us), - kTimebase)); - ASSERT_EQ(RtpTimeDelta::FromTicks(3), - RtpTimeDelta::FromTimeDelta(base::Microseconds(63 + error_us), - kTimebase)); - ASSERT_EQ(RtpTimeDelta::FromTicks(4), - RtpTimeDelta::FromTimeDelta(base::Microseconds(83 + error_us), - kTimebase)); - ASSERT_EQ(RtpTimeDelta::FromTicks(11200000000000), - RtpTimeDelta::FromTimeDelta( - base::Microseconds(INT64_C(233333333333333) + error_us), - kTimebase)); - } - ASSERT_EQ(base::Microseconds(21), - RtpTimeDelta::FromTicks(1).ToTimeDelta(kTimebase)); - ASSERT_EQ(base::Microseconds(42), - RtpTimeDelta::FromTicks(2).ToTimeDelta(kTimebase)); - ASSERT_EQ(base::Microseconds(63), - RtpTimeDelta::FromTicks(3).ToTimeDelta(kTimebase)); - ASSERT_EQ(base::Microseconds(83), - RtpTimeDelta::FromTicks(4).ToTimeDelta(kTimebase)); - ASSERT_EQ(base::Microseconds(INT64_C(233333333333333)), - RtpTimeDelta::FromTicks(11200000000000).ToTimeDelta(kTimebase)); -} - -} // namespace cast -} // namespace media
diff --git a/media/cast/encoding/av1_encoder.cc b/media/cast/encoding/av1_encoder.cc index 2d80c5c..0ce764c3 100644 --- a/media/cast/encoding/av1_encoder.cc +++ b/media/cast/encoding/av1_encoder.cc
@@ -6,6 +6,7 @@ #include "base/logging.h" #include "media/base/video_frame.h" +#include "media/cast/common/openscreen_conversion_helpers.h" #include "media/cast/common/sender_encoded_frame.h" #include "media/cast/constants.h" #include "third_party/libaom/source/libaom/aom/aomcx.h" @@ -254,7 +255,7 @@ encoded_frame->referenced_frame_id = encoded_frame->frame_id - 1; } encoded_frame->rtp_timestamp = - RtpTimeTicks::FromTimeDelta(video_frame->timestamp(), kVideoFrequency); + ToRtpTimeTicks(video_frame->timestamp(), kVideoFrequency); encoded_frame->reference_time = reference_time; encoded_frame->data.assign( static_cast<const uint8_t*>(pkt->data.frame.buf),
diff --git a/media/cast/encoding/external_video_encoder.cc b/media/cast/encoding/external_video_encoder.cc index 8feef5ab..4440185 100644 --- a/media/cast/encoding/external_video_encoder.cc +++ b/media/cast/encoding/external_video_encoder.cc
@@ -37,6 +37,7 @@ #include "media/base/video_util.h" #include "media/cast/cast_config.h" #include "media/cast/common/encoded_frame.h" +#include "media/cast/common/openscreen_conversion_helpers.h" #include "media/cast/common/rtp_time.h" #include "media/cast/common/sender_encoded_frame.h" #include "media/cast/encoding/vpx_quantizer_parser.h" @@ -426,8 +427,8 @@ } else { encoded_frame->referenced_frame_id = encoded_frame->frame_id - 1; } - encoded_frame->rtp_timestamp = RtpTimeTicks::FromTimeDelta( - request.video_frame->timestamp(), kVideoFrequency); + encoded_frame->rtp_timestamp = + ToRtpTimeTicks(request.video_frame->timestamp(), kVideoFrequency); encoded_frame->reference_time = request.reference_time; std::string header = stream_header_.str();
diff --git a/media/cast/encoding/fake_software_video_encoder.cc b/media/cast/encoding/fake_software_video_encoder.cc index b300e96..ef7219e 100644 --- a/media/cast/encoding/fake_software_video_encoder.cc +++ b/media/cast/encoding/fake_software_video_encoder.cc
@@ -11,6 +11,7 @@ #include "media/base/video_frame.h" #include "media/cast/common/encoded_frame.h" #include "media/cast/common/frame_id.h" +#include "media/cast/common/openscreen_conversion_helpers.h" #include "media/cast/common/rtp_time.h" #include "media/cast/common/sender_encoded_frame.h" #include "media/cast/constants.h" @@ -52,7 +53,7 @@ encoded_frame->referenced_frame_id = encoded_frame->frame_id - 1; } encoded_frame->rtp_timestamp = - RtpTimeTicks::FromTimeDelta(video_frame->timestamp(), kVideoFrequency); + ToRtpTimeTicks(video_frame->timestamp(), kVideoFrequency); encoded_frame->reference_time = reference_time; base::Value values(base::Value::Type::DICTIONARY);
diff --git a/media/cast/encoding/h264_vt_encoder.cc b/media/cast/encoding/h264_vt_encoder.cc index 67177fc..3e7b84f1 100644 --- a/media/cast/encoding/h264_vt_encoder.cc +++ b/media/cast/encoding/h264_vt_encoder.cc
@@ -21,6 +21,7 @@ #include "base/time/time.h" #include "build/build_config.h" #include "media/base/mac/video_frame_mac.h" +#include "media/cast/common/openscreen_conversion_helpers.h" #include "media/cast/common/rtp_time.h" #include "media/cast/common/sender_encoded_frame.h" #include "media/cast/common/video_frame_factory.h" @@ -390,8 +391,7 @@ // We'll get the pointer back from the VideoToolbox completion callback. std::unique_ptr<InProgressH264VTFrameEncode> request( new InProgressH264VTFrameEncode( - RtpTimeTicks::FromTimeDelta(video_frame->timestamp(), - kVideoFrequency), + ToRtpTimeTicks(video_frame->timestamp(), kVideoFrequency), reference_time, std::move(frame_encoded_callback))); // Build a suitable frame properties dictionary for keyframes.
diff --git a/media/cast/encoding/h264_vt_encoder_unittest.cc b/media/cast/encoding/h264_vt_encoder_unittest.cc index e9cc165..f7b42b59 100644 --- a/media/cast/encoding/h264_vt_encoder_unittest.cc +++ b/media/cast/encoding/h264_vt_encoder_unittest.cc
@@ -22,6 +22,7 @@ #include "media/base/media.h" #include "media/base/media_switches.h" #include "media/base/media_util.h" +#include "media/cast/common/openscreen_conversion_helpers.h" #include "media/cast/common/rtp_time.h" #include "media/cast/common/sender_encoded_frame.h" #include "media/cast/common/video_frame_factory.h" @@ -277,8 +278,7 @@ auto metadata_recorder = base::MakeRefCounted<MetadataRecorder>(); metadata_recorder->PushExpectation( FrameId::first(), FrameId::first(), - RtpTimeTicks::FromTimeDelta(frame_->timestamp(), kVideoFrequency), - clock_.NowTicks()); + ToRtpTimeTicks(frame_->timestamp(), kVideoFrequency), clock_.NowTicks()); EXPECT_TRUE(encoder_->EncodeVideoFrame( frame_, clock_.NowTicks(), base::BindOnce(&MetadataRecorder::CompareFrameWithExpected, @@ -290,7 +290,7 @@ AdvanceClockAndVideoFrameTimestamp(); metadata_recorder->PushExpectation( frame_id, frame_id - 1, - RtpTimeTicks::FromTimeDelta(frame_->timestamp(), kVideoFrequency), + ToRtpTimeTicks(frame_->timestamp(), kVideoFrequency), clock_.NowTicks()); EXPECT_TRUE(encoder_->EncodeVideoFrame( frame_, clock_.NowTicks(),
diff --git a/media/cast/encoding/video_encoder_unittest.cc b/media/cast/encoding/video_encoder_unittest.cc index d30944d4..41e68133 100644 --- a/media/cast/encoding/video_encoder_unittest.cc +++ b/media/cast/encoding/video_encoder_unittest.cc
@@ -21,6 +21,7 @@ #include "media/base/fake_single_thread_task_runner.h" #include "media/base/video_frame.h" #include "media/cast/cast_environment.h" +#include "media/cast/common/openscreen_conversion_helpers.h" #include "media/cast/common/rtp_time.h" #include "media/cast/common/sender_encoded_frame.h" #include "media/cast/common/video_frame_factory.h" @@ -265,8 +266,7 @@ encoded_frames->emplace_back(std::move(encoded_frame)); }, encoded_frames_weak_factory.GetWeakPtr(), - RtpTimeTicks::FromTimeDelta(timestamp, kVideoFrequency), - reference_time)); + ToRtpTimeTicks(timestamp, kVideoFrequency), reference_time)); if (accepted_request) { ++count_frames_accepted; }
diff --git a/media/cast/encoding/vpx_encoder.cc b/media/cast/encoding/vpx_encoder.cc index a03015c..0ad738f 100644 --- a/media/cast/encoding/vpx_encoder.cc +++ b/media/cast/encoding/vpx_encoder.cc
@@ -6,6 +6,7 @@ #include "base/logging.h" #include "media/base/video_frame.h" +#include "media/cast/common/openscreen_conversion_helpers.h" #include "media/cast/common/sender_encoded_frame.h" #include "media/cast/constants.h" #include "third_party/libvpx/source/libvpx/vpx/vp8cx.h" @@ -294,7 +295,7 @@ encoded_frame->referenced_frame_id = encoded_frame->frame_id - 1; } encoded_frame->rtp_timestamp = - RtpTimeTicks::FromTimeDelta(video_frame->timestamp(), kVideoFrequency); + ToRtpTimeTicks(video_frame->timestamp(), kVideoFrequency); encoded_frame->reference_time = reference_time; encoded_frame->data.assign( static_cast<const uint8_t*>(pkt->data.frame.buf),
diff --git a/media/cast/sender/audio_sender.cc b/media/cast/sender/audio_sender.cc index 27bea44..284cad5 100644 --- a/media/cast/sender/audio_sender.cc +++ b/media/cast/sender/audio_sender.cc
@@ -9,10 +9,14 @@ #include "base/bind.h" #include "base/check_op.h" #include "base/notreached.h" +#include "media/base/media_switches.h" +#include "media/cast/common/openscreen_conversion_helpers.h" #include "media/cast/common/rtp_time.h" #include "media/cast/common/sender_encoded_frame.h" #include "media/cast/encoding/audio_encoder.h" #include "media/cast/net/cast_transport_config.h" +#include "media/cast/sender/openscreen_frame_sender.h" +#include "third_party/openscreen/src/cast/streaming/sender.h" namespace media::cast { @@ -20,12 +24,33 @@ const FrameSenderConfig& audio_config, StatusChangeOnceCallback status_change_cb, CastTransport* const transport_sender) + : AudioSender(cast_environment, + audio_config, + std::move(status_change_cb), + FrameSender::Create(cast_environment, + audio_config, + transport_sender, + *this)) {} + +AudioSender::AudioSender(scoped_refptr<CastEnvironment> cast_environment, + const FrameSenderConfig& audio_config, + StatusChangeOnceCallback status_change_cb, + openscreen::cast::Sender* sender) + : AudioSender( + cast_environment, + audio_config, + std::move(status_change_cb), + FrameSender::Create(cast_environment, audio_config, sender, *this)) { + DCHECK(base::FeatureList::IsEnabled(kOpenscreenCastStreamingSession)); +} + +AudioSender::AudioSender(scoped_refptr<CastEnvironment> cast_environment, + const FrameSenderConfig& audio_config, + StatusChangeOnceCallback status_change_cb, + std::unique_ptr<FrameSender> sender) : cast_environment_(cast_environment), rtp_timebase_(audio_config.rtp_timebase), - frame_sender_(FrameSender::Create(cast_environment, - audio_config, - transport_sender, - this)) { + frame_sender_(std::move(sender)) { if (!audio_config.use_external_encoder) { audio_encoder_ = std::make_unique<AudioEncoder>( std::move(cast_environment), audio_config.channels, rtp_timebase_, @@ -61,7 +86,7 @@ } const base::TimeDelta next_frame_duration = - RtpTimeDelta::FromTicks(audio_bus->frames()).ToTimeDelta(rtp_timebase_); + ToTimeDelta(RtpTimeDelta::FromTicks(audio_bus->frames()), rtp_timebase_); if (frame_sender_->ShouldDropNextFrame(next_frame_duration)) return; @@ -90,8 +115,8 @@ } base::TimeDelta AudioSender::GetEncoderBacklogDuration() const { - return RtpTimeDelta::FromTicks(samples_in_encoder_) - .ToTimeDelta(rtp_timebase_); + return ToTimeDelta(RtpTimeDelta::FromTicks(samples_in_encoder_), + rtp_timebase_); } void AudioSender::OnEncodedAudioFrame(
diff --git a/media/cast/sender/audio_sender.h b/media/cast/sender/audio_sender.h index e3f3fd4b..90147a5 100644 --- a/media/cast/sender/audio_sender.h +++ b/media/cast/sender/audio_sender.h
@@ -17,6 +17,10 @@ #include "media/cast/cast_sender.h" #include "media/cast/sender/frame_sender.h" +namespace openscreen::cast { +class Sender; +} + namespace media::cast { class AudioEncoder; @@ -29,11 +33,22 @@ // timeouts. class AudioSender final : public FrameSender::Client { public: + // Old way to instantiate, using a cast transport. + // TODO(https://crbug.com/1316434): should be removed once libcast sender is + // successfully launched. AudioSender(scoped_refptr<CastEnvironment> cast_environment, const FrameSenderConfig& audio_config, StatusChangeOnceCallback status_change_cb, CastTransport* const transport_sender); + // New way of instantiating using an openscreen::cast::Sender. Since the + // |Sender| instance is destroyed when renegotiation is complete, |this| + // is also invalid and should be immediately torn down. + AudioSender(scoped_refptr<CastEnvironment> cast_environment, + const FrameSenderConfig& audio_config, + StatusChangeOnceCallback status_change_cb, + openscreen::cast::Sender* sender); + AudioSender(const AudioSender&) = delete; AudioSender& operator=(const AudioSender&) = delete; @@ -56,6 +71,11 @@ base::TimeDelta GetEncoderBacklogDuration() const final; private: + AudioSender(scoped_refptr<CastEnvironment> cast_environment, + const FrameSenderConfig& audio_config, + StatusChangeOnceCallback status_change_cb, + std::unique_ptr<FrameSender> sender); + // Called by the |audio_encoder_| with the next EncodedFrame to send. void OnEncodedAudioFrame(std::unique_ptr<SenderEncodedFrame> encoded_frame, int samples_skipped);
diff --git a/media/cast/sender/congestion_control.cc b/media/cast/sender/congestion_control.cc index 3e854ab..49d8de3 100644 --- a/media/cast/sender/congestion_control.cc +++ b/media/cast/sender/congestion_control.cc
@@ -44,9 +44,9 @@ // CongestionControl implementation. void UpdateRtt(base::TimeDelta rtt) final; void UpdateTargetPlayoutDelay(base::TimeDelta delay) final; - void SendFrameToTransport(FrameId frame_id, - size_t frame_size_in_bits, - base::TimeTicks when) final; + void WillSendFrameToTransport(FrameId frame_id, + size_t frame_size_in_bytes, + base::TimeTicks when) final; void AckFrame(FrameId frame_id, base::TimeTicks when) final; void AckLaterFrames(std::vector<FrameId> received_frames, base::TimeTicks when) final; @@ -118,9 +118,9 @@ // CongestionControl implementation. void UpdateRtt(base::TimeDelta rtt) final {} void UpdateTargetPlayoutDelay(base::TimeDelta delay) final {} - void SendFrameToTransport(FrameId frame_id, - size_t frame_size_in_bits, - base::TimeTicks when) final {} + void WillSendFrameToTransport(FrameId frame_id, + size_t frame_size_in_bytes, + base::TimeTicks when) final {} void AckFrame(FrameId frame_id, base::TimeTicks when) final {} void AckLaterFrames(std::vector<FrameId> received_frames, base::TimeTicks when) final {} @@ -319,14 +319,15 @@ } } -void AdaptiveCongestionControl::SendFrameToTransport(FrameId frame_id, - size_t frame_size_in_bits, - base::TimeTicks when) { +void AdaptiveCongestionControl::WillSendFrameToTransport( + FrameId frame_id, + size_t frame_size_in_bytes, + base::TimeTicks when) { last_enqueued_frame_ = frame_id; FrameStats* frame_stats = GetFrameStats(frame_id); DCHECK(frame_stats); frame_stats->enqueue_time = when; - frame_stats->frame_size_in_bits = frame_size_in_bits; + frame_stats->frame_size_in_bits = frame_size_in_bytes * 8; } base::TimeTicks AdaptiveCongestionControl::EstimatedSendingTime(
diff --git a/media/cast/sender/congestion_control.h b/media/cast/sender/congestion_control.h index e63bbff8..4e2dcb1 100644 --- a/media/cast/sender/congestion_control.h +++ b/media/cast/sender/congestion_control.h
@@ -29,9 +29,9 @@ virtual void UpdateTargetPlayoutDelay(base::TimeDelta delay) = 0; // Called when an encoded frame is enqueued for transport. - virtual void SendFrameToTransport(FrameId frame_id, - size_t frame_size_in_bits, - base::TimeTicks when) = 0; + virtual void WillSendFrameToTransport(FrameId frame_id, + size_t frame_size_in_bytes, + base::TimeTicks when) = 0; // Called when we receive an ACK for a frame. virtual void AckFrame(FrameId frame_id, base::TimeTicks when) = 0;
diff --git a/media/cast/sender/congestion_control_unittest.cc b/media/cast/sender/congestion_control_unittest.cc index 3118392..c86d8183 100644 --- a/media/cast/sender/congestion_control_unittest.cc +++ b/media/cast/sender/congestion_control_unittest.cc
@@ -47,15 +47,15 @@ } void Run(int num_frames, - size_t frame_size, + size_t frame_size_in_bytes, base::TimeDelta rtt, base::TimeDelta frame_delay, base::TimeDelta ack_time) { const FrameId end = FrameId::first() + num_frames; for (frame_id_ = FrameId::first(); frame_id_ < end; frame_id_++) { congestion_control_->UpdateRtt(rtt); - congestion_control_->SendFrameToTransport( - frame_id_, frame_size, testing_clock_.NowTicks()); + congestion_control_->WillSendFrameToTransport( + frame_id_, frame_size_in_bytes, testing_clock_.NowTicks()); task_runner_->PostDelayedTask( FROM_HERE, base::BindOnce(&CongestionControlTest::AckFrame, @@ -75,13 +75,13 @@ // estimations of network bandwidth and how much is in-flight (i.e, using the // "target buffer fill" model). TEST_F(CongestionControlTest, SimpleRun) { - uint32_t frame_size = 10000 * 8; - Run(500, frame_size, base::Milliseconds(10), + uint32_t frame_size_in_bytes = 10000; + Run(500, frame_size_in_bytes, base::Milliseconds(10), base::Milliseconds(kFrameDelayMs), base::Milliseconds(45)); // Empty the buffer. task_runner_->Sleep(base::Milliseconds(100)); - uint32_t safe_bitrate = frame_size * 1000 / kFrameDelayMs; + uint32_t safe_bitrate = frame_size_in_bytes * 1000 * 8 / kFrameDelayMs; uint32_t bitrate = congestion_control_->GetBitrate( testing_clock_.NowTicks() + base::Milliseconds(300), base::Milliseconds(300)); @@ -103,8 +103,8 @@ safe_bitrate * 0.05); // Add a large (100ms) frame. - congestion_control_->SendFrameToTransport( - frame_id_++, safe_bitrate * 100 / 1000, testing_clock_.NowTicks()); + congestion_control_->WillSendFrameToTransport( + frame_id_++, safe_bitrate * 100 / 1000 / 8, testing_clock_.NowTicks()); // Results should show that we have ~200ms to send. bitrate = congestion_control_->GetBitrate( @@ -115,8 +115,8 @@ safe_bitrate * 0.05); // Add another large (100ms) frame. - congestion_control_->SendFrameToTransport( - frame_id_++, safe_bitrate * 100 / 1000, testing_clock_.NowTicks()); + congestion_control_->WillSendFrameToTransport( + frame_id_++, safe_bitrate * 100 / 1000 / 8, testing_clock_.NowTicks()); // Results should show that we have ~100ms to send. bitrate = congestion_control_->GetBitrate( @@ -157,8 +157,8 @@ // GetBitrate() returns an in-range value at each step. FrameId frame_id = FrameId::first(); for (int i = 0; i < kMaxUnackedFrames; ++i) { - congestion_control_->SendFrameToTransport(frame_id, 16384, - testing_clock_.NowTicks()); + congestion_control_->WillSendFrameToTransport(frame_id, 16384 / 8, + testing_clock_.NowTicks()); bitrate = congestion_control_->GetBitrate( testing_clock_.NowTicks() + kFakePlayoutDelay, kFakePlayoutDelay);
diff --git a/media/cast/sender/frame_sender.h b/media/cast/sender/frame_sender.h index 02221e2..0164872 100644 --- a/media/cast/sender/frame_sender.h +++ b/media/cast/sender/frame_sender.h
@@ -17,6 +17,10 @@ #include "media/cast/net/rtcp/rtcp_defines.h" #include "media/cast/sender/congestion_control.h" +namespace openscreen::cast { +class Sender; +} + namespace media::cast { struct SenderEncodedFrame; @@ -46,11 +50,21 @@ virtual void OnFrameCanceled(FrameId frame_id) {} }; + // Method of creating a frame sender using a cast transport. + // TODO(https://crbug.com/1316434): should be removed once libcast sender is + // successfully launched. static std::unique_ptr<FrameSender> Create( scoped_refptr<CastEnvironment> cast_environment, const FrameSenderConfig& config, CastTransport* const transport_sender, - Client* client); + Client& client); + + // Method of creating a frame sender using an openscreen::cast::Sender. + static std::unique_ptr<FrameSender> Create( + scoped_refptr<CastEnvironment> cast_environment, + const FrameSenderConfig& config, + openscreen::cast::Sender* sender, + Client& client); FrameSender(); FrameSender(FrameSender&&) = delete; @@ -85,6 +99,9 @@ virtual bool ShouldDropNextFrame(base::TimeDelta frame_duration) const = 0; // Returns the RTP timestamp on the frame associated with |frame_id|. + // In practice this should be implemented as a ring buffer using the lower + // eight bits of the FrameId, so timestamps older than 256 frames will be + // incorrect. virtual RtpTimeTicks GetRecordedRtpTimestamp(FrameId frame_id) const = 0; // Returns the number of frames that were sent but not yet acknowledged. @@ -113,6 +130,10 @@ virtual FrameId LatestAckedFrameId() const = 0; // RTCP client-specific methods. + // TODO(https://crbug.com/1318499): these assume we are using an RTCP client, + // which is not true when this implementation is backed by an + // OpenscreenFrameSender. These methods should be removed and tests updated to + // use a different mechanism. virtual void OnReceivedCastFeedback(const RtcpCastMessage& cast_feedback) = 0; virtual void OnReceivedPli() = 0; virtual void OnMeasuredRoundTripTime(base::TimeDelta rtt) = 0;
diff --git a/media/cast/sender/frame_sender_impl.cc b/media/cast/sender/frame_sender_impl.cc index 77b969cf..0ac8fed 100644 --- a/media/cast/sender/frame_sender_impl.cc +++ b/media/cast/sender/frame_sender_impl.cc
@@ -15,7 +15,7 @@ #include "base/logging.h" #include "base/numerics/safe_conversions.h" #include "base/trace_event/trace_event.h" -#include "media/base/media_switches.h" +#include "media/cast/common/openscreen_conversion_helpers.h" #include "media/cast/common/sender_encoded_frame.h" #include "media/cast/constants.h" @@ -37,16 +37,7 @@ scoped_refptr<CastEnvironment> cast_environment, const FrameSenderConfig& config, CastTransport* const transport_sender, - Client* client) { - // TODO(https://crbug.com/1212803): return a new OpenscreenSender if the - // Open Screen cast streaming session flag is enabled. - if (base::FeatureList::IsEnabled(kOpenscreenCastStreamingSession)) { - NOTIMPLEMENTED() - << "Enabled the OpenscreenCastStreamingFlag, but no FrameSenderImpl " - "implementation yet."; - return nullptr; - } - + Client& client) { return std::make_unique<FrameSenderImpl>(cast_environment, config, transport_sender, client); } @@ -84,7 +75,7 @@ scoped_refptr<CastEnvironment> cast_environment, const FrameSenderConfig& config, CastTransport* const transport_sender, - Client* client) + Client& client) : cast_environment_(cast_environment), config_(config), target_playout_delay_(config.max_playout_delay), @@ -163,7 +154,7 @@ const base::TimeDelta time_delta = now - GetRecordedReferenceTime(last_sent_frame_id_); const RtpTimeDelta rtp_delta = - RtpTimeDelta::FromTimeDelta(time_delta, config_.rtp_timebase); + ToRtpTimeDelta(time_delta, config_.rtp_timebase); const RtpTimeTicks now_as_rtp_timestamp = GetRecordedRtpTimestamp(last_sent_frame_id_) + rtp_delta; transport_sender_->SendSenderReport(config_.sender_ssrc, now, @@ -253,7 +244,7 @@ } base::TimeDelta FrameSenderImpl::GetInFlightMediaDuration() const { - const base::TimeDelta encoder_duration = client_->GetEncoderBacklogDuration(); + const base::TimeDelta encoder_duration = client_.GetEncoderBacklogDuration(); // No frames are in flight, so only look at the encoder duration. if (last_sent_frame_id_ == latest_acked_frame_id_) { return encoder_duration; @@ -263,8 +254,8 @@ GetRecordedRtpTimestamp(latest_acked_frame_id_); const RtpTimeTicks newest_acked_timestamp = GetRecordedRtpTimestamp(last_sent_frame_id_); - return (newest_acked_timestamp - oldest_acked_timestamp) - .ToTimeDelta(config_.rtp_timebase) + + return ToTimeDelta(newest_acked_timestamp - oldest_acked_timestamp, + config_.rtp_timebase) + encoder_duration; } @@ -332,7 +323,7 @@ std::vector<FrameId> cancel_sending_frames; for (FrameId id = latest_acked_frame_id_ + 1; id < frame_id; ++id) { cancel_sending_frames.push_back(id); - client_->OnFrameCanceled(id); + client_.OnFrameCanceled(id); } transport_sender_->CancelSendingFrames(config_.sender_ssrc, cancel_sending_frames); @@ -392,8 +383,8 @@ SendRtcpReport(is_last_aggressive_report); } - congestion_control_->SendFrameToTransport( - frame_id, encoded_frame->data.size() * 8, last_send_time_); + congestion_control_->WillSendFrameToTransport( + frame_id, encoded_frame->data.size(), last_send_time_); if (send_target_playout_delay_) { encoded_frame->new_playout_delay_ms = @@ -491,7 +482,7 @@ do { ++latest_acked_frame_id_; frames_to_cancel.push_back(latest_acked_frame_id_); - client_->OnFrameCanceled(latest_acked_frame_id_); + client_.OnFrameCanceled(latest_acked_frame_id_); // This is a good place to match the trace for frame ids // since this ensures we not only track frame ids that are // implicitly ACKed, but also handles duplicate ACKs @@ -515,7 +506,7 @@ // Check that accepting the next frame won't cause more frames to become // in-flight than the system's design limit. const int count_frames_in_flight = - GetUnacknowledgedFrameCount() + client_->GetNumberOfFramesInEncoder(); + GetUnacknowledgedFrameCount() + client_.GetNumberOfFramesInEncoder(); if (count_frames_in_flight >= kMaxUnackedFrames) { VLOG(1) << SENDER_SSRC << "Dropping: Too many frames would be in-flight."; return true;
diff --git a/media/cast/sender/frame_sender_impl.h b/media/cast/sender/frame_sender_impl.h index 9000837..4b9c1920 100644 --- a/media/cast/sender/frame_sender_impl.h +++ b/media/cast/sender/frame_sender_impl.h
@@ -29,7 +29,7 @@ FrameSenderImpl(scoped_refptr<CastEnvironment> cast_environment, const FrameSenderConfig& config, CastTransport* const transport_sender, - Client* client); + Client& client); ~FrameSenderImpl() override; // FrameSender overrides. @@ -115,7 +115,7 @@ const raw_ptr<CastTransport> transport_sender_; // The frame sender client. - raw_ptr<Client> client_ = nullptr; + Client& client_; // Whether this is an audio or video frame sender. const bool is_audio_;
diff --git a/media/cast/sender/openscreen_frame_sender.cc b/media/cast/sender/openscreen_frame_sender.cc new file mode 100644 index 0000000..4449ae3a --- /dev/null +++ b/media/cast/sender/openscreen_frame_sender.cc
@@ -0,0 +1,311 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "media/cast/sender/openscreen_frame_sender.h" + +#include <algorithm> +#include <limits> +#include <memory> +#include <utility> +#include <vector> + +#include "base/bind.h" +#include "base/cxx17_backports.h" +#include "base/feature_list.h" +#include "base/logging.h" +#include "base/numerics/safe_conversions.h" +#include "base/trace_event/trace_event.h" +#include "media/base/media_switches.h" +#include "media/cast/common/openscreen_conversion_helpers.h" +#include "media/cast/common/sender_encoded_frame.h" +#include "media/cast/constants.h" + +namespace media::cast { + +// The additional number of frames that can be in-flight when input exceeds the +// maximum frame rate. +static constexpr int kMaxFrameBurst = 5; + +std::unique_ptr<FrameSender> FrameSender::Create( + scoped_refptr<CastEnvironment> cast_environment, + const FrameSenderConfig& config, + openscreen::cast::Sender* sender, + Client& client) { + return std::make_unique<OpenscreenFrameSender>(cast_environment, config, + sender, client); +} + +// Convenience macro used in logging statements throughout this file. +#define VLOG_WITH_SSRC(N) \ + VLOG(N) << (is_audio_ ? "AUDIO[" : "VIDEO[") \ + << sender_->config().sender_ssrc << "] " + +OpenscreenFrameSender::OpenscreenFrameSender( + scoped_refptr<CastEnvironment> cast_environment, + const FrameSenderConfig& config, + openscreen::cast::Sender* sender, + Client& client) + : cast_environment_(cast_environment), + sender_(sender), + client_(client), + max_frame_rate_(config.max_frame_rate), + is_audio_(config.rtp_payload_type <= RtpPayloadType::AUDIO_LAST), + // We only use the adaptive control for software video encoding. + congestion_control_( + (!config.use_external_encoder && !is_audio_) + ? NewAdaptiveCongestionControl(cast_environment->Clock(), + config.max_bitrate, + config.min_bitrate, + max_frame_rate_) + : NewFixedCongestionControl( + (config.min_bitrate + config.max_bitrate) / 2) + + ), + min_playout_delay_(config.min_playout_delay), + max_playout_delay_(config.max_playout_delay) { + DCHECK_GT(sender_->config().rtp_timebase, 0); + + // We assume animated content to begin with since that is the common use + // case today. + VLOG_WITH_SSRC(1) << "target latency " + << sender_->config().target_playout_delay.count() << "ms"; + SetTargetPlayoutDelay(config.animated_playout_delay); + + sender_->SetObserver(this); +} + +OpenscreenFrameSender::~OpenscreenFrameSender() { + sender_->SetObserver(nullptr); +} + +bool OpenscreenFrameSender::NeedsKeyFrame() const { + return sender_->NeedsKeyFrame(); +} + +void OpenscreenFrameSender::OnMeasuredRoundTripTime( + base::TimeDelta round_trip_time) { + NOTIMPLEMENTED(); +} + +void OpenscreenFrameSender::SetTargetPlayoutDelay( + base::TimeDelta new_target_playout_delay) { + if (send_target_playout_delay_ && + target_playout_delay_ == new_target_playout_delay) { + return; + } + + new_target_playout_delay = base::clamp( + new_target_playout_delay, min_playout_delay_, max_playout_delay_); + VLOG_WITH_SSRC(2) << "Target playout delay changing from " + << target_playout_delay_.InMilliseconds() << " ms to " + << new_target_playout_delay.InMilliseconds() << " ms."; + target_playout_delay_ = new_target_playout_delay; + send_target_playout_delay_ = true; + congestion_control_->UpdateTargetPlayoutDelay(target_playout_delay_); +} + +base::TimeDelta OpenscreenFrameSender::GetTargetPlayoutDelay() const { + return target_playout_delay_; +} + +void OpenscreenFrameSender::OnFrameCanceled( + openscreen::cast::FrameId frame_id) { + client_.OnFrameCanceled(frame_id); +} + +void OpenscreenFrameSender::OnPictureLost() { + NOTIMPLEMENTED(); +} + +void OpenscreenFrameSender::RecordLatestFrameTimestamps( + FrameId frame_id, + base::TimeTicks reference_time, + RtpTimeTicks rtp_timestamp) { + DCHECK(!reference_time.is_null()); + frame_rtp_timestamps_[frame_id.lower_8_bits()] = rtp_timestamp; +} + +base::TimeDelta OpenscreenFrameSender::GetInFlightMediaDuration() const { + const base::TimeDelta encoder_duration = client_.GetEncoderBacklogDuration(); + const RtpTimeTicks newest_timestamp = + GetRecordedRtpTimestamp(last_sent_frame_id_); + return encoder_duration + + ToTimeDelta(sender_->GetInFlightMediaDuration(newest_timestamp)); +} + +RtpTimeTicks OpenscreenFrameSender::GetRecordedRtpTimestamp( + FrameId frame_id) const { + if (static_cast<size_t>(std::abs(last_sent_frame_id_ - frame_id)) >= + std::size(frame_rtp_timestamps_)) { + return {}; + } + return frame_rtp_timestamps_[frame_id.lower_8_bits()]; +} + +int OpenscreenFrameSender::GetUnacknowledgedFrameCount() const { + return sender_->GetInFlightFrameCount(); +} + +int OpenscreenFrameSender::GetSuggestedBitrate(base::TimeTicks playout_time, + base::TimeDelta playout_delay) { + return congestion_control_->GetBitrate(playout_time, playout_delay); +} + +double OpenscreenFrameSender::MaxFrameRate() const { + return max_frame_rate_; +} + +void OpenscreenFrameSender::SetMaxFrameRate(double max_frame_rate) { + max_frame_rate_ = max_frame_rate; +} + +base::TimeDelta OpenscreenFrameSender::TargetPlayoutDelay() const { + return target_playout_delay_; +} + +base::TimeDelta OpenscreenFrameSender::CurrentRoundTripTime() const { + return base::Microseconds( + std::chrono::duration_cast<std::chrono::microseconds>( + sender_->GetCurrentRoundTripTime()) + .count()); +} + +base::TimeTicks OpenscreenFrameSender::LastSendTime() const { + return last_send_time_; +} + +FrameId OpenscreenFrameSender::LatestAckedFrameId() const { + // TODO(https://crbug.com/1318499): this field is only used for testing + // the RemotingSender, and should be refactored since this property is not + // available from the openscreen::cast::Sender. + return {}; +} + +base::TimeDelta OpenscreenFrameSender::GetAllowedInFlightMediaDuration() const { + return ToTimeDelta(sender_->GetMaxInFlightMediaDuration()); +} + +void OpenscreenFrameSender::EnqueueFrame( + std::unique_ptr<SenderEncodedFrame> encoded_frame) { + DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); + + VLOG_WITH_SSRC(2) << "About to send another frame: last_sent=" + << last_sent_frame_id_; + + const FrameId frame_id = encoded_frame->frame_id; + last_send_time_ = cast_environment_->Clock()->NowTicks(); + + DCHECK(frame_id > last_sent_frame_id_) << "enqueued frames out of order."; + last_sent_frame_id_ = frame_id; + if (!is_audio_ && encoded_frame->dependency == EncodedFrame::KEY) { + VLOG_WITH_SSRC(1) << "Sending encoded key frame, id=" << frame_id; + } + + auto encode_event = std::make_unique<FrameEvent>(); + encode_event->timestamp = encoded_frame->encode_completion_time; + encode_event->type = FRAME_ENCODED; + encode_event->media_type = is_audio_ ? AUDIO_EVENT : VIDEO_EVENT; + encode_event->rtp_timestamp = encoded_frame->rtp_timestamp; + encode_event->frame_id = frame_id; + encode_event->size = base::checked_cast<uint32_t>(encoded_frame->data.size()); + encode_event->key_frame = encoded_frame->dependency == EncodedFrame::KEY; + encode_event->target_bitrate = encoded_frame->encoder_bitrate; + encode_event->encoder_cpu_utilization = encoded_frame->encoder_utilization; + encode_event->idealized_bitrate_utilization = encoded_frame->lossiness; + + // This is used specifically for testing and is no longer consumed in + // production. + cast_environment_->logger()->DispatchFrameEvent(std::move(encode_event)); + + RecordLatestFrameTimestamps(frame_id, encoded_frame->reference_time, + encoded_frame->rtp_timestamp); + + if (!is_audio_) { + // Used by chrome/browser/media/cast_mirroring_performance_browsertest.cc + TRACE_EVENT_INSTANT1("cast_perf_test", "VideoFrameEncoded", + TRACE_EVENT_SCOPE_THREAD, "rtp_timestamp", + encoded_frame->rtp_timestamp.lower_32_bits()); + } + + congestion_control_->WillSendFrameToTransport( + frame_id, encoded_frame->data.size(), last_send_time_); + + if (send_target_playout_delay_) { + encoded_frame->new_playout_delay_ms = + target_playout_delay_.InMilliseconds(); + send_target_playout_delay_ = false; + } + + static const char* name = is_audio_ ? "Audio Transport" : "Video Transport"; + TRACE_EVENT_NESTABLE_ASYNC_BEGIN1( + "cast.stream", name, TRACE_ID_WITH_SCOPE(name, frame_id.lower_32_bits()), + "rtp_timestamp", encoded_frame->rtp_timestamp.lower_32_bits()); + + const auto result = + sender_->EnqueueFrame(ToOpenscreenEncodedFrame(*encoded_frame)); + if (result != openscreen::cast::Sender::EnqueueFrameResult::OK) { + VLOG(1) << "Failed to enqueue frame " << frame_id << ", dropping..."; + } +} + +void OpenscreenFrameSender::OnReceivedCastFeedback( + const RtcpCastMessage& cast_feedback) { + NOTIMPLEMENTED(); +} + +void OpenscreenFrameSender::OnReceivedPli() { + OnPictureLost(); +} + +bool OpenscreenFrameSender::ShouldDropNextFrame( + base::TimeDelta frame_duration) const { + // Check that accepting the next frame won't cause more frames to become + // in-flight than the system's design limit. + const int count_frames_in_flight = + GetUnacknowledgedFrameCount() + client_.GetNumberOfFramesInEncoder(); + if (count_frames_in_flight >= kMaxUnackedFrames) { + VLOG_WITH_SSRC(1) << "Dropping: Too many frames would be in-flight."; + return true; + } + + // Check that accepting the next frame won't exceed the configured maximum + // frame rate, allowing for short-term bursts. + const base::TimeDelta duration_in_flight = GetInFlightMediaDuration(); + const double max_frames_in_flight = + max_frame_rate_ * duration_in_flight.InSecondsF(); + if (count_frames_in_flight >= max_frames_in_flight + kMaxFrameBurst) { + VLOG_WITH_SSRC(1) << "Dropping: Burst threshold would be exceeded."; + return true; + } + + // Check that accepting the next frame won't exceed the allowed in-flight + // media duration. + const base::TimeDelta duration_would_be_in_flight = + duration_in_flight + frame_duration; + const base::TimeDelta allowed_in_flight = GetAllowedInFlightMediaDuration(); + if (VLOG_IS_ON(1)) { + const int64_t percent = + allowed_in_flight.is_positive() + ? base::ClampRound<int64_t>(duration_would_be_in_flight / + allowed_in_flight * 100) + : std::numeric_limits<int64_t>::max(); + + if (percent > 50) { + VLOG_WITH_SSRC(1) << duration_in_flight.InMicroseconds() + << " usec in-flight + " + << frame_duration.InMicroseconds() + << " usec for next frame --> " << percent + << "% of allowed in-flight."; + } + } + if (duration_would_be_in_flight > allowed_in_flight) { + VLOG_WITH_SSRC(1) << "Dropping: In-flight duration would be too high."; + return true; + } + + // Next frame is accepted. + return false; +} + +} // namespace media::cast
diff --git a/media/cast/sender/openscreen_frame_sender.h b/media/cast/sender/openscreen_frame_sender.h new file mode 100644 index 0000000..1066b3bb --- /dev/null +++ b/media/cast/sender/openscreen_frame_sender.h
@@ -0,0 +1,144 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MEDIA_CAST_SENDER_OPENSCREEN_FRAME_SENDER_H_ +#define MEDIA_CAST_SENDER_OPENSCREEN_FRAME_SENDER_H_ + +#include <stdint.h> + +#include "base/memory/raw_ptr.h" +#include "base/memory/ref_counted.h" +#include "base/memory/weak_ptr.h" +#include "base/time/time.h" +#include "media/cast/cast_config.h" +#include "media/cast/cast_environment.h" +#include "media/cast/net/cast_transport.h" +#include "media/cast/net/rtcp/rtcp_defines.h" +#include "media/cast/sender/congestion_control.h" +#include "media/cast/sender/frame_sender.h" + +#include "third_party/openscreen/src/cast/streaming/sender.h" + +namespace media::cast { + +struct SenderEncodedFrame; + +// This is the Open Screen implementation of the FrameSender API. It wraps +// an openscreen::cast::Sender object and provides some basic functionality +// that is shared between the AudioSender, VideoSender, and RemotingSender +// classes. +// +// For more information, see the Cast Streaming README.md located at: +// https://source.chromium.org/chromium/chromium/src/+/main:third_party/openscreen/src/cast/streaming/README.md + +class OpenscreenFrameSender : public FrameSender, + openscreen::cast::Sender::Observer { + public: + // TODO(https://crbug.com/1318499): will likely need to remove + // FrameSenderConfig here once the migration to libcast is complete. + OpenscreenFrameSender(scoped_refptr<CastEnvironment> cast_environment, + const FrameSenderConfig& config, + openscreen::cast::Sender* sender, + Client& client); + ~OpenscreenFrameSender() override; + + // FrameSender overrides. + void SetTargetPlayoutDelay(base::TimeDelta new_target_playout_delay) override; + base::TimeDelta GetTargetPlayoutDelay() const override; + bool NeedsKeyFrame() const override; + void EnqueueFrame(std::unique_ptr<SenderEncodedFrame> encoded_frame) override; + bool ShouldDropNextFrame(base::TimeDelta frame_duration) const override; + RtpTimeTicks GetRecordedRtpTimestamp(FrameId frame_id) const override; + int GetUnacknowledgedFrameCount() const override; + int GetSuggestedBitrate(base::TimeTicks playout_time, + base::TimeDelta playout_delay) override; + double MaxFrameRate() const override; + void SetMaxFrameRate(double max_frame_rate) override; + base::TimeDelta TargetPlayoutDelay() const override; + base::TimeDelta CurrentRoundTripTime() const override; + base::TimeTicks LastSendTime() const override; + FrameId LatestAckedFrameId() const override; + + private: + // TODO(https://crbug.com/1318499): these should be removed from the + // FrameSender API. + void OnReceivedCastFeedback(const RtcpCastMessage& cast_feedback) override; + void OnReceivedPli() override; + void OnMeasuredRoundTripTime(base::TimeDelta rtt) override; + + // openscreen::cast::Sender::Observer overrides. + void OnFrameCanceled(openscreen::cast::FrameId frame_id) override; + void OnPictureLost() override; + + // Helper for getting the reference time recorded on the frame associated + // with |frame_id|. + base::TimeTicks GetRecordedReferenceTime(FrameId frame_id) const; + + // Record timestamps for later retrieval by GetRecordedRtpTimestamp. + void RecordLatestFrameTimestamps(FrameId frame_id, + base::TimeTicks reference_time, + RtpTimeTicks rtp_timestamp); + + base::TimeDelta GetInFlightMediaDuration() const; + + private: + // Returns the maximum media duration currently allowed in-flight. This + // fluctuates in response to the currently-measured network latency. + base::TimeDelta GetAllowedInFlightMediaDuration() const; + + // The cast environment. + const scoped_refptr<CastEnvironment> cast_environment_; + + // The backing Open Screen sender implementation. + raw_ptr<openscreen::cast::Sender> const sender_; + + // The frame sender client. + Client& client_; + + // Max encoded frames generated per second. + double max_frame_rate_; + + // Whether this is an audio or video frame sender. + const bool is_audio_; + + // The congestion control manages frame statistics and helps make decisions + // about what bitrate we encode the next frame at. + std::unique_ptr<CongestionControl> congestion_control_; + + // The target playout delay, may fluctuate between the min and max delays. + base::TimeDelta target_playout_delay_; + base::TimeDelta min_playout_delay_; + base::TimeDelta max_playout_delay_; + + // This is "null" until the first frame is sent. Thereafter, this tracks the + // last time any frame was sent or re-sent. + base::TimeTicks last_send_time_; + + // The ID of the last frame sent. This member is invalid until + // |!last_send_time_.is_null()|. + FrameId last_sent_frame_id_; + + // This is the maximum delay that the sender should get ack from receiver. + // Counts how many RTCP reports are being "aggressively" sent (i.e., one per + // frame) at the start of the session. Once a threshold is reached, RTCP + // reports are instead sent at the configured interval + random drift. + int num_aggressive_rtcp_reports_sent_ = 0; + + // Should send the target playout delay with the next frame. Behind the + // scenes, the openscreen::cast::Sender checks the frame's playout delay and + // notifies the receiver if it has changed. + bool send_target_playout_delay_ = false; + + // Ring buffer to keep track of recent frame timestamps. These should only be + // accessed through the Record/GetXXX() methods. The index into this ring + // buffer is the lower 8 bits of the FrameId. + RtpTimeTicks frame_rtp_timestamps_[256]; + + // NOTE: Weak pointers must be invalidated before all other member variables. + base::WeakPtrFactory<OpenscreenFrameSender> weak_factory_{this}; +}; + +} // namespace media::cast + +#endif // MEDIA_CAST_SENDER_OPENSCREEN_FRAME_SENDER_H_
diff --git a/media/cast/sender/video_sender.cc b/media/cast/sender/video_sender.cc index 187051d..7b5621e 100644 --- a/media/cast/sender/video_sender.cc +++ b/media/cast/sender/video_sender.cc
@@ -13,10 +13,14 @@ #include "base/bind.h" #include "base/logging.h" #include "base/trace_event/trace_event.h" +#include "media/base/media_switches.h" +#include "media/cast/common/openscreen_conversion_helpers.h" #include "media/cast/common/sender_encoded_frame.h" #include "media/cast/encoding/video_encoder.h" #include "media/cast/net/cast_transport_config.h" +#include "media/cast/sender/openscreen_frame_sender.h" #include "media/cast/sender/performance_metrics_overlay.h" +#include "third_party/openscreen/src/cast/streaming/sender.h" namespace media::cast { @@ -84,6 +88,44 @@ } // namespace +VideoSender::VideoSender( + scoped_refptr<CastEnvironment> cast_environment, + const FrameSenderConfig& video_config, + StatusChangeCallback status_change_cb, + const CreateVideoEncodeAcceleratorCallback& create_vea_cb, + CastTransport* const transport_sender, + PlayoutDelayChangeCB playout_delay_change_cb, + media::VideoCaptureFeedbackCB feedback_callback) + : VideoSender(cast_environment, + video_config, + std::move(status_change_cb), + std::move(create_vea_cb), + FrameSender::Create(cast_environment, + video_config, + transport_sender, + *this), + std::move(playout_delay_change_cb), + std::move(feedback_callback)) {} + +VideoSender::VideoSender( + scoped_refptr<CastEnvironment> cast_environment, + const FrameSenderConfig& video_config, + StatusChangeCallback status_change_cb, + const CreateVideoEncodeAcceleratorCallback& create_vea_cb, + openscreen::cast::Sender* sender, + PlayoutDelayChangeCB playout_delay_change_cb, + media::VideoCaptureFeedbackCB feedback_callback) + : VideoSender( + cast_environment, + video_config, + std::move(status_change_cb), + std::move(create_vea_cb), + FrameSender::Create(cast_environment, video_config, sender, *this), + std::move(playout_delay_change_cb), + std::move(feedback_callback)) { + DCHECK(base::FeatureList::IsEnabled(kOpenscreenCastStreamingSession)); +} + // Note, we use a fixed bitrate value when external video encoder is used. // Some hardware encoder shows bad behavior if we set the bitrate too // frequently, e.g. quality drop, not abiding by target bitrate, etc. @@ -93,13 +135,10 @@ const FrameSenderConfig& video_config, StatusChangeCallback status_change_cb, const CreateVideoEncodeAcceleratorCallback& create_vea_cb, - CastTransport* const transport_sender, + std::unique_ptr<FrameSender> sender, PlayoutDelayChangeCB playout_delay_change_cb, media::VideoCaptureFeedbackCB feedback_callback) - : frame_sender_(FrameSender::Create(cast_environment, - video_config, - transport_sender, - this)), + : frame_sender_(std::move(sender)), cast_environment_(cast_environment), min_playout_delay_(video_config.min_playout_delay), max_playout_delay_(video_config.max_playout_delay), @@ -128,7 +167,7 @@ } const RtpTimeTicks rtp_timestamp = - RtpTimeTicks::FromTimeDelta(video_frame->timestamp(), kVideoFrequency); + ToRtpTimeTicks(video_frame->timestamp(), kVideoFrequency); LogVideoCaptureTimestamps(cast_environment_.get(), *video_frame, rtp_timestamp);
diff --git a/media/cast/sender/video_sender.h b/media/cast/sender/video_sender.h index c369620..816d7ef6 100644 --- a/media/cast/sender/video_sender.h +++ b/media/cast/sender/video_sender.h
@@ -18,6 +18,10 @@ #include "media/cast/common/rtp_time.h" #include "media/cast/sender/frame_sender.h" +namespace openscreen::cast { +class Sender; +} + namespace media { class VideoFrame; } @@ -38,6 +42,9 @@ // timeouts. class VideoSender : public FrameSender::Client { public: + // Old way to instantiate, using a cast transport. + // TODO(https://crbug.com/1316434): should be removed once libcast sender is + // successfully launched. VideoSender(scoped_refptr<CastEnvironment> cast_environment, const FrameSenderConfig& video_config, StatusChangeCallback status_change_cb, @@ -46,6 +53,17 @@ PlayoutDelayChangeCB playout_delay_change_cb, media::VideoCaptureFeedbackCB feedback_callback); + // New way of instantiating using an openscreen::cast::Sender. Since the + // |Sender| instance is destroyed when renegotiation is complete, |this| + // is also invalid and should be immediately torn down. + VideoSender(scoped_refptr<CastEnvironment> cast_environment, + const FrameSenderConfig& video_config, + StatusChangeCallback status_change_cb, + const CreateVideoEncodeAcceleratorCallback& create_vea_cb, + openscreen::cast::Sender* sender, + PlayoutDelayChangeCB playout_delay_change_cb, + media::VideoCaptureFeedbackCB feedback_callback); + VideoSender(const VideoSender&) = delete; VideoSender& operator=(const VideoSender&) = delete; @@ -76,6 +94,14 @@ FrameSender* frame_sender_for_testing() { return frame_sender_.get(); } private: + VideoSender(scoped_refptr<CastEnvironment> cast_environment, + const FrameSenderConfig& video_config, + StatusChangeCallback status_change_cb, + const CreateVideoEncodeAcceleratorCallback& create_vea_cb, + std::unique_ptr<FrameSender> sender, + PlayoutDelayChangeCB playout_delay_change_cb, + media::VideoCaptureFeedbackCB feedback_callback); + // Called by the |video_encoder_| with the next EncodedFrame to send. void OnEncodedVideoFrame(scoped_refptr<media::VideoFrame> video_frame, std::unique_ptr<SenderEncodedFrame> encoded_frame);
diff --git a/media/cast/test/receiver/frame_receiver.cc b/media/cast/test/receiver/frame_receiver.cc index c935dad..573bf683 100644 --- a/media/cast/test/receiver/frame_receiver.cc +++ b/media/cast/test/receiver/frame_receiver.cc
@@ -15,6 +15,7 @@ #include "media/cast/cast_config.h" #include "media/cast/cast_environment.h" #include "media/cast/common/encoded_frame.h" +#include "media/cast/common/openscreen_conversion_helpers.h" #include "media/cast/constants.h" #include "media/cast/net/rtcp/rtcp_utility.h" @@ -165,7 +166,7 @@ // Note: It's okay for the conversion ToTimeDelta() to be approximate // because |lip_sync_drift_| will account for accumulated errors. lip_sync_reference_time_ += - (fresh_sync_rtp - lip_sync_rtp_timestamp_).ToTimeDelta(rtp_timebase_); + ToTimeDelta(fresh_sync_rtp - lip_sync_rtp_timestamp_, rtp_timebase_); } lip_sync_rtp_timestamp_ = fresh_sync_rtp; lip_sync_drift_.Update(now, @@ -303,8 +304,8 @@ target_playout_delay = base::Milliseconds(frame.new_playout_delay_ms); } return lip_sync_reference_time_ + lip_sync_drift_.Current() + - (frame.rtp_timestamp - lip_sync_rtp_timestamp_) - .ToTimeDelta(rtp_timebase_) + + ToTimeDelta(frame.rtp_timestamp - lip_sync_rtp_timestamp_, + rtp_timebase_) + target_playout_delay; }
diff --git a/media/cast/test/receiver/frame_receiver_unittest.cc b/media/cast/test/receiver/frame_receiver_unittest.cc index e818bb3..5a5cb48f 100644 --- a/media/cast/test/receiver/frame_receiver_unittest.cc +++ b/media/cast/test/receiver/frame_receiver_unittest.cc
@@ -18,6 +18,7 @@ #include "media/base/fake_single_thread_task_runner.h" #include "media/cast/cast_environment.h" #include "media/cast/common/encoded_frame.h" +#include "media/cast/common/openscreen_conversion_helpers.h" #include "media/cast/logging/simple_event_subscriber.h" #include "media/cast/net/cast_transport_impl.h" #include "media/cast/net/rtcp/rtcp_utility.h" @@ -130,7 +131,7 @@ void FeedLipSyncInfoIntoReceiver() { const base::TimeTicks now = testing_clock_.NowTicks(); const RtpTimeTicks rtp_timestamp = - RtpTimeTicks::FromTimeDelta(now - start_time_, config_.rtp_timebase); + ToRtpTimeTicks(now - start_time_, config_.rtp_timebase); CHECK_LE(RtpTimeTicks(), rtp_timestamp); uint32_t ntp_seconds; uint32_t ntp_fraction; @@ -248,7 +249,7 @@ const base::TimeDelta time_advance_per_frame = base::Seconds(1) / config_.target_frame_rate; const RtpTimeDelta rtp_advance_per_frame = - RtpTimeDelta::FromTimeDelta(time_advance_per_frame, config_.rtp_timebase); + ToRtpTimeDelta(time_advance_per_frame, config_.rtp_timebase); // Feed and process lip sync in receiver. FeedLipSyncInfoIntoReceiver(); @@ -362,7 +363,7 @@ const base::TimeDelta time_advance_per_frame = base::Seconds(1) / config_.target_frame_rate; const RtpTimeDelta rtp_advance_per_frame = - RtpTimeDelta::FromTimeDelta(time_advance_per_frame, config_.rtp_timebase); + ToRtpTimeDelta(time_advance_per_frame, config_.rtp_timebase); // Feed and process lip sync in receiver. FeedLipSyncInfoIntoReceiver();
diff --git a/media/cast/test/receiver/receiver_stats.cc b/media/cast/test/receiver/receiver_stats.cc index 445ec128..1743e953 100644 --- a/media/cast/test/receiver/receiver_stats.cc +++ b/media/cast/test/receiver/receiver_stats.cc
@@ -4,6 +4,7 @@ #include "media/cast/test/receiver/receiver_stats.h" +#include "media/cast/common/openscreen_conversion_helpers.h" #include "media/cast/net/rtp/rtp_defines.h" namespace media { @@ -109,9 +110,8 @@ if (total_number_packets_ > 0) { const base::TimeDelta packet_time_difference = now - last_received_packet_time_; - const base::TimeDelta media_time_differerence = - (header.rtp_timestamp - last_received_rtp_timestamp_) - .ToTimeDelta(rtp_timebase); + const base::TimeDelta media_time_differerence = ToTimeDelta( + header.rtp_timestamp - last_received_rtp_timestamp_, rtp_timebase); const base::TimeDelta delta = packet_time_difference - media_time_differerence; // Update jitter.
diff --git a/media/cast/test/receiver/receiver_stats_unittest.cc b/media/cast/test/receiver/receiver_stats_unittest.cc index efc7227e..8b51945 100644 --- a/media/cast/test/receiver/receiver_stats_unittest.cc +++ b/media/cast/test/receiver/receiver_stats_unittest.cc
@@ -8,6 +8,7 @@ #include "base/test/simple_test_tick_clock.h" #include "base/time/time.h" +#include "media/cast/common/openscreen_conversion_helpers.h" #include "media/cast/constants.h" #include "media/cast/net/rtp/rtp_defines.h" #include "media/cast/test/receiver/receiver_stats.h" @@ -63,7 +64,7 @@ stats_.UpdateStatistics(rtp_header_, kVideoFrequency); if (i % 3) { rtp_header_.rtp_timestamp += - RtpTimeDelta::FromTimeDelta(base::Milliseconds(33), kVideoFrequency); + ToRtpTimeDelta(base::Milliseconds(33), kVideoFrequency); } ++rtp_header_.sequence_number; testing_clock_.Advance(delta_increments_); @@ -82,7 +83,7 @@ stats_.UpdateStatistics(rtp_header_, kVideoFrequency); if (i % 3) { rtp_header_.rtp_timestamp += - RtpTimeDelta::FromTimeDelta(base::Milliseconds(33), kVideoFrequency); + ToRtpTimeDelta(base::Milliseconds(33), kVideoFrequency); } ++rtp_header_.sequence_number; testing_clock_.Advance(delta_increments_); @@ -119,7 +120,7 @@ stats_.UpdateStatistics(rtp_header_, kVideoFrequency); ++rtp_header_.sequence_number; rtp_header_.rtp_timestamp += - RtpTimeDelta::FromTimeDelta(base::Milliseconds(33), kVideoFrequency); + ToRtpTimeDelta(base::Milliseconds(33), kVideoFrequency); testing_clock_.Advance(delta_increments_); } RtpReceiverStatistics s = stats_.GetStatistics(); @@ -137,7 +138,7 @@ stats_.UpdateStatistics(rtp_header_, kVideoFrequency); ++rtp_header_.sequence_number; rtp_header_.rtp_timestamp += - RtpTimeDelta::FromTimeDelta(base::Milliseconds(33), kVideoFrequency); + ToRtpTimeDelta(base::Milliseconds(33), kVideoFrequency); base::TimeDelta additional_delta = base::Milliseconds(kAdditionalIncrement); testing_clock_.Advance(delta_increments_ + additional_delta); }
diff --git a/media/cast/test/receiver/video_decoder.cc b/media/cast/test/receiver/video_decoder.cc index cf627c8..098af4f 100644 --- a/media/cast/test/receiver/video_decoder.cc +++ b/media/cast/test/receiver/video_decoder.cc
@@ -17,6 +17,7 @@ #include "media/base/video_util.h" #include "media/cast/cast_environment.h" #include "media/cast/common/encoded_frame.h" +#include "media/cast/common/openscreen_conversion_helpers.h" #include "third_party/libvpx/source/libvpx/vpx/vp8dx.h" #include "third_party/libvpx/source/libvpx/vpx/vpx_decoder.h" #include "third_party/libyuv/include/libyuv/convert.h" @@ -66,7 +67,7 @@ return; } decoded_frame->set_timestamp( - encoded_frame->rtp_timestamp.ToTimeDelta(kVideoFrequency)); + ToTimeDelta(encoded_frame->rtp_timestamp, kVideoFrequency)); std::unique_ptr<FrameEvent> decode_event(new FrameEvent()); decode_event->timestamp = cast_environment_->Clock()->NowTicks();
diff --git a/net/quic/quic_chromium_client_session.cc b/net/quic/quic_chromium_client_session.cc index 67988c8..802f281 100644 --- a/net/quic/quic_chromium_client_session.cc +++ b/net/quic/quic_chromium_client_session.cc
@@ -2854,6 +2854,8 @@ void QuicChromiumClientSession::MaybeMigrateToDifferentPortOnPathDegrading() { DCHECK(allow_port_migration_ && !migrate_session_early_v2_); + current_migration_cause_ = CHANGE_PORT_ON_PATH_DEGRADING; + if (!version().UsesHttp3()) return; @@ -2872,7 +2874,6 @@ return; } - current_migration_cause_ = CHANGE_PORT_ON_PATH_DEGRADING; net_log_.BeginEvent(NetLogEventType::QUIC_PORT_MIGRATION_TRIGGERED); if (!stream_factory_)
diff --git a/sandbox/win/src/sandbox_types.h b/sandbox/win/src/sandbox_types.h index e5c36643..8651aac 100644 --- a/sandbox/win/src/sandbox_types.h +++ b/sandbox/win/src/sandbox_types.h
@@ -191,7 +191,9 @@ // Contains the pointer to a target or broker service. struct SandboxInterfaceInfo { - raw_ptr<BrokerServices> broker_services; + // TODO(crbug.com/1298696): Chrome crashes with MTECheckedPtr + // enabled. Triage. + raw_ptr<BrokerServices, DegradeToNoOpWhenMTE> broker_services; raw_ptr<TargetServices> target_services; };
diff --git a/services/network/sct_auditing/sct_auditing_handler.cc b/services/network/sct_auditing/sct_auditing_handler.cc index 18afd1bb..5afcf31 100644 --- a/services/network/sct_auditing/sct_auditing_handler.cc +++ b/services/network/sct_auditing/sct_auditing_handler.cc
@@ -7,6 +7,7 @@ #include <algorithm> #include "base/base64.h" +#include "base/bind.h" #include "base/containers/cxx20_erase.h" #include "base/containers/span.h" #include "base/feature_list.h" @@ -357,12 +358,6 @@ DeserializeData(serialized); } -void SCTAuditingHandler::OnWriteFinished(base::OnceClosure callback, - bool /*unused*/) { - DCHECK(background_runner_->RunsTasksInCurrentSequence()); - foreground_runner_->PostTask(FROM_HERE, std::move(callback)); -} - void SCTAuditingHandler::ClearPendingReports(base::OnceClosure callback) { DCHECK(foreground_runner_->RunsTasksInCurrentSequence()); // Delete any outstanding Reporters. This will delete any extant URLLoader @@ -374,8 +369,18 @@ if (writer_) { writer_->RegisterOnNextWriteCallbacks( base::OnceClosure(), - base::BindOnce(&SCTAuditingHandler::OnWriteFinished, - weak_factory_.GetWeakPtr(), std::move(callback))); + // The callback set by NetworkContext is a BarrierClosure that does not + // take any arguments. The ImportantFileWriter runs its callbacks on the + // background sequence. This addresses both issues by setting up the + // `after_write_callback` to post back to the foreground task runner and + // adapts the type signatures to drop the unused bool. + base::BindPostTask( + foreground_runner_, + base::BindOnce( + [](base::OnceCallback<void()> cb, bool /* unused */) { + return std::move(cb).Run(); + }, + std::move(callback)))); auto data = std::make_unique<std::string>(); SerializeData(data.get()); writer_->WriteNow(std::move(data));
diff --git a/services/network/sct_auditing/sct_auditing_handler.h b/services/network/sct_auditing/sct_auditing_handler.h index 51a5779..9a34f7f 100644 --- a/services/network/sct_auditing/sct_auditing_handler.h +++ b/services/network/sct_auditing/sct_auditing_handler.h
@@ -137,12 +137,6 @@ void OnReporterStateUpdated(); void OnReporterFinished(net::HashValue reporter_key); - // Wrapper to pass the callback back to the foreground runner, as the - // underlying ImportantFileWriter runs its callback on the background runner. - // ImportantFileWriter requires a `OnceCallback<void(bool success)>` for the - // write completion callback, but the boolean is currently unused here. - void OnWriteFinished(base::OnceClosure callback, bool /*unused*/); - void ReportHWMMetrics(); mojom::URLLoaderFactory* GetURLLoaderFactory();
diff --git a/services/network/sct_auditing/sct_auditing_handler_unittest.cc b/services/network/sct_auditing/sct_auditing_handler_unittest.cc index 68af989..7176a3ea 100644 --- a/services/network/sct_auditing/sct_auditing_handler_unittest.cc +++ b/services/network/sct_auditing/sct_auditing_handler_unittest.cc
@@ -1004,6 +1004,59 @@ } } +// Regression test for crbug.com/1344881 +// Writes a pre-existing persisted reporter, starts up the SCTAuditingHandler, +// waits for the Reporter to be created from the persisted data, and then +// clears the pending reporters. (Prior to the fix for crbug.com/1344881, it was +// possible for the ImportantFileWriter `after_write_callback` to run on the +// background sequence in some circumstances, causing thread safety violations +// when dereferencing the WeakPtr. This test explicitly covers the case where +// the `after_write_callback` code path is exercised.) +TEST_F(SCTAuditingHandlerTest, ClearPendingReports) { + // Set up previously persisted data on disk: + // - Default-initialized net::HashValue(net::HASH_VALUE_SHA256) + // - Empty SCTClientReport for origin "example.test:443". + // - A simple BackoffEntry. + std::string persisted_report = + R"( + [{ + "reporter_key": + "sha256/qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqo=", + "report": "EhUKExIRCgxleGFtcGxlLnRlc3QQuwM=", + "backoff_entry": [2,0,"30000000","11644578625551798"] + }] + )"; + ASSERT_TRUE(base::WriteFile(persistence_path_, persisted_report)); + + mojo::PendingRemote<network::mojom::URLLoaderFactory> factory_remote; + url_loader_factory_.Clone(factory_remote.InitWithNewPipeAndPassReceiver()); + + SCTAuditingHandler handler(network_context_.get(), persistence_path_); + handler.SetMode(mojom::SCTAuditingMode::kEnhancedSafeBrowsingReporting); + handler.SetURLLoaderFactoryForTesting(std::move(factory_remote)); + + auto* file_writer = handler.GetFileWriterForTesting(); + ASSERT_TRUE(file_writer); + + WaitForRequests(1u); + + EXPECT_EQ(handler.GetPendingReportersForTesting()->size(), 1u); + EXPECT_EQ(1, url_loader_factory_.NumPending()); + + // Clear pending reports (with persistence set up and data on disk) to + // exercise the full clearing and callbacks code paths. + base::RunLoop run_loop; + handler.ClearPendingReports(run_loop.QuitClosure()); + run_loop.Run(); + + // Check that the pending reporter was deleted. + EXPECT_TRUE(handler.GetPendingReportersForTesting()->empty()); + + // Check that the Reporter is no longer in the file. + EXPECT_FALSE(FileContentsHasString( + "sha256/qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqo=")); +} + class NoPersistenceSCTAuditingHandlerTest : public SCTAuditingHandlerTest { public: void SetUp() override {
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc index ed1cce3e..e59a7ee0 100644 --- a/third_party/blink/common/features.cc +++ b/third_party/blink/common/features.cc
@@ -1443,6 +1443,9 @@ const base::Feature kZeroCopyTabCapture{"ZeroCopyTabCapture", base::FEATURE_DISABLED_BY_DEFAULT}; +const base::Feature kRegionCaptureExperimentalSubtypes{ + "RegionCaptureExperimentalSubtypes", base::FEATURE_DISABLED_BY_DEFAULT}; + const base::Feature kUserAgentOverrideExperiment{ "UserAgentOverrideExperiment", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/third_party/blink/public/common/features.h b/third_party/blink/public/common/features.h index 9318259c..738b6f6 100644 --- a/third_party/blink/public/common/features.h +++ b/third_party/blink/public/common/features.h
@@ -697,6 +697,11 @@ // which should trigger a zero-copy path in the tab capture code. BLINK_COMMON_EXPORT extern const base::Feature kZeroCopyTabCapture; +// If enabled, the `CropTarget.fromElement()` method will allow for the use +// of additional element tag tyeps, instead of just <div> and <iframe>. +BLINK_COMMON_EXPORT extern const base::Feature + kRegionCaptureExperimentalSubtypes; + // Experiment for measuring how often an overridden User-Agent string is made by // appending or prepending to the original User-Agent string. BLINK_COMMON_EXPORT extern const base::Feature kUserAgentOverrideExperiment;
diff --git a/third_party/blink/public/platform/media/key_system_config_selector.h b/third_party/blink/public/platform/media/key_system_config_selector.h index ccbd576..d5be2c4 100644 --- a/third_party/blink/public/platform/media/key_system_config_selector.h +++ b/third_party/blink/public/platform/media/key_system_config_selector.h
@@ -14,6 +14,7 @@ #include "base/memory/raw_ptr.h" #include "base/memory/weak_ptr.h" #include "media/base/eme_constants.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/blink/public/platform/web_common.h" #include "third_party/blink/public/platform/web_content_settings_client.h" #include "third_party/blink/public/platform/web_media_key_system_media_capability.h" @@ -129,7 +130,7 @@ const std::string& codecs, ConfigState* config_state); - media::EmeConfigRule GetEncryptionSchemeConfigRule( + absl::optional<media::EmeConfigRule> GetEncryptionSchemeConfigRule( const std::string& key_system, const WebMediaKeySystemMediaCapability::EncryptionScheme encryption_scheme);
diff --git a/third_party/blink/public/platform/task_type.h b/third_party/blink/public/platform/task_type.h index 3518c0b9..7466cb15 100644 --- a/third_party/blink/public/platform/task_type.h +++ b/third_party/blink/public/platform/task_type.h
@@ -262,6 +262,9 @@ // Cross-process PostMessage IPCs that are deferred in the current task. kInternalPostMessageForwarding = 79, + // Tasks related to renderer-initiated navigation cancellation. + kInternalNavigationCancellation = 80, + /////////////////////////////////////// // The following task types are only for thread-local queues. /////////////////////////////////////// @@ -289,7 +292,7 @@ kWorkerThreadTaskQueueV8 = 47, kWorkerThreadTaskQueueCompositor = 48, - kMaxValue = kInternalPostMessageForwarding, + kMaxValue = kInternalNavigationCancellation, }; } // namespace blink
diff --git a/third_party/blink/public/web/web_ax_object.h b/third_party/blink/public/web/web_ax_object.h index e8adee42..c1e3c9d2 100644 --- a/third_party/blink/public/web/web_ax_object.h +++ b/third_party/blink/public/web/web_ax_object.h
@@ -132,6 +132,8 @@ BLINK_EXPORT void Serialize(ui::AXNodeData* node_data, ui::AXMode accessibility_mode) const; + BLINK_EXPORT void SerializerClearedNode(int node_id) const; + BLINK_EXPORT ax::mojom::CheckedState CheckedState() const; BLINK_EXPORT bool IsCheckable() const; BLINK_EXPORT bool IsClickable() const; @@ -345,10 +347,9 @@ bool* clips_children = nullptr) const; // Retrieves a vector of all WebAXObjects in this document whose - // bounding boxes may have changed since the last query. Can be called - // on any object. - BLINK_EXPORT void GetAllObjectsWithChangedBounds( - WebVector<WebAXObject>& out_changed_bounds_objects) const; + // bounding boxes may have changed since the last query. Sends that vector + // via mojo to the browser process. + BLINK_EXPORT void SerializeLocationChanges() const; // Exchanges a WebAXObject with another. BLINK_EXPORT void Swap(WebAXObject& other);
diff --git a/third_party/blink/renderer/bindings/scripts/bind_gen/dictionary.py b/third_party/blink/renderer/bindings/scripts/bind_gen/dictionary.py index eac3100b..ea7a3b7 100644 --- a/third_party/blink/renderer/bindings/scripts/bind_gen/dictionary.py +++ b/third_party/blink/renderer/bindings/scripts/bind_gen/dictionary.py
@@ -219,7 +219,7 @@ "${execution_context}->CrossOriginIsolatedCapability();")), S("is_direct_socket_enabled", ("const bool ${is_direct_socket_enabled} = " - "${execution_context}->DirectSocketCapability();")), + "${execution_context}->IsolatedApplicationCapability();")), S("is_in_secure_context", ("const bool ${is_in_secure_context} = " "${execution_context}->IsSecureContext();")),
diff --git a/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py b/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py index 98a5e7a9..0a81c617 100644 --- a/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py +++ b/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py
@@ -4718,7 +4718,7 @@ "${execution_context}->CrossOriginIsolatedCapability();")), S("is_direct_socket_enabled", ("const bool ${is_direct_socket_enabled} = " - "${execution_context}->DirectSocketCapability();")), + "${execution_context}->IsolatedApplicationCapability();")), S("is_in_secure_context", ("const bool ${is_in_secure_context} = " "${execution_context}->IsSecureContext();")),
diff --git a/third_party/blink/renderer/core/css/style_rule.h b/third_party/blink/renderer/core/css/style_rule.h index 1d448a7d..69b2a673 100644 --- a/third_party/blink/renderer/core/css/style_rule.h +++ b/third_party/blink/renderer/core/css/style_rule.h
@@ -427,7 +427,7 @@ const Vector<LayerName>& GetNames() const { return names_; } Vector<String> GetNamesAsStrings() const; - StyleRuleLayerStatement* copy() const { + StyleRuleLayerStatement* Copy() const { return MakeGarbageCollected<StyleRuleLayerStatement>(*this); }
diff --git a/third_party/blink/renderer/core/execution_context/execution_context.h b/third_party/blink/renderer/core/execution_context/execution_context.h index db0a06a..f64cfe50 100644 --- a/third_party/blink/renderer/core/execution_context/execution_context.h +++ b/third_party/blink/renderer/core/execution_context/execution_context.h
@@ -388,10 +388,12 @@ // https://html.spec.whatwg.org/C/webappapis.html#concept-settings-object-cross-origin-isolated-capability virtual bool CrossOriginIsolatedCapability() const = 0; - // Reflects the context's potential ability to use Direct Socket APIs. + // Returns true if scripts within this ExecutionContext are allowed to use + // APIs that require the page to be part of an isolated application. + // https://github.com/reillyeon/isolated-web-apps // // TODO(mkwst): We need a specification for the necessary restrictions. - virtual bool DirectSocketCapability() const = 0; + virtual bool IsolatedApplicationCapability() const = 0; // Returns true if SharedArrayBuffers can be transferred via PostMessage, // false otherwise. SharedArrayBuffer allows pages to craft high-precision
diff --git a/third_party/blink/renderer/core/frame/local_dom_window.cc b/third_party/blink/renderer/core/frame/local_dom_window.cc index 58e09e18..f78c68a 100644 --- a/third_party/blink/renderer/core/frame/local_dom_window.cc +++ b/third_party/blink/renderer/core/frame/local_dom_window.cc
@@ -2243,7 +2243,7 @@ mojom::blink::PermissionsPolicyFeature::kCrossOriginIsolated); } -bool LocalDOMWindow::DirectSocketCapability() const { +bool LocalDOMWindow::IsolatedApplicationCapability() const { return Agent::IsIsolatedApplication(); }
diff --git a/third_party/blink/renderer/core/frame/local_dom_window.h b/third_party/blink/renderer/core/frame/local_dom_window.h index 3d9872cb..9b4aacc3 100644 --- a/third_party/blink/renderer/core/frame/local_dom_window.h +++ b/third_party/blink/renderer/core/frame/local_dom_window.h
@@ -438,7 +438,7 @@ void ClearIsolatedWorldCSPForTesting(int32_t world_id); bool CrossOriginIsolatedCapability() const override; - bool DirectSocketCapability() const override; + bool IsolatedApplicationCapability() const override; // These delegate to the document_. ukm::UkmRecorder* UkmRecorder() override;
diff --git a/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc b/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc index 9bcc47f..580f69e 100644 --- a/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc +++ b/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
@@ -39,7 +39,6 @@ #include "base/metrics/histogram_macros.h" #include "base/numerics/checked_math.h" #include "base/numerics/safe_conversions.h" -#include "base/trace_event/trace_event.h" #include "build/build_config.h" #include "services/metrics/public/cpp/ukm_recorder.h" #include "services/metrics/public/cpp/ukm_source_id.h" @@ -423,7 +422,8 @@ return nullptr; SetNeedsUnbufferedInputEvents(true); frame_dispatcher_ = std::make_unique<CanvasResourceDispatcher>( - nullptr, surface_layer_bridge_->GetFrameSinkId().client_id(), + nullptr, + surface_layer_bridge_->GetFrameSinkId().client_id(), surface_layer_bridge_->GetFrameSinkId().sink_id(), CanvasResourceDispatcher::kInvalidPlaceholderCanvasId, size_); // We don't actually need the begin frame signal when in low latency mode, @@ -745,8 +745,6 @@ SharedGpuContext::ContextProviderWrapper()), kBackBuffer, gfx::ColorSpace::CreateREC709(), std::move(split_callback.first))) { - TRACE_EVENT1("blink", "HTMLCanvasElement::NotifyListenersCanvasChanged", - "OneCopyCanvasCapture", true); continue; } }
diff --git a/third_party/blink/renderer/core/html/html_element.cc b/third_party/blink/renderer/core/html/html_element.cc index 44f2904..8768a07 100644 --- a/third_party/blink/renderer/core/html/html_element.cc +++ b/third_party/blink/renderer/core/html/html_element.cc
@@ -25,6 +25,7 @@ #include "third_party/blink/renderer/core/html/html_element.h" +#include "third_party/blink/public/common/features.h" #include "third_party/blink/renderer/bindings/core/v8/js_event_handler_for_content_attribute.h" #include "third_party/blink/renderer/bindings/core/v8/v8_union_stringtreatnullasemptystring_trustedscript.h" #include "third_party/blink/renderer/core/css/css_color.h" @@ -1181,6 +1182,11 @@ } } +bool HTMLElement::IsSupportedByRegionCapture() const { + return base::FeatureList::IsEnabled( + features::kRegionCaptureExperimentalSubtypes); +} + const AtomicString& HTMLElement::autocapitalize() const { DEFINE_STATIC_LOCAL(const AtomicString, kOff, ("off")); DEFINE_STATIC_LOCAL(const AtomicString, kNone, ("none"));
diff --git a/third_party/blink/renderer/core/html/html_element.h b/third_party/blink/renderer/core/html/html_element.h index e135d75..d1a27d7 100644 --- a/third_party/blink/renderer/core/html/html_element.h +++ b/third_party/blink/renderer/core/html/html_element.h
@@ -180,6 +180,8 @@ // https://html.spec.whatwg.org/C/#potentially-render-blocking virtual bool IsPotentiallyRenderBlocking() const { return false; } + bool IsSupportedByRegionCapture() const override; + protected: enum AllowPercentage { kDontAllowPercentageValues, kAllowPercentageValues }; enum AllowZero { kDontAllowZeroValues, kAllowZeroValues };
diff --git a/third_party/blink/renderer/core/layout/layout_object.cc b/third_party/blink/renderer/core/layout/layout_object.cc index f29b244..62efdaf 100644 --- a/third_party/blink/renderer/core/layout/layout_object.cc +++ b/third_party/blink/renderer/core/layout/layout_object.cc
@@ -2657,12 +2657,6 @@ style_->EffectiveZIndex() != new_style.EffectiveZIndex() || IsStackingContext(*style_) != IsStackingContext(new_style)) { GetDocument().SetAnnotatedRegionsDirty(true); - if (AXObjectCache* cache = GetDocument().ExistingAXObjectCache()) { - if (GetNode()) - cache->ChildrenChanged(GetNode()->parentNode()); - else - cache->ChildrenChanged(Parent()); - } } bool background_color_changed = @@ -2691,8 +2685,13 @@ // tree. if (PaintLayer* layer = EnclosingLayer()) layer->DirtyVisibleContentStatus(); - if (AXObjectCache* cache = GetDocument().ExistingAXObjectCache()) + if (AXObjectCache* cache = GetDocument().ExistingAXObjectCache()) { + if (GetNode()) + cache->ChildrenChanged(GetNode()->parentNode()); + else + cache->ChildrenChanged(Parent()); cache->ChildrenChanged(this); + } GetDocument().GetFrame()->GetInputMethodController().DidChangeVisibility( *this); }
diff --git a/third_party/blink/renderer/core/layout/ng/custom/layout_worklet_global_scope_proxy.cc b/third_party/blink/renderer/core/layout/ng/custom/layout_worklet_global_scope_proxy.cc index 8a655f2..776e6d5 100644 --- a/third_party/blink/renderer/core/layout/ng/custom/layout_worklet_global_scope_proxy.cc +++ b/third_party/blink/renderer/core/layout/ng/custom/layout_worklet_global_scope_proxy.cc
@@ -65,7 +65,7 @@ window->GetAgentClusterID(), ukm::kInvalidSourceId, window->GetExecutionContextToken(), window->CrossOriginIsolatedCapability(), - window->DirectSocketCapability()); + window->IsolatedApplicationCapability()); global_scope_ = LayoutWorkletGlobalScope::Create( frame, std::move(creation_params), *reporting_proxy_, pending_layout_registry);
diff --git a/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h b/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h index 7abd1368..1ce129b0 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h +++ b/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h
@@ -822,7 +822,7 @@ public: // |RareData| unions different types of data which are mutually exclusive. // They fall into the following categories: - enum DataUnionType { + enum class DataUnionType { kNone, kBlockData, // An inflow block which doesn't establish a new FC. kTableCellData, // A table-cell (display: table-cell). @@ -835,7 +835,7 @@ explicit RareData(const NGBfcOffset bfc_offset) : bfc_offset(bfc_offset), - data_union_type(static_cast<unsigned>(kNone)), + data_union_type(static_cast<unsigned>(DataUnionType::kNone)), is_line_clamp_context(false), is_restricted_block_size_table_cell(false), hide_table_cell_if_empty(false), @@ -876,29 +876,29 @@ propagate_child_break_values(other.propagate_child_break_values), is_at_fragmentainer_start(other.is_at_fragmentainer_start), is_repeatable(other.is_repeatable) { - switch (data_union_type) { - case kNone: + switch (GetDataUnionType()) { + case DataUnionType::kNone: break; - case kBlockData: + case DataUnionType::kBlockData: new (&block_data_) BlockData(other.block_data_); break; - case kTableCellData: + case DataUnionType::kTableCellData: new (&table_cell_data_) TableCellData(other.table_cell_data_); break; - case kTableRowData: + case DataUnionType::kTableRowData: new (&table_row_data_) TableRowData(other.table_row_data_); break; - case kTableSectionData: + case DataUnionType::kTableSectionData: new (&table_section_data_) TableSectionData(other.table_section_data_); break; - case kCustomData: + case DataUnionType::kCustomData: new (&custom_data_) CustomData(other.custom_data_); break; - case kStretchData: + case DataUnionType::kStretchData: new (&stretch_data_) StretchData(other.stretch_data_); break; - case kSubgridData: + case DataUnionType::kSubgridData: new (&subgrid_data_) SubgridData(other.subgrid_data_); break; default: @@ -906,28 +906,28 @@ } } ~RareData() { - switch (data_union_type) { - case kNone: + switch (GetDataUnionType()) { + case DataUnionType::kNone: break; - case kBlockData: + case DataUnionType::kBlockData: block_data_.~BlockData(); break; - case kTableCellData: + case DataUnionType::kTableCellData: table_cell_data_.~TableCellData(); break; - case kTableRowData: + case DataUnionType::kTableRowData: table_row_data_.~TableRowData(); break; - case kTableSectionData: + case DataUnionType::kTableSectionData: table_section_data_.~TableSectionData(); break; - case kCustomData: + case DataUnionType::kCustomData: custom_data_.~CustomData(); break; - case kStretchData: + case DataUnionType::kStretchData: stretch_data_.~StretchData(); break; - case kSubgridData: + case DataUnionType::kSubgridData: subgrid_data_.~SubgridData(); break; default: @@ -953,22 +953,22 @@ is_repeatable != other.is_repeatable) return false; - switch (data_union_type) { - case kNone: + switch (GetDataUnionType()) { + case DataUnionType::kNone: return true; - case kBlockData: + case DataUnionType::kBlockData: return block_data_.MaySkipLayout(other.block_data_); - case kTableCellData: + case DataUnionType::kTableCellData: return table_cell_data_.MaySkipLayout(other.table_cell_data_); - case kTableRowData: + case DataUnionType::kTableRowData: return table_row_data_.MaySkipLayout(other.table_row_data_); - case kTableSectionData: + case DataUnionType::kTableSectionData: return table_section_data_.MaySkipLayout(other.table_section_data_); - case kCustomData: + case DataUnionType::kCustomData: return custom_data_.MaySkipLayout(other.custom_data_); - case kStretchData: + case DataUnionType::kStretchData: return stretch_data_.MaySkipLayout(other.stretch_data_); - case kSubgridData: + case DataUnionType::kSubgridData: return subgrid_data_.MaySkipLayout(other.subgrid_data_); } NOTREACHED(); @@ -988,22 +988,22 @@ is_repeatable) return false; - switch (data_union_type) { - case kNone: + switch (GetDataUnionType()) { + case DataUnionType::kNone: return true; - case kBlockData: + case DataUnionType::kBlockData: return block_data_.IsInitialForMaySkipLayout(); - case kTableCellData: + case DataUnionType::kTableCellData: return table_cell_data_.IsInitialForMaySkipLayout(); - case kTableRowData: + case DataUnionType::kTableRowData: return table_row_data_.IsInitialForMaySkipLayout(); - case kTableSectionData: + case DataUnionType::kTableSectionData: return table_section_data_.IsInitialForMaySkipLayout(); - case kCustomData: + case DataUnionType::kCustomData: return custom_data_.IsInitialForMaySkipLayout(); - case kStretchData: + case DataUnionType::kStretchData: return stretch_data_.IsInitialForMaySkipLayout(); - case kSubgridData: + case DataUnionType::kSubgridData: return subgrid_data_.IsInitialForMaySkipLayout(); } NOTREACHED(); @@ -1019,8 +1019,9 @@ } NGMarginStrut MarginStrut() const { - return data_union_type == kBlockData ? block_data_.margin_strut - : NGMarginStrut(); + return GetDataUnionType() == DataUnionType::kBlockData + ? block_data_.margin_strut + : NGMarginStrut(); } void SetMarginStrut(const NGMarginStrut& margin_strut) { @@ -1028,7 +1029,7 @@ } absl::optional<LayoutUnit> OptimisticBfcBlockOffset() const { - return data_union_type == kBlockData + return GetDataUnionType() == DataUnionType::kBlockData ? block_data_.optimistic_bfc_block_offset : absl::nullopt; } @@ -1039,8 +1040,9 @@ } absl::optional<LayoutUnit> ForcedBfcBlockOffset() const { - return data_union_type == kBlockData ? block_data_.forced_bfc_block_offset - : absl::nullopt; + return GetDataUnionType() == DataUnionType::kBlockData + ? block_data_.forced_bfc_block_offset + : absl::nullopt; } void SetForcedBfcBlockOffset(LayoutUnit forced_bfc_block_offset) { @@ -1048,8 +1050,9 @@ } LayoutUnit ClearanceOffset() const { - return data_union_type == kBlockData ? block_data_.clearance_offset - : LayoutUnit::Min(); + return GetDataUnionType() == DataUnionType::kBlockData + ? block_data_.clearance_offset + : LayoutUnit::Min(); } void SetClearanceOffset(LayoutUnit clearance_offset) { @@ -1057,8 +1060,9 @@ } absl::optional<int> LinesUntilClamp() const { - return data_union_type == kBlockData ? block_data_.lines_until_clamp - : absl::nullopt; + return GetDataUnionType() == DataUnionType::kBlockData + ? block_data_.lines_until_clamp + : absl::nullopt; } void SetLinesUntilClamp(int value) { @@ -1066,7 +1070,7 @@ } NGBoxStrut TableCellBorders() const { - return data_union_type == kTableCellData + return GetDataUnionType() == DataUnionType::kTableCellData ? table_cell_data_.table_cell_borders : NGBoxStrut(); } @@ -1076,7 +1080,7 @@ } wtf_size_t TableCellColumnIndex() const { - return data_union_type == kTableCellData + return GetDataUnionType() == DataUnionType::kTableCellData ? table_cell_data_.table_cell_column_index : 0; } @@ -1086,7 +1090,7 @@ } absl::optional<LayoutUnit> TableCellAlignmentBaseline() const { - return data_union_type == kTableCellData + return GetDataUnionType() == DataUnionType::kTableCellData ? table_cell_data_.table_cell_alignment_baseline : absl::nullopt; } @@ -1098,7 +1102,7 @@ } bool IsTableCellHiddenForPaint() const { - return data_union_type == kTableCellData && + return GetDataUnionType() == DataUnionType::kTableCellData && table_cell_data_.is_hidden_for_paint; } @@ -1107,7 +1111,7 @@ } bool IsTableCellWithCollapsedBorders() const { - return data_union_type == kTableCellData && + return GetDataUnionType() == DataUnionType::kTableCellData && table_cell_data_.has_collapsed_borders; } @@ -1131,7 +1135,7 @@ void ReplaceTableRowData(const NGTableConstraintSpaceData& table_data, wtf_size_t row_index) { - DCHECK_EQ(data_union_type, kTableRowData); + DCHECK_EQ(GetDataUnionType(), DataUnionType::kTableRowData); DCHECK( table_data.IsTableSpecificDataEqual(*(table_row_data_.table_data))); DCHECK(table_data.MaySkipRowLayout(*table_row_data_.table_data, row_index, @@ -1141,26 +1145,29 @@ } const NGTableConstraintSpaceData* TableData() { - if (data_union_type == kTableRowData) + if (GetDataUnionType() == DataUnionType::kTableRowData) return table_row_data_.table_data.get(); - if (data_union_type == kTableSectionData) + if (GetDataUnionType() == DataUnionType::kTableSectionData) return table_section_data_.table_data.get(); return nullptr; } wtf_size_t TableRowIndex() const { - return data_union_type == kTableRowData ? table_row_data_.row_index - : kNotFound; + return GetDataUnionType() == DataUnionType::kTableRowData + ? table_row_data_.row_index + : kNotFound; } wtf_size_t TableSectionIndex() const { - return data_union_type == kTableSectionData + return GetDataUnionType() == DataUnionType::kTableSectionData ? table_section_data_.section_index : kNotFound; } SerializedScriptValue* CustomLayoutData() const { - return data_union_type == kCustomData ? custom_data_.data.get() : nullptr; + return GetDataUnionType() == DataUnionType::kCustomData + ? custom_data_.data.get() + : nullptr; } void SetCustomLayoutData( @@ -1169,7 +1176,7 @@ } LayoutUnit TargetStretchInlineSize() const { - return data_union_type == kStretchData + return GetDataUnionType() == DataUnionType::kStretchData ? stretch_data_.target_stretch_inline_size : kIndefiniteSize; } @@ -1181,7 +1188,7 @@ absl::optional<MathTargetStretchBlockSizes> TargetStretchBlockSizes() const { - return data_union_type == kStretchData + return GetDataUnionType() == DataUnionType::kStretchData ? stretch_data_.target_stretch_block_sizes : absl::nullopt; } @@ -1193,7 +1200,7 @@ } const NGGridLayoutTrackCollection* SubgriddedColumns() const { - return data_union_type == kSubgridData + return GetDataUnionType() == DataUnionType::kSubgridData ? subgrid_data_.layout_data.columns.get() : nullptr; } @@ -1204,7 +1211,7 @@ } const NGGridLayoutTrackCollection* SubgriddedRows() const { - return data_union_type == kSubgridData + return GetDataUnionType() == DataUnionType::kSubgridData ? subgrid_data_.layout_data.rows.get() : nullptr; } @@ -1213,6 +1220,10 @@ EnsureSubgridData()->layout_data.rows = std::move(rows); } + DataUnionType GetDataUnionType() const { + return static_cast<DataUnionType>(data_union_type); + } + LogicalSize percentage_resolution_size; LayoutUnit replaced_percentage_resolution_block_size; LayoutUnit block_start_annotation_space; @@ -1361,63 +1372,71 @@ }; BlockData* EnsureBlockData() { - DCHECK(data_union_type == kNone || data_union_type == kBlockData); - if (data_union_type != kBlockData) { - data_union_type = kBlockData; + DCHECK(GetDataUnionType() == DataUnionType::kNone || + GetDataUnionType() == DataUnionType::kBlockData); + if (GetDataUnionType() != DataUnionType::kBlockData) { + data_union_type = static_cast<unsigned>(DataUnionType::kBlockData); new (&block_data_) BlockData(); } return &block_data_; } TableCellData* EnsureTableCellData() { - DCHECK(data_union_type == kNone || data_union_type == kTableCellData); - if (data_union_type != kTableCellData) { - data_union_type = kTableCellData; + DCHECK(GetDataUnionType() == DataUnionType::kNone || + GetDataUnionType() == DataUnionType::kTableCellData); + if (GetDataUnionType() != DataUnionType::kTableCellData) { + data_union_type = static_cast<unsigned>(DataUnionType::kTableCellData); new (&table_cell_data_) TableCellData(); } return &table_cell_data_; } TableRowData* EnsureTableRowData() { - DCHECK(data_union_type == kNone || data_union_type == kTableRowData); - if (data_union_type != kTableRowData) { - data_union_type = kTableRowData; + DCHECK(GetDataUnionType() == DataUnionType::kNone || + GetDataUnionType() == DataUnionType::kTableRowData); + if (GetDataUnionType() != DataUnionType::kTableRowData) { + data_union_type = static_cast<unsigned>(DataUnionType::kTableRowData); new (&table_row_data_) TableRowData(); } return &table_row_data_; } TableSectionData* EnsureTableSectionData() { - DCHECK(data_union_type == kNone || data_union_type == kTableSectionData); - if (data_union_type != kTableSectionData) { - data_union_type = kTableSectionData; + DCHECK(GetDataUnionType() == DataUnionType::kNone || + GetDataUnionType() == DataUnionType::kTableSectionData); + if (GetDataUnionType() != DataUnionType::kTableSectionData) { + data_union_type = + static_cast<unsigned>(DataUnionType::kTableSectionData); new (&table_section_data_) TableSectionData(); } return &table_section_data_; } CustomData* EnsureCustomData() { - DCHECK(data_union_type == kNone || data_union_type == kCustomData); - if (data_union_type != kCustomData) { - data_union_type = kCustomData; + DCHECK(GetDataUnionType() == DataUnionType::kNone || + GetDataUnionType() == DataUnionType::kCustomData); + if (GetDataUnionType() != DataUnionType::kCustomData) { + data_union_type = static_cast<unsigned>(DataUnionType::kCustomData); new (&custom_data_) CustomData(); } return &custom_data_; } StretchData* EnsureStretchData() { - DCHECK(data_union_type == kNone || data_union_type == kStretchData); - if (data_union_type != kStretchData) { - data_union_type = kStretchData; + DCHECK(GetDataUnionType() == DataUnionType::kNone || + GetDataUnionType() == DataUnionType::kStretchData); + if (GetDataUnionType() != DataUnionType::kStretchData) { + data_union_type = static_cast<unsigned>(DataUnionType::kStretchData); new (&stretch_data_) StretchData(); } return &stretch_data_; } SubgridData* EnsureSubgridData() { - DCHECK(data_union_type == kNone || data_union_type == kSubgridData); - if (data_union_type != kSubgridData) { - data_union_type = kSubgridData; + DCHECK(GetDataUnionType() == DataUnionType::kNone || + GetDataUnionType() == DataUnionType::kSubgridData); + if (GetDataUnionType() != DataUnionType::kSubgridData) { + data_union_type = static_cast<unsigned>(DataUnionType::kSubgridData); new (&subgrid_data_) SubgridData(); } return &subgrid_data_;
diff --git a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc index 1bec72d0..29c2bd2 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc
@@ -34,49 +34,6 @@ namespace blink { -namespace { - -bool IsAnonymousContainer(const LayoutObject* layout_object) { - const bool result = layout_object->IsAnonymousBlock() && - layout_object->CanContainAbsolutePositionObjects(); - // There shouldn't be any anonymous container in `NGBlockInInline`. - DCHECK(!(RuntimeEnabledFeatures::LayoutNGBlockInInlineEnabled() && result)); - return result; -} - -// When the containing block is a split inline, Legacy and NG use different -// containers to place the OOF-positioned nodes: -// - Legacy uses the anonymous block generated by inline. -// - NG uses the anonymous' parent block, that contains all the anonymous -// continuations. -// This function finds the correct anonymous parent block. -const LayoutInline* GetOOFContainingBlockFromAnonymous( - const LayoutObject* anonymous_block, - EPosition child_position) { - DCHECK(IsAnonymousContainer(anonymous_block)); - DCHECK(anonymous_block->IsBox()); - - // Comments and code copied from - // LayoutBox::ContainingBlockLogicalWidthForPositioned. - // Ensure we compute our width based on the width of our rel-pos inline - // container rather than any anonymous block created to manage a block-flow - // ancestor of ours in the rel-pos inline's inline flow. - LayoutBoxModelObject* absolute_containing_block = - To<LayoutBox>(anonymous_block)->Continuation(); - // There may be nested parallel inline continuations. We have now found the - // innermost inline (which may not be relatively positioned). Locate the - // inline that serves as the containing block of this box. - while (!absolute_containing_block->CanContainOutOfFlowPositionedElement( - child_position)) { - absolute_containing_block = - To<LayoutBoxModelObject>(absolute_containing_block->Container()); - } - // Make absolute_containing_block continuation root. - return To<LayoutInline>(absolute_containing_block->ContinuationRoot()); -} - -} // namespace - NGOutOfFlowLayoutPart::NGOutOfFlowLayoutPart( const NGBlockNode& container_node, const NGConstraintSpace& container_space, @@ -153,37 +110,6 @@ clear_scope(&candidates); container_builder_->SwapOutOfFlowPositionedCandidates(&candidates); - // Special case: containing block is a split inline. - // If current container was generated by a split inline, do not position - // OOF-positioned nodes inside this container. Let its non-anonymous parent - // handle it. Only the parent has geometry information needed to compute - // containing block geometry. - // See "Special case: oof css container" comment for detailed description. - if (candidates.size() > 0 && current_container && !only_layout && - IsAnonymousContainer(current_container)) { - const LayoutInline* absolute_containing_block = - is_absolute_container_ ? GetOOFContainingBlockFromAnonymous( - current_container, EPosition::kAbsolute) - : nullptr; - const LayoutInline* fixed_containing_block = - is_fixed_container_ ? GetOOFContainingBlockFromAnonymous( - current_container, EPosition::kFixed) - : nullptr; - for (auto& candidate : candidates) { - if (absolute_containing_block && - absolute_containing_block->CanContainOutOfFlowPositionedElement( - candidate.Node().Style().GetPosition())) { - candidate.inline_container.container = absolute_containing_block; - } else if (fixed_containing_block && - fixed_containing_block->CanContainOutOfFlowPositionedElement( - candidate.Node().Style().GetPosition())) { - candidate.inline_container.container = fixed_containing_block; - } - container_builder_->AddOutOfFlowDescendant(candidate); - } - return; - } - HeapHashSet<Member<const LayoutObject>> placed_objects; LayoutCandidates(&candidates, only_layout, &placed_objects); @@ -320,15 +246,9 @@ container_builder_->Borders() + container_builder_->Scrollbar(), container_builder_); - const LayoutObject* css_container = layout_box->Container(); - if (IsAnonymousContainer(css_container)) { - css_container = GetOOFContainingBlockFromAnonymous( - css_container, layout_box->Style()->GetPosition()); - } - container_builder_->AddOutOfFlowLegacyCandidate( NGBlockNode(layout_box), static_position, - DynamicTo<LayoutInline>(css_container)); + DynamicTo<LayoutInline>(layout_box->Container())); candidate_added = true; } return candidate_added;
diff --git a/third_party/blink/renderer/core/paint/box_painter_base.cc b/third_party/blink/renderer/core/paint/box_painter_base.cc index da7aba3..d5607b5 100644 --- a/third_party/blink/renderer/core/paint/box_painter_base.cc +++ b/third_party/blink/renderer/core/paint/box_painter_base.cc
@@ -837,11 +837,26 @@ auto image_auto_dark_mode = ImageClassifierHelper::GetImageAutoDarkMode( *document->GetFrame(), style, image_border.Rect(), src_rect); + + Image::ImageClampingMode clamping_mode = + Image::ImageClampingMode::kClampImageToSourceRect; + + // If the intended snapped background image is the whole tile, do not clamp + // the source rect. This allows mipmaps and filtering to read beyond the + // final adjusted source rect even if snapping and scaling means it's subset. + // However, this detects and preserves clamping to the source rect for sprite + // sheet background images. + if (geometry.TileSize().width == geometry.SnappedDestRect().Width() && + geometry.TileSize().height == geometry.SnappedDestRect().Height()) { + clamping_mode = Image::ImageClampingMode::kDoNotClampImageToSourceRect; + } + // Since there is no way for the developer to specify decode behavior, use // kSync by default. context.DrawImageRRect(image, Image::kSyncDecode, image_auto_dark_mode, image_border, src_rect, composite_op, - info.respect_image_orientation, may_be_lcp_candidate); + info.respect_image_orientation, may_be_lcp_candidate, + clamping_mode); return true; }
diff --git a/third_party/blink/renderer/core/paint/box_painter_test.cc b/third_party/blink/renderer/core/paint/box_painter_test.cc index ec8190d4..b7e03ce10 100644 --- a/third_party/blink/renderer/core/paint/box_painter_test.cc +++ b/third_party/blink/renderer/core/paint/box_painter_test.cc
@@ -277,4 +277,41 @@ // This should not crash. } +size_t CountDrawImagesWithConstraint(const cc::PaintOpBuffer* buffer, + SkCanvas::SrcRectConstraint constraint) { + size_t count = 0; + for (cc::PaintOpBuffer::Iterator it(buffer); it; ++it) { + if (it->GetType() == cc::PaintOpType::DrawImageRect) { + auto* image_op = static_cast<cc::DrawImageRectOp*>(*it); + if (image_op->constraint == constraint) + ++count; + } else if (it->GetType() == cc::PaintOpType::DrawRecord) { + auto* record_op = static_cast<cc::DrawRecordOp*>(*it); + count += + CountDrawImagesWithConstraint(record_op->record.get(), constraint); + } + } + return count; +} + +TEST_P(BoxPainterTest, ImageClampingMode) { + SetBodyInnerHTML(R"HTML( + <!doctype html> + <style> + div#test { + height: 500px; + width: 353.743px; + background-image: url("data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="); + background-size: contain; + background-repeat: no-repeat; + } + </style> + <div id="test"></div> + )HTML"); + + sk_sp<PaintRecord> record = GetDocument().View()->GetPaintRecord(); + EXPECT_EQ(1U, CountDrawImagesWithConstraint( + record.get(), SkCanvas::kFast_SrcRectConstraint)); +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc b/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc index cf6bd9dc..9727c598 100644 --- a/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc +++ b/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
@@ -1704,7 +1704,9 @@ // This must be computed before std::move(state) below. bool needs_pixel_moving_filter_clip_expander = - state.direct_compositing_reasons != CompositingReason::kNone || + (state.direct_compositing_reasons & + (CompositingReason::kWillChangeFilter | + CompositingReason::kActiveFilterAnimation)) || state.filter.HasFilterThatMovesPixels(); EffectPaintPropertyNode::AnimationState animation_state;
diff --git a/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc b/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc index 3ffc99f..dbbfdef 100644 --- a/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc +++ b/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc
@@ -4951,6 +4951,35 @@ clip->PaintClipRect().Rect()); } +TEST_P(PaintPropertyTreeBuilderTest, SimpleFilterWithWillChangeTransform) { + SetBodyInnerHTML(R"HTML( + <div id='filter' style='filter:opacity(0.5); height:1000px; + will-change: transform'>" + </div> + )HTML"); + + auto* properties = PaintPropertiesForElement("filter"); + ASSERT_TRUE(properties); + auto* filter = properties->Filter(); + ASSERT_TRUE(filter); + EXPECT_TRUE(filter->HasDirectCompositingReasons()); + EXPECT_FALSE(properties->PixelMovingFilterClipExpander()); +} + +TEST_P(PaintPropertyTreeBuilderTest, WillChangeFilterCreatesClipExpander) { + SetBodyInnerHTML( + "<div id='filter' style='height:1000px; will-change: filter'>"); + + auto* properties = PaintPropertiesForElement("filter"); + ASSERT_TRUE(properties); + auto* filter = properties->Filter(); + ASSERT_TRUE(filter); + EXPECT_TRUE(filter->HasDirectCompositingReasons()); + auto* clip_expander = properties->PixelMovingFilterClipExpander(); + ASSERT_TRUE(clip_expander); + EXPECT_EQ(filter, clip_expander->PixelMovingFilter()); +} + TEST_P(PaintPropertyTreeBuilderTest, FilterReparentClips) { SetBodyInnerHTML(R"HTML( <div id='clip' style='overflow:hidden;'>
diff --git a/third_party/blink/renderer/core/testing/null_execution_context.h b/third_party/blink/renderer/core/testing/null_execution_context.h index fee0a5fb..d5195aff 100644 --- a/third_party/blink/renderer/core/testing/null_execution_context.h +++ b/third_party/blink/renderer/core/testing/null_execution_context.h
@@ -50,7 +50,7 @@ ResourceFetcher* Fetcher() override { return nullptr; } bool CrossOriginIsolatedCapability() const override { return false; } - bool DirectSocketCapability() const override { return false; } + bool IsolatedApplicationCapability() const override { return false; } ukm::UkmRecorder* UkmRecorder() override { return nullptr; } ukm::SourceId UkmSourceID() const override { return ukm::kInvalidSourceId; } FrameOrWorkerScheduler* GetScheduler() override;
diff --git a/third_party/blink/renderer/core/workers/dedicated_worker.cc b/third_party/blink/renderer/core/workers/dedicated_worker.cc index 59f02b8f..e69aa4f 100644 --- a/third_party/blink/renderer/core/workers/dedicated_worker.cc +++ b/third_party/blink/renderer/core/workers/dedicated_worker.cc
@@ -484,7 +484,7 @@ execution_context->GetAgentClusterID(), execution_context->UkmSourceID(), execution_context->GetExecutionContextToken(), execution_context->CrossOriginIsolatedCapability(), - execution_context->DirectSocketCapability()); + execution_context->IsolatedApplicationCapability()); } scoped_refptr<WebWorkerFetchContext>
diff --git a/third_party/blink/renderer/core/workers/dedicated_worker_global_scope.h b/third_party/blink/renderer/core/workers/dedicated_worker_global_scope.h index 3765eda..abe17da9 100644 --- a/third_party/blink/renderer/core/workers/dedicated_worker_global_scope.h +++ b/third_party/blink/renderer/core/workers/dedicated_worker_global_scope.h
@@ -161,7 +161,7 @@ bool CrossOriginIsolatedCapability() const final { return cross_origin_isolated_capability_; } - bool DirectSocketCapability() const final { + bool IsolatedApplicationCapability() const final { return direct_socket_capability_; } ExecutionContextToken GetExecutionContextToken() const final {
diff --git a/third_party/blink/renderer/core/workers/shared_worker_global_scope.cc b/third_party/blink/renderer/core/workers/shared_worker_global_scope.cc index 20ab7cc..608dbbc 100644 --- a/third_party/blink/renderer/core/workers/shared_worker_global_scope.cc +++ b/third_party/blink/renderer/core/workers/shared_worker_global_scope.cc
@@ -308,7 +308,7 @@ return Agent::IsCrossOriginIsolated(); } -bool SharedWorkerGlobalScope::DirectSocketCapability() const { +bool SharedWorkerGlobalScope::IsolatedApplicationCapability() const { return Agent::IsIsolatedApplication(); }
diff --git a/third_party/blink/renderer/core/workers/shared_worker_global_scope.h b/third_party/blink/renderer/core/workers/shared_worker_global_scope.h index 8e92d161..80ec193 100644 --- a/third_party/blink/renderer/core/workers/shared_worker_global_scope.h +++ b/third_party/blink/renderer/core/workers/shared_worker_global_scope.h
@@ -97,7 +97,7 @@ const SharedWorkerToken& GetSharedWorkerToken() const { return token_; } WorkerToken GetWorkerToken() const final { return token_; } bool CrossOriginIsolatedCapability() const final; - bool DirectSocketCapability() const final; + bool IsolatedApplicationCapability() const final; ExecutionContextToken GetExecutionContextToken() const final { return token_; }
diff --git a/third_party/blink/renderer/core/workers/threaded_worklet_messaging_proxy.cc b/third_party/blink/renderer/core/workers/threaded_worklet_messaging_proxy.cc index 401950a8..da59d7b0e 100644 --- a/third_party/blink/renderer/core/workers/threaded_worklet_messaging_proxy.cc +++ b/third_party/blink/renderer/core/workers/threaded_worklet_messaging_proxy.cc
@@ -91,7 +91,7 @@ window->GetAgentClusterID(), ukm::kInvalidSourceId, window->GetExecutionContextToken(), window->CrossOriginIsolatedCapability(), - window->DirectSocketCapability()); + window->IsolatedApplicationCapability()); // Worklets share the pre-initialized backing thread so that we don't have to // specify the backing thread startup data.
diff --git a/third_party/blink/renderer/core/workers/worker_thread_test_helper.h b/third_party/blink/renderer/core/workers/worker_thread_test_helper.h index e4c32551..a635553 100644 --- a/third_party/blink/renderer/core/workers/worker_thread_test_helper.h +++ b/third_party/blink/renderer/core/workers/worker_thread_test_helper.h
@@ -107,7 +107,7 @@ // Returns a token uniquely identifying this fake worker. WorkerToken GetWorkerToken() const final { return token_; } bool CrossOriginIsolatedCapability() const final { return false; } - bool DirectSocketCapability() const final { return false; } + bool IsolatedApplicationCapability() const final { return false; } ExecutionContextToken GetExecutionContextToken() const final { return token_; }
diff --git a/third_party/blink/renderer/core/workers/worklet_global_scope.cc b/third_party/blink/renderer/core/workers/worklet_global_scope.cc index 7003eed..30ba1ad 100644 --- a/third_party/blink/renderer/core/workers/worklet_global_scope.cc +++ b/third_party/blink/renderer/core/workers/worklet_global_scope.cc
@@ -308,7 +308,7 @@ return parent_cross_origin_isolated_capability_; } -bool WorkletGlobalScope::DirectSocketCapability() const { +bool WorkletGlobalScope::IsolatedApplicationCapability() const { return parent_direct_socket_capability_; }
diff --git a/third_party/blink/renderer/core/workers/worklet_global_scope.h b/third_party/blink/renderer/core/workers/worklet_global_scope.h index e5b63822..f60583a8 100644 --- a/third_party/blink/renderer/core/workers/worklet_global_scope.h +++ b/third_party/blink/renderer/core/workers/worklet_global_scope.h
@@ -67,7 +67,7 @@ scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner(TaskType) final; FrameOrWorkerScheduler* GetScheduler() final; bool CrossOriginIsolatedCapability() const final; - bool DirectSocketCapability() const final; + bool IsolatedApplicationCapability() const final; ukm::UkmRecorder* UkmRecorder() final; ukm::SourceId UkmSourceID() const final;
diff --git a/third_party/blink/renderer/modules/accessibility/DEPS b/third_party/blink/renderer/modules/accessibility/DEPS index 50948449..73a2f60 100644 --- a/third_party/blink/renderer/modules/accessibility/DEPS +++ b/third_party/blink/renderer/modules/accessibility/DEPS
@@ -13,4 +13,5 @@ "+ui/accessibility/ax_mode.h", "+ui/accessibility/ax_node_data.h", "+ui/accessibility/ax_role_properties.h", + "+ui/accessibility/mojom/ax_relative_bounds.mojom-blink.h" ]
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object.cc b/third_party/blink/renderer/modules/accessibility/ax_object.cc index 94ad63ca..bb3f318 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_object.cc +++ b/third_party/blink/renderer/modules/accessibility/ax_object.cc
@@ -56,6 +56,7 @@ #include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/frame/local_frame_view.h" #include "third_party/blink/renderer/core/frame/settings.h" +#include "third_party/blink/renderer/core/frame/visual_viewport.h" #include "third_party/blink/renderer/core/fullscreen/fullscreen.h" #include "third_party/blink/renderer/core/html/canvas/html_canvas_element.h" #include "third_party/blink/renderer/core/html/custom/element_internals.h" @@ -1242,6 +1243,9 @@ // Always try to serialize child tree ids. SerializeChildTreeID(node_data); + if (!accessibility_mode.has_mode(ui::AXMode::kPDF)) + SerializeBoundingBoxAttributes(*node_data); + // Return early. The following attributes are unnecessary for ignored nodes. // Exception: focusable ignored nodes are fully serialized, so that reasonable // verbalizations can be made if they actually receive focus. @@ -1282,6 +1286,50 @@ SerializeOtherScreenReaderAttributes(node_data); } +void AXObject::SerializeBoundingBoxAttributes(ui::AXNodeData& dst) const { + bool clips_children = false; + PopulateAXRelativeBounds(dst.relative_bounds, &clips_children); + if (clips_children) { + dst.AddBoolAttribute(ax::mojom::blink::BoolAttribute::kClipsChildren, true); + } + + if (IsLineBreakingObject()) { + dst.AddBoolAttribute(ax::mojom::blink::BoolAttribute::kIsLineBreakingObject, + true); + } + AXObjectCache().SetCachedBoundingBox(AXObjectID(), dst.relative_bounds); +} + +static bool AXShouldIncludePageScaleFactorInRoot() { +#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_MAC) + return true; +#else + return false; +#endif +} + +void AXObject::PopulateAXRelativeBounds(ui::AXRelativeBounds& bounds, + bool* clips_children) const { + AXObject* offset_container; + gfx::RectF bounds_in_container; + gfx::Transform container_transform; + GetRelativeBounds(&offset_container, bounds_in_container, container_transform, + clips_children); + bounds.bounds = bounds_in_container; + if (offset_container && !offset_container->IsDetached()) + bounds.offset_container_id = offset_container->AXObjectID(); + + if (AXShouldIncludePageScaleFactorInRoot() && IsRoot()) { + const Page* page = GetDocument()->GetPage(); + container_transform.Scale(page->PageScaleFactor(), page->PageScaleFactor()); + container_transform.Translate( + -page->GetVisualViewport().VisibleRect().origin().OffsetFromOrigin()); + } + + if (!container_transform.IsIdentity()) + bounds.transform = std::make_unique<gfx::Transform>(container_transform); +} + void AXObject::SerializeActionAttributes(ui::AXNodeData* node_data) { if (CanSetValueAttribute()) node_data->AddAction(ax::mojom::blink::Action::kSetValue);
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object.h b/third_party/blink/renderer/modules/accessibility/ax_object.h index b01effb4..5f0e915 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_object.h +++ b/third_party/blink/renderer/modules/accessibility/ax_object.h
@@ -63,6 +63,7 @@ namespace ui { struct AXActionData; struct AXNodeData; +struct AXRelativeBounds; } namespace blink { @@ -1330,6 +1331,9 @@ // used during UpdateCachedValuesIfNecessary() without causing recursion. String ToString(bool verbose = false, bool cached_values_only = false) const; + void PopulateAXRelativeBounds(ui::AXRelativeBounds& bounds, + bool* clips_children) const; + protected: AXID id_; // Any parent, regardless of whether it's ignored or not included in the tree. @@ -1396,6 +1400,7 @@ const AXObject* TableParent() const; // Helpers for serialization. + void SerializeBoundingBoxAttributes(ui::AXNodeData& dst) const; void SerializeActionAttributes(ui::AXNodeData* node_data); void SerializeChildTreeID(ui::AXNodeData* node_data); void SerializeChooserPopupAttributes(ui::AXNodeData* node_data);
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc index 27292d7e..4cf9eb95 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc +++ b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc
@@ -36,6 +36,7 @@ #include "mojo/public/cpp/bindings/pending_remote.h" #include "third_party/blink/public/mojom/permissions/permission.mojom-blink.h" #include "third_party/blink/public/mojom/permissions/permission_status.mojom-blink.h" +#include "third_party/blink/public/mojom/render_accessibility.mojom-blink.h" #include "third_party/blink/public/platform/task_type.h" #include "third_party/blink/public/web/web_local_frame_client.h" #include "third_party/blink/renderer/core/accessibility/scoped_blink_ax_event_intent.h" @@ -48,6 +49,7 @@ #include "third_party/blink/renderer/core/editing/markers/document_marker_controller.h" #include "third_party/blink/renderer/core/events/event_util.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/frame/local_frame_view.h" #include "third_party/blink/renderer/core/frame/settings.h" #include "third_party/blink/renderer/core/frame/web_local_frame_impl.h" @@ -105,6 +107,7 @@ #include "ui/accessibility/ax_enums.mojom-blink.h" #include "ui/accessibility/ax_event.h" #include "ui/accessibility/ax_role_properties.h" +#include "ui/accessibility/mojom/ax_relative_bounds.mojom-blink.h" // Prevent code that runs during the lifetime of the stack from altering the // document lifecycle. Usually doc is the same as document_, but it can be @@ -3671,16 +3674,43 @@ return active_aria_modal_dialog_; } -HeapVector<Member<AXObject>> -AXObjectCacheImpl::GetAllObjectsWithChangedBounds() { - VectorOf<AXObject> changed_bounds_objects; - changed_bounds_objects.ReserveCapacity(changed_bounds_ids_.size()); +void AXObjectCacheImpl::SerializeLocationChanges() { + if (changed_bounds_ids_.IsEmpty()) + return; + Vector<mojom::blink::LocationChangesPtr> changes; + changes.ReserveCapacity(changed_bounds_ids_.size()); for (AXID changed_bounds_id : changed_bounds_ids_) { - if (AXObject* obj = ObjectFromAXID(changed_bounds_id)) - changed_bounds_objects.push_back(obj); + if (AXObject* obj = ObjectFromAXID(changed_bounds_id)) { + // Only update locations that are already known. + auto bounds = cached_bounding_boxes_.find(changed_bounds_id); + if (bounds == cached_bounding_boxes_.end()) + continue; + + ui::AXRelativeBounds new_location; + bool clips_children; + obj->PopulateAXRelativeBounds(new_location, &clips_children); + if (bounds->value == new_location) + continue; + + cached_bounding_boxes_.Set(changed_bounds_id, new_location); + changes.push_back( + mojom::blink::LocationChanges::New(changed_bounds_id, new_location)); + } } changed_bounds_ids_.clear(); - return changed_bounds_objects; + if (!changes.IsEmpty()) { + GetOrCreateRemoteRenderAccessibilityHost()->HandleAXLocationChanges( + std::move(changes)); + } +} + +mojo::Remote<blink::mojom::blink::RenderAccessibilityHost>& +AXObjectCacheImpl::GetOrCreateRemoteRenderAccessibilityHost() { + if (!render_accessibility_host_) { + GetDocument().GetFrame()->GetBrowserInterfaceBroker().GetInterface( + render_accessibility_host_.BindNewPipeAndPassReceiver()); + } + return render_accessibility_host_; } void AXObjectCacheImpl::HandleInitialFocus() { @@ -3905,8 +3935,19 @@ void AXObjectCacheImpl::InvalidateBoundingBox( const LayoutObject* layout_object) { - if (AXObject* obj = Get(const_cast<LayoutObject*>(layout_object))) + if (AXObject* obj = Get(const_cast<LayoutObject*>(layout_object))) { changed_bounds_ids_.insert(obj->AXObjectID()); + } +} + +void AXObjectCacheImpl::SetCachedBoundingBox( + AXID id, + const ui::AXRelativeBounds& bounds) { + cached_bounding_boxes_.Set(id, bounds); +} + +void AXObjectCacheImpl::SerializerClearedNode(AXID id) { + cached_bounding_boxes_.erase(id); } void AXObjectCacheImpl::HandleScrollPositionChanged(
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h index 6abf2c4..b5621d0 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h +++ b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h
@@ -37,6 +37,7 @@ #include "third_party/blink/public/mojom/permissions/permission.mojom-blink.h" #include "third_party/blink/public/mojom/permissions/permission_status.mojom-blink-forward.h" #include "third_party/blink/public/mojom/permissions/permission_status.mojom-blink.h" +#include "third_party/blink/public/mojom/render_accessibility.mojom-blink.h" #include "third_party/blink/public/web/web_ax_enums.h" #include "third_party/blink/renderer/core/accessibility/ax_object_cache_base.h" #include "third_party/blink/renderer/core/accessibility/blink_ax_event_intent.h" @@ -197,9 +198,13 @@ void HandleFrameRectsChanged(Document&) override; // Invalidates the bounding box, which can be later retrieved by - // GetAllObjectsWithChangedBounds. + // SerializeLocationChanges. void InvalidateBoundingBox(const LayoutObject*) override; + void SetCachedBoundingBox(AXID id, const ui::AXRelativeBounds& bounds); + + void SerializerClearedNode(AXID id); + const AtomicString& ComputedRoleForNode(Node*) override; String ComputedNameForNode(Node*) override; @@ -364,9 +369,10 @@ bool HasBeenDisposed() { return has_been_disposed_; } // Retrieves a vector of all AXObjects whose bounding boxes may have changed - // since the last query. Clears the vector so that the next time it's + // since the last query. Sends the resulting vector over mojo to the browser + // process. Clears the vector so that the next time it's // called, it will only retrieve objects that have changed since now. - HeapVector<Member<AXObject>> GetAllObjectsWithChangedBounds(); + void SerializeLocationChanges(); static constexpr int kDataTableHeuristicMinRows = 20; @@ -405,6 +411,9 @@ void Remove(AXID); private: + mojo::Remote<mojom::blink::RenderAccessibilityHost>& + GetOrCreateRemoteRenderAccessibilityHost(); + HeapHashSet<WeakMember<InspectorAccessibilityAgent>> agents_; struct AXEventParams final : public GarbageCollected<AXEventParams> { @@ -630,7 +639,7 @@ // Invalidates the bounding boxes of fixed or sticky positioned objects which // should be updated when the scroll offset is changed. Like // InvalidateBoundingBox, it can be later retrieved by - // GetAllObjectsWithChangedBounds. + // SerializeLocationChanges. void InvalidateBoundingBoxForFixedOrStickyPosition(); // Return true if this is the popup document. There can only be one popup @@ -675,9 +684,13 @@ HashMap<AXID, WebAXAutofillState> autofill_state_map_; // The set of node IDs whose bounds has changed since the last time - // GetAllObjectsWithChangedBounds was called. + // SerializeLocationChanges was called. HashSet<AXID> changed_bounds_ids_; + // Known locations and sizes of bounding boxes that are known to have been + // serialized. + HashMap<AXID, ui::AXRelativeBounds> cached_bounding_boxes_; + // The list of node IDs whose position is fixed or sticky. HashSet<AXID> fixed_or_sticky_node_ids_; @@ -703,6 +716,9 @@ // instead. static bool use_ax_menu_list_; + mojo::Remote<mojom::blink::RenderAccessibilityHost> + render_accessibility_host_; + FRIEND_TEST_ALL_PREFIXES(AccessibilityTest, PauseUpdatesAfterMaxNumberQueued); };
diff --git a/third_party/blink/renderer/modules/csspaint/paint_worklet_global_scope_proxy.cc b/third_party/blink/renderer/modules/csspaint/paint_worklet_global_scope_proxy.cc index 91e5d3a2..7e43d92a 100644 --- a/third_party/blink/renderer/modules/csspaint/paint_worklet_global_scope_proxy.cc +++ b/third_party/blink/renderer/modules/csspaint/paint_worklet_global_scope_proxy.cc
@@ -63,7 +63,7 @@ window->GetAgentClusterID(), ukm::kInvalidSourceId, window->GetExecutionContextToken(), window->CrossOriginIsolatedCapability(), - window->DirectSocketCapability()); + window->IsolatedApplicationCapability()); global_scope_ = PaintWorkletGlobalScope::Create( frame, std::move(creation_params), *reporting_proxy_); }
diff --git a/third_party/blink/renderer/modules/exported/web_ax_object.cc b/third_party/blink/renderer/modules/exported/web_ax_object.cc index 029783a..6216ae8 100644 --- a/third_party/blink/renderer/modules/exported/web_ax_object.cc +++ b/third_party/blink/renderer/modules/exported/web_ax_object.cc
@@ -238,6 +238,10 @@ private_->Serialize(node_data, accessibility_mode); } +BLINK_EXPORT void WebAXObject::SerializerClearedNode(int node_id) const { + private_->AXObjectCache().SerializerClearedNode(node_id); +} + WebString WebAXObject::AutoComplete() const { if (IsDetached()) return WebString(); @@ -1142,18 +1146,11 @@ bounds_in_container = bounds; } -void WebAXObject::GetAllObjectsWithChangedBounds( - WebVector<WebAXObject>& out_changed_bounds_objects) const { +void WebAXObject::SerializeLocationChanges() const { if (IsDetached()) return; - HeapVector<Member<AXObject>> changed_bounds_objects = - private_->AXObjectCache().GetAllObjectsWithChangedBounds(); - - out_changed_bounds_objects.reserve(changed_bounds_objects.size()); - out_changed_bounds_objects.resize(changed_bounds_objects.size()); - std::copy(changed_bounds_objects.begin(), changed_bounds_objects.end(), - out_changed_bounds_objects.begin()); + private_->AXObjectCache().SerializeLocationChanges(); } bool WebAXObject::ScrollToMakeVisible() const {
diff --git a/third_party/blink/renderer/modules/mediastream/media_devices_test.cc b/third_party/blink/renderer/modules/mediastream/media_devices_test.cc index 3999cf9..97b0b53a 100644 --- a/third_party/blink/renderer/modules/mediastream/media_devices_test.cc +++ b/third_party/blink/renderer/modules/mediastream/media_devices_test.cc
@@ -7,11 +7,13 @@ #include <memory> #include <utility> +#include "base/test/scoped_feature_list.h" #include "build/build_config.h" #include "mojo/public/cpp/bindings/receiver.h" #include "mojo/public/cpp/bindings/remote.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/public/common/features.h" #include "third_party/blink/public/mojom/media/capture_handle_config.mojom-blink.h" #include "third_party/blink/renderer/bindings/core/v8/script_function.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise.h" @@ -256,8 +258,11 @@ public: using MediaDeviceInfos = HeapVector<Member<MediaDeviceInfo>>; - MediaDevicesTest() : device_infos_(MakeGarbageCollected<MediaDeviceInfos>()) { - dispatcher_host_ = std::make_unique<MockMediaDevicesDispatcherHost>(); + MediaDevicesTest() + : dispatcher_host_(std::make_unique<MockMediaDevicesDispatcherHost>()), + device_infos_(MakeGarbageCollected<MediaDeviceInfos>()) { + scoped_feature_list_.InitAndEnableFeature( + blink::features::kRegionCaptureExperimentalSubtypes); } MediaDevices* GetMediaDevices(LocalDOMWindow& window) { @@ -323,6 +328,10 @@ return *dispatcher_host_; } + base::test::ScopedFeatureList& scoped_feature_list() { + return scoped_feature_list_; + } + private: ScopedTestingPlatformSupport<TestingPlatformSupport> platform_; std::unique_ptr<MockMediaDevicesDispatcherHost> dispatcher_host_; @@ -332,6 +341,7 @@ bool device_changed_ = false; bool listener_connection_error_ = false; Persistent<MediaDevices> media_devices_; + base::test::ScopedFeatureList scoped_feature_list_; }; TEST_F(MediaDevicesTest, GetUserMediaCanBeCalled) { @@ -755,23 +765,38 @@ SetBodyContent(R"HTML( <div id='test-div'></div> - <iframe id='test-iframe' src="about:blank" /> + <iframe id='test-iframe' src="about:blank"></iframe> + <p id='test-p'> + <var id='test-var'>e</var> equals mc<sup id='test-sup'>2</sup>, or is + <wbr id='test-wbr'>it mc<sub id='test-sub'>2</sub>? + <u id='test-u'>probz</u>. + </p> + <select id='test-select'> + <optgroup label="Bar" id='test-optgroup'> + <option value="foo" id='test-option'>Foo</option> + </optgroup> + </select> )HTML"); Document& document = GetDocument(); - Element* const div = document.getElementById("test-div"); - const ScriptPromise div_promise = media_devices->ProduceCropTarget( - scope.GetScriptState(), div, scope.GetExceptionState()); - platform()->RunUntilIdle(); - EXPECT_FALSE(div_promise.IsEmpty()); - EXPECT_FALSE(scope.GetExceptionState().HadException()); + static const std::vector<const char*> kElementIds{ + "test-div", "test-iframe", "test-p", "test-var", + "test-sup", "test-wbr", "test-sub", "test-u", + "test-select", "test-optgroup", "test-option"}; - Element* const iframe = document.getElementById("test-iframe"); - const ScriptPromise iframe_promise = media_devices->ProduceCropTarget( - scope.GetScriptState(), iframe, scope.GetExceptionState()); - platform()->RunUntilIdle(); - EXPECT_FALSE(iframe_promise.IsEmpty()); - EXPECT_FALSE(scope.GetExceptionState().HadException()); + for (const char* id : kElementIds) { + Element* const element = document.getElementById(id); + dispatcher_host().SetNextCropId( + String(base::GUID::GenerateRandomV4().AsLowercaseString())); + const ScriptPromise promise = media_devices->ProduceCropTarget( + scope.GetScriptState(), element, scope.GetExceptionState()); + + ScriptPromiseTester script_promise_tester(scope.GetScriptState(), promise); + script_promise_tester.WaitUntilSettled(); + EXPECT_TRUE(script_promise_tester.IsFulfilled()) + << "Failed promise for element id=" << id; + EXPECT_FALSE(scope.GetExceptionState().HadException()); + } } TEST_F(MediaDevicesTest, ProduceCropIdRejectedIfUnsupportedElementType) { @@ -779,7 +804,9 @@ auto* media_devices = GetMediaDevices(*GetDocument().domWindow()); ASSERT_TRUE(media_devices); - // At the moment, buttons are unsupported by Region Capture. + // Currently if the experimental subtypes feature is not enabled, only + // <div> and <iframe> are supported. + scoped_feature_list().Reset(); SetBodyContent(R"HTML( <button id='test-button'>Click!</button> )HTML");
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc index dbf8a20e..a860da8 100644 --- a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc +++ b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc
@@ -148,7 +148,8 @@ "The SDP does not match the previously generated SDP for this type"; base::LazyInstance<RTCPeerConnection::RtcPeerConnectionHandlerFactoryCallback>:: - Leaky g_create_rpc_peer_connection_handler_callback_; + Leaky g_create_rpc_peer_connection_handler_callback_ = + LAZY_INSTANCE_INITIALIZER; // The maximum number of PeerConnections that can exist simultaneously. const int64_t kMaxPeerConnections = 500;
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc index 73da5925..675253a3 100644 --- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc +++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc
@@ -791,7 +791,7 @@ return Agent::IsCrossOriginIsolated(); } -bool ServiceWorkerGlobalScope::DirectSocketCapability() const { +bool ServiceWorkerGlobalScope::IsolatedApplicationCapability() const { // TODO(mkwst): Make a decision here, and spec it. return false; }
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h index d815400..5a74e1a 100644 --- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h +++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h
@@ -314,7 +314,7 @@ const ServiceWorkerToken& GetServiceWorkerToken() const { return token_; } WorkerToken GetWorkerToken() const final { return token_; } bool CrossOriginIsolatedCapability() const final; - bool DirectSocketCapability() const final; + bool IsolatedApplicationCapability() const final; ExecutionContextToken GetExecutionContextToken() const final { return token_; }
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.cc b/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.cc index fa33a58..cf60e3d 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.cc +++ b/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.cc
@@ -261,15 +261,6 @@ texture_->GetHandle(), swap_buffers_->Size(), resource_provider); } -bool GPUCanvasContext::CopyRenderingResultsToVideoFrame( - WebGraphicsContext3DVideoFramePool* frame_pool, - SourceDrawingBuffer src_buffer, - const gfx::ColorSpace& dst_color_space, - VideoFrameCopyCompletedCallback callback) { - return swap_buffers_->CopyToVideoFrame(frame_pool, src_buffer, - dst_color_space, std::move(callback)); -} - void GPUCanvasContext::SetFilterQuality( cc::PaintFlags::FilterQuality filter_quality) { if (filter_quality != filter_quality_) {
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.h b/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.h index 7118c98..9e6755e 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.h +++ b/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.h
@@ -31,6 +31,7 @@ public: class Factory : public CanvasRenderingContextFactory { + public: Factory() = default; @@ -68,11 +69,6 @@ // be webgpu compatible. Returns true on success. bool CopyRenderingResultsFromDrawingBuffer(CanvasResourceProvider*, SourceDrawingBuffer) final; - bool CopyRenderingResultsToVideoFrame( - WebGraphicsContext3DVideoFramePool* frame_pool, - SourceDrawingBuffer src_buffer, - const gfx::ColorSpace& dst_color_space, - VideoFrameCopyCompletedCallback callback) override; void SetIsInHiddenPage(bool) override {} void SetIsBeingDisplayed(bool) override {} bool isContextLost() const override { return false; }
diff --git a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc index be455ec6..140f202 100644 --- a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc +++ b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc
@@ -4739,4 +4739,53 @@ // This test passes if no DCHECK occurs. } +TEST_P(PaintArtifactCompositorTest, + CompositedPixelMovingFilterWithClipExpander) { + CompositorFilterOperations filter_op; + filter_op.AppendBlurFilter(5); + auto filter = + CreateFilterEffect(e0(), filter_op, CompositingReason::kWillChangeFilter); + auto clip_expander = ClipPaintPropertyNode::Create( + c0(), ClipPaintPropertyNode::State(&t0(), filter.get())); + + Update(TestPaintArtifact() + .Chunk(t0(), *clip_expander, *filter) + .RectDrawing(gfx::Rect(150, 150, 100, 100), Color::kWhite) + .Build()); + ASSERT_EQ(1u, LayerCount()); + const auto* cc_clip_expander = + GetPropertyTrees().clip_tree().Node(LayerAt(0)->clip_tree_index()); + EXPECT_FALSE(cc_clip_expander->AppliesLocalClip()); + EXPECT_EQ(cc_clip_expander->pixel_moving_filter_id, + LayerAt(0)->effect_tree_index()); +} + +TEST_P(PaintArtifactCompositorTest, + NonCompositedPixelMovingFilterWithCompositedClipExpander) { + CompositorFilterOperations filter_op; + filter_op.AppendBlurFilter(5); + auto filter = CreateFilterEffect(e0(), filter_op); + auto clip_expander = ClipPaintPropertyNode::Create( + c0(), ClipPaintPropertyNode::State(&t0(), filter.get())); + + EffectPaintPropertyNode::State mask_state; + mask_state.local_transform_space = &t0(); + mask_state.output_clip = clip_expander.get(); + mask_state.blend_mode = SkBlendMode::kDstIn; + mask_state.direct_compositing_reasons = + CompositingReason::kBackdropFilterMask; + auto mask = EffectPaintPropertyNode::Create(e0(), std::move(mask_state)); + + Update(TestPaintArtifact() + .Chunk(t0(), *clip_expander, *filter) + .RectDrawing(gfx::Rect(150, 150, 100, 100), Color::kWhite) + .Chunk(t0(), *clip_expander, *mask) + .RectDrawing(gfx::Rect(150, 150, 100, 100), Color::kBlack) + .Build()); + ASSERT_EQ(2u, LayerCount()); + const auto* cc_clip_expander = + GetPropertyTrees().clip_tree().Node(LayerAt(0)->clip_tree_index()); + EXPECT_TRUE(cc_clip_expander->AppliesLocalClip()); +} + } // namespace blink
diff --git a/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc b/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc index 822f2f6..a86e783 100644 --- a/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc +++ b/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc
@@ -1272,7 +1272,8 @@ DCHECK(cc_clip); cc_clip->pixel_moving_filter_id = clip->PixelMovingFilter()->CcNodeId(new_sequence_number_); - DCHECK(!cc_clip->AppliesLocalClip()); + // No DCHECK(!cc_clip->AppliesLocalClip()) because the PixelMovingFilter + // may not be composited, and the clip node is a no-op node. } pixel_moving_filter_clip_expanders_.clear(); }
diff --git a/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider.cc b/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider.cc index b10f599..d3e2ebe 100644 --- a/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider.cc +++ b/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider.cc
@@ -6,7 +6,6 @@ #include "build/build_config.h" #include "gpu/GLES2/gl2extchromium.h" -#include "gpu/command_buffer/client/raster_interface.h" #include "gpu/command_buffer/client/shared_image_interface.h" #include "gpu/command_buffer/client/webgpu_interface.h" #include "gpu/command_buffer/common/gpu_memory_buffer_support.h" @@ -28,7 +27,6 @@ return viz::RGBA_8888; } } - } // namespace WebGPUSwapBufferProvider::WebGPUSwapBufferProvider( @@ -96,33 +94,7 @@ } } -std::tuple<uint32_t, bool> -WebGPUSwapBufferProvider::GetTextureTargetAndOverlayCandidacy() const { -// On macOS, shared images are backed by IOSurfaces that can only be used with -// OpenGL via the rectangle texture target and are overlay candidates. Every -// other shared image implementation is implemented on OpenGL via some form of -// eglSurface and eglBindTexImage (on ANGLE or system drivers) so they use the -// 2D texture target and cannot always be overlay candidates. -#if BUILDFLAG(IS_MAC) - const uint32_t texture_target = gpu::GetPlatformSpecificTextureTarget(); - const bool is_overlay_candidate = true; -#else - const uint32_t texture_target = GL_TEXTURE_2D; - const bool is_overlay_candidate = false; -#endif - - return std::make_tuple(texture_target, is_overlay_candidate); -} - -uint32_t WebGPUSwapBufferProvider::GetTextureTarget() const { - return std::get<0>(GetTextureTargetAndOverlayCandidacy()); -} -bool WebGPUSwapBufferProvider::IsOverlayCandidate() const { - return std::get<1>(GetTextureTargetAndOverlayCandidacy()); -} - -void WebGPUSwapBufferProvider::ReleaseWGPUTextureAccessIfNeeded( - bool for_transfer) { +void WebGPUSwapBufferProvider::DiscardCurrentSwapBuffer() { if (current_swap_buffer_) { if (auto context_provider = GetContextProviderWeakPtr()) { gpu::webgpu::WebGPUInterface* webgpu = @@ -130,17 +102,8 @@ // Dissociate mailbox to avoid memory leaks. if (wire_device_id_ && wire_texture_id_) { - if (for_transfer) { - // Give client a chance to do something before the dissociation. - DCHECK(client_); - client_->OnTextureTransferred(); + webgpu->DissociateMailbox(wire_texture_id_, wire_texture_generation_); - webgpu->DissociateMailboxForPresent( - wire_device_id_, wire_device_generation_, wire_texture_id_, - wire_texture_generation_); - } else { - webgpu->DissociateMailbox(wire_texture_id_, wire_texture_generation_); - } wire_device_id_ = 0; wire_device_generation_ = 0; wire_texture_id_ = 0; @@ -152,14 +115,10 @@ webgpu->GenUnverifiedSyncTokenCHROMIUM( current_swap_buffer_->access_finished_token.GetData()); } + current_swap_buffer_ = nullptr; } } -void WebGPUSwapBufferProvider::DiscardCurrentSwapBuffer() { - ReleaseWGPUTextureAccessIfNeeded(/*for_transfer=*/false); - current_swap_buffer_ = nullptr; -} - void WebGPUSwapBufferProvider::Neuter() { if (neutered_) { return; @@ -223,7 +182,7 @@ WGPUTexture WebGPUSwapBufferProvider::GetNewTexture(const gfx::Size& size, SkAlphaType alpha_mode) { - DCHECK(!wire_texture_id_); + DCHECK(!current_swap_buffer_); auto context_provider = GetContextProviderWeakPtr(); if (!context_provider) { return nullptr; @@ -298,13 +257,41 @@ return false; } - ReleaseWGPUTextureAccessIfNeeded(/*for_transfer=*/true); + DCHECK(client_); + client_->OnTextureTransferred(); + // Make Dawn relinquish access to the texture so it can be used by the + // compositor. This will call wgpu::Texture::Destroy so that further accesses + // to the texture are errors. + gpu::webgpu::WebGPUInterface* webgpu = + GetContextProviderWeakPtr()->ContextProvider()->WebGPUInterface(); + DCHECK_NE(wire_device_id_, 0u); + DCHECK_NE(wire_texture_id_, 0u); + webgpu->DissociateMailboxForPresent(wire_device_id_, wire_device_generation_, + wire_texture_id_, + wire_texture_generation_); + + // Make the compositor wait on previous Dawn commands. + webgpu->GenUnverifiedSyncTokenCHROMIUM( + current_swap_buffer_->access_finished_token.GetData()); + + // On macOS, shared images are backed by IOSurfaces that can only be used with + // OpenGL via the rectangle texture target and are overlay candidates. Every + // other shared image implementation is implemented on OpenGL via some form of + // eglSurface and eglBindTexImage (on ANGLE or system drivers) so they use the + // 2D texture target and cannot always be overlay candidates. +#if BUILDFLAG(IS_MAC) + const uint32_t texture_target = gpu::GetPlatformSpecificTextureTarget(); + const bool is_overlay_candidate = true; +#else + const uint32_t texture_target = GL_TEXTURE_2D; + const bool is_overlay_candidate = false; +#endif // Populate the output resource *out_resource = viz::TransferableResource::MakeGL( - current_swap_buffer_->mailbox, GL_LINEAR, GetTextureTarget(), + current_swap_buffer_->mailbox, GL_LINEAR, texture_target, current_swap_buffer_->access_finished_token, current_swap_buffer_->size, - IsOverlayCandidate()); + is_overlay_candidate); out_resource->color_space = gfx::ColorSpace::CreateSRGB(); out_resource->format = Format(); @@ -315,49 +302,14 @@ scoped_refptr<WebGPUSwapBufferProvider>(this), std::move(current_swap_buffer_)); + wire_device_id_ = 0; + wire_device_generation_ = 0; + wire_texture_id_ = 0; + wire_texture_generation_ = 0; + return true; } -bool WebGPUSwapBufferProvider::CopyToVideoFrame( - WebGraphicsContext3DVideoFramePool* frame_pool, - SourceDrawingBuffer src_buffer, - const gfx::ColorSpace& dst_color_space, - WebGraphicsContext3DVideoFramePool::FrameReadyCallback callback) { - DCHECK(!neutered_); - if (neutered_ || !GetContextProviderWeakPtr()) { - return false; - } - - DCHECK(frame_pool); - - auto* frame_pool_ri = frame_pool->GetRasterInterface(); - DCHECK(frame_pool_ri); - - // Copy kFrontBuffer to a video frame is not supported - DCHECK_EQ(src_buffer, kBackBuffer); - - // For a conversion from swap buffer's texture to video frame, we do it - // using WebGraphicsContext3DVideoFramePool's graphics context. Thus, we - // need to release WebGPU/Dawn's context's access to the texture. - ReleaseWGPUTextureAccessIfNeeded(/*for_transfer=*/true); - - gpu::MailboxHolder mailbox_holder(current_swap_buffer_->mailbox, - current_swap_buffer_->access_finished_token, - GetTextureTarget()); - - auto success = frame_pool->CopyRGBATextureToVideoFrame( - Format(), current_swap_buffer_->size, gfx::ColorSpace::CreateSRGB(), - kTopLeft_GrSurfaceOrigin, mailbox_holder, dst_color_space, - std::move(callback)); - - // Subsequent access to this swap buffer (either webgpu or compositor) must - // wait for the copy operation to finish. - frame_pool_ri->GenUnverifiedSyncTokenCHROMIUM( - current_swap_buffer_->access_finished_token.GetData()); - - return success; -} - void WebGPUSwapBufferProvider::MailboxReleased( std::unique_ptr<SwapBuffer> swap_buffer, const gpu::SyncToken& sync_token,
diff --git a/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider.h b/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider.h index 2556c01..c69ec7d5 100644 --- a/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider.h +++ b/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider.h
@@ -11,8 +11,6 @@ #include "gpu/command_buffer/common/sync_token.h" #include "third_party/blink/renderer/platform/graphics/gpu/dawn_control_client_holder.h" #include "third_party/blink/renderer/platform/graphics/gpu/webgpu_mailbox_texture.h" -#include "third_party/blink/renderer/platform/graphics/graphics_types_3d.h" -#include "third_party/blink/renderer/platform/graphics/web_graphics_context_3d_video_frame_pool.h" #include "third_party/blink/renderer/platform/platform_export.h" #include "third_party/blink/renderer/platform/wtf/functional.h" #include "third_party/blink/renderer/platform/wtf/ref_counted.h" @@ -31,7 +29,7 @@ class Client { public: // Called to make the WebGPU/Dawn stop accessing the texture prior to its - // transfer to the compositor/video frame + // transfer to the compositor. virtual void OnTextureTransferred() = 0; }; @@ -51,32 +49,6 @@ void DiscardCurrentSwapBuffer(); WGPUTexture GetNewTexture(const gfx::Size& size, SkAlphaType alpha_type); - // Copy swapchain's texture to a video frame. - // This happens at the end of an animation frame. Dawn's access to the - // texture will be released in order for the texture to be processed by - // WebGraphicsContext3DVideoFramePool context. Attempting to use the texture - // via WebGPU/Dawn API in JS after this point won't work. - // - // These are typical sequential steps of an animation frame: - // 1. start frame: - // - WebGPUSwapBufferProvider::GetNewTexture() - // 2. client draws to the swap chain's texture using WebGPU APIs. - // 3. finalize frame: - // (if client uses canvas.captureStream()) - // - WebGPUSwapBufferProvider::CopyToVideoFrame() - // - ReleaseWGPUTextureAccessIfNeeded() - // - copy swap chain's texture to a video frame using another graphics - // context. - // 4. TextureLayer::Update() - // - WebGPUSwapBufferProvider::PrepareTransferableResource() - // - ReleaseWGPUTextureAccessIfNeeded() (if not already done) - // - current_swap_buffer_'s ownership is transferred to caller. - bool CopyToVideoFrame( - WebGraphicsContext3DVideoFramePool* frame_pool, - SourceDrawingBuffer src_buffer, - const gfx::ColorSpace& dst_color_space, - WebGraphicsContext3DVideoFramePool::FrameReadyCallback callback); - struct WebGPUMailboxTextureAndSize { scoped_refptr<WebGPUMailboxTexture> mailbox_texture; gfx::Size size; @@ -123,10 +95,6 @@ gpu::SyncToken access_finished_token; }; - std::tuple<uint32_t, bool> GetTextureTargetAndOverlayCandidacy() const; - uint32_t GetTextureTarget() const; - bool IsOverlayCandidate() const; - std::unique_ptr<WebGPUSwapBufferProvider::SwapBuffer> NewOrRecycledSwapBuffer( gpu::SharedImageInterface* sii, base::WeakPtr<WebGraphicsContext3DProviderWrapper> context_provider, @@ -139,13 +107,6 @@ const gpu::SyncToken& sync_token, bool lost_resource); - // This method will dissociate current Dawn Texture (produced by - // GetNewTexture()) from the mailbox so that the mailbox can be used by other - // components (Compositor/Skia). - // After this method returns, Dawn won't be able to access the mailbox - // anymore. - void ReleaseWGPUTextureAccessIfNeeded(bool for_transfer); - scoped_refptr<DawnControlClientHolder> dawn_control_client_; Client* client_; WGPUDevice device_;
diff --git a/third_party/blink/renderer/platform/graphics/graphics_context.cc b/third_party/blink/renderer/platform/graphics/graphics_context.cc index 18dced4..8835f381 100644 --- a/third_party/blink/renderer/platform/graphics/graphics_context.cc +++ b/third_party/blink/renderer/platform/graphics/graphics_context.cc
@@ -752,7 +752,8 @@ const gfx::RectF* src_ptr, SkBlendMode op, RespectImageOrientationEnum should_respect_image_orientation, - bool image_may_be_lcp_candidate) { + bool image_may_be_lcp_candidate, + Image::ImageClampingMode clamping_mode) { if (!image) return; @@ -763,10 +764,10 @@ SkSamplingOptions sampling = ComputeSamplingOptions(image, dest, src); DarkModeFilter* dark_mode_filter = GetDarkModeFilterForImage(auto_dark_mode); - ImageDrawOptions draw_options( - dark_mode_filter, sampling, should_respect_image_orientation, - Image::kClampImageToSourceRect, decode_mode, auto_dark_mode.enabled, - image_may_be_lcp_candidate); + ImageDrawOptions draw_options(dark_mode_filter, sampling, + should_respect_image_orientation, clamping_mode, + decode_mode, auto_dark_mode.enabled, + image_may_be_lcp_candidate); image->Draw(canvas_, image_flags, dest, src, draw_options); paint_controller_.SetImagePainted(); @@ -780,13 +781,14 @@ const gfx::RectF& src_rect, SkBlendMode op, RespectImageOrientationEnum respect_orientation, - bool image_may_be_lcp_candidate) { + bool image_may_be_lcp_candidate, + Image::ImageClampingMode clamping_mode) { if (!image) return; if (!dest.IsRounded()) { DrawImage(image, decode_mode, auto_dark_mode, dest.Rect(), &src_rect, op, - respect_orientation, image_may_be_lcp_candidate); + respect_orientation, image_may_be_lcp_candidate, clamping_mode); return; } @@ -804,10 +806,9 @@ image_flags.setColor(SK_ColorBLACK); DarkModeFilter* dark_mode_filter = GetDarkModeFilterForImage(auto_dark_mode); - ImageDrawOptions draw_options(dark_mode_filter, sampling, respect_orientation, - Image::kClampImageToSourceRect, decode_mode, - auto_dark_mode.enabled, - image_may_be_lcp_candidate); + ImageDrawOptions draw_options( + dark_mode_filter, sampling, respect_orientation, clamping_mode, + decode_mode, auto_dark_mode.enabled, image_may_be_lcp_candidate); bool use_shader = (visible_src == src_rect) && (respect_orientation == kDoNotRespectImageOrientation ||
diff --git a/third_party/blink/renderer/platform/graphics/graphics_context.h b/third_party/blink/renderer/platform/graphics/graphics_context.h index 329f05d..064cfad 100644 --- a/third_party/blink/renderer/platform/graphics/graphics_context.h +++ b/third_party/blink/renderer/platform/graphics/graphics_context.h
@@ -323,7 +323,9 @@ const gfx::RectF* src_rect = nullptr, SkBlendMode = SkBlendMode::kSrcOver, RespectImageOrientationEnum = kRespectImageOrientation, - bool image_may_be_lcp_candidate = false); + bool image_may_be_lcp_candidate = false, + Image::ImageClampingMode clamping_mode = + Image::ImageClampingMode::kClampImageToSourceRect); void DrawImageRRect(Image*, Image::ImageDecodingMode, const ImageAutoDarkMode& auto_dark_mode, @@ -331,7 +333,9 @@ const gfx::RectF& src_rect, SkBlendMode = SkBlendMode::kSrcOver, RespectImageOrientationEnum = kRespectImageOrientation, - bool image_may_be_lcp_candidate = false); + bool image_may_be_lcp_candidate = false, + Image::ImageClampingMode clamping_mode = + Image::ImageClampingMode::kClampImageToSourceRect); void DrawImageTiled(Image* image, const gfx::RectF& dest_rect, const ImageTilingInfo& tiling_info,
diff --git a/third_party/blink/renderer/platform/media/key_system_config_selector.cc b/third_party/blink/renderer/platform/media/key_system_config_selector.cc index ff5d451c..f2a4ff19 100644 --- a/third_party/blink/renderer/platform/media/key_system_config_selector.cc +++ b/third_party/blink/renderer/platform/media/key_system_config_selector.cc
@@ -15,6 +15,7 @@ #include "build/build_config.h" #include "build/chromeos_buildflags.h" #include "media/base/cdm_config.h" +#include "media/base/eme_constants.h" #include "media/base/key_system_names.h" #include "media/base/key_systems.h" #include "media/base/logging_override_if_enabled.h" @@ -33,27 +34,28 @@ namespace { using ::media::EmeConfigRule; +using ::media::EmeConfigRuleState; using ::media::EmeFeatureSupport; using ::media::EmeMediaType; using ::media::EncryptionScheme; using EmeFeatureRequirement = WebMediaKeySystemConfiguration::Requirement; using EmeEncryptionScheme = WebMediaKeySystemMediaCapability::EncryptionScheme; -EmeConfigRule GetDistinctiveIdentifierConfigRule( +absl::optional<EmeConfigRule> GetDistinctiveIdentifierConfigRule( EmeFeatureSupport support, EmeFeatureRequirement requirement) { if (support == EmeFeatureSupport::INVALID) { NOTREACHED(); - return EmeConfigRule::NOT_SUPPORTED; + return absl::nullopt; } - // For NOT_ALLOWED and REQUIRED, the result is as expected. For OPTIONAL, we - // return the most restrictive rule that is not more restrictive than for - // NOT_ALLOWED or REQUIRED. Those values will be checked individually when + // For kNotAllowed and kRequired, the result is as expected. For kRecommended, + // we return the most restrictive rule that is not more restrictive than for + // kNotAllowed or kRequired. Those values will be checked individually when // the option is resolved. // // |---------------Requirement------------------- - // Support | NOT_ALLOWED | OPTIONAL | REQUIRED + // Support | kNotAllowed | kRecommended | kRequired // NOT_SUPPORTED | I_NOT_ALLOWED | I_NOT_ALLOWED | NOT_SUPPORTED // REQUESTABLE | I_NOT_ALLOWED | SUPPORTED | I_REQUIRED // ALWAYS_ENABLED | NOT_SUPPORTED | I_REQUIRED | I_REQUIRED @@ -67,36 +69,37 @@ requirement == EmeFeatureRequirement::kRequired) || (support == EmeFeatureSupport::ALWAYS_ENABLED && requirement == EmeFeatureRequirement::kNotAllowed)) { - return EmeConfigRule::NOT_SUPPORTED; + return absl::nullopt; } if (support == EmeFeatureSupport::REQUESTABLE && requirement == EmeFeatureRequirement::kOptional) { - return EmeConfigRule::SUPPORTED; + return EmeConfigRule(); } if (support == EmeFeatureSupport::NOT_SUPPORTED || requirement == EmeFeatureRequirement::kNotAllowed) { - return EmeConfigRule::IDENTIFIER_NOT_ALLOWED; + return EmeConfigRule{.identifier = EmeConfigRuleState::kNotAllowed}; } - return EmeConfigRule::IDENTIFIER_REQUIRED; + return EmeConfigRule{.identifier = EmeConfigRuleState::kRequired}; } -EmeConfigRule GetPersistentStateConfigRule(EmeFeatureSupport support, - EmeFeatureRequirement requirement) { +absl::optional<EmeConfigRule> GetPersistentStateConfigRule( + EmeFeatureSupport support, + EmeFeatureRequirement requirement) { if (support == EmeFeatureSupport::INVALID) { NOTREACHED(); - return EmeConfigRule::NOT_SUPPORTED; + return absl::nullopt; } - // For NOT_ALLOWED and REQUIRED, the result is as expected. For OPTIONAL, we - // return the most restrictive rule that is not more restrictive than for - // NOT_ALLOWED or REQUIRED. Those values will be checked individually when + // For kNotAllowed and kRequired, the result is as expected. For kRecommended, + // we return the most restrictive rule that is not more restrictive than for + // kNotAllowed or kRequired. Those values will be checked individually when // the option is resolved. // // Note that even though a distinctive identifier can not be required for // persistent state, it may still be required for persistent sessions. // // |---------------Requirement------------------- - // Support | NOT_ALLOWED | OPTIONAL | REQUIRED + // Support | kNotAllowed | kRecommended | kRequired // NOT_SUPPORTED | P_NOT_ALLOWED | P_NOT_ALLOWED | NOT_SUPPORTED // REQUESTABLE | P_NOT_ALLOWED | SUPPORTED | P_REQUIRED // ALWAYS_ENABLED | NOT_SUPPORTED | P_REQUIRED | P_REQUIRED @@ -110,17 +113,17 @@ requirement == EmeFeatureRequirement::kRequired) || (support == EmeFeatureSupport::ALWAYS_ENABLED && requirement == EmeFeatureRequirement::kNotAllowed)) { - return EmeConfigRule::NOT_SUPPORTED; + return absl::nullopt; } if (support == EmeFeatureSupport::REQUESTABLE && requirement == EmeFeatureRequirement::kOptional) { - return EmeConfigRule::SUPPORTED; + return EmeConfigRule(); } if (support == EmeFeatureSupport::NOT_SUPPORTED || requirement == EmeFeatureRequirement::kNotAllowed) { - return EmeConfigRule::PERSISTENCE_NOT_ALLOWED; + return EmeConfigRule{.persistence = EmeConfigRuleState::kNotAllowed}; } - return EmeConfigRule::PERSISTENCE_REQUIRED; + return EmeConfigRule{.persistence = EmeConfigRuleState::kRequired}; } bool IsPersistentSessionType(WebEncryptedMediaSessionType sessionType) { @@ -197,101 +200,130 @@ return is_permission_granted_ || !was_permission_requested_; } - bool IsIdentifierRequired() const { return is_identifier_required_; } + bool IsIdentifierRequired() const { + return rules.identifier == EmeConfigRuleState::kRequired; + } - bool IsIdentifierRecommended() const { return is_identifier_recommended_; } + bool IsIdentifierRecommended() const { + return rules.identifier == EmeConfigRuleState::kRecommended; + } bool AreHwSecureCodecsRequired() const { - return are_hw_secure_codecs_required_; + return rules.hw_secure_codecs == EmeConfigRuleState::kRequired; } bool AreHwSecureCodesNotAllowed() const { - return are_hw_secure_codecs_not_allowed_; + return rules.hw_secure_codecs == EmeConfigRuleState::kNotAllowed; } // Checks whether a rule is compatible with all previously added rules. - bool IsRuleSupported(EmeConfigRule rule) const { - switch (rule) { - case EmeConfigRule::NOT_SUPPORTED: - return false; - case EmeConfigRule::IDENTIFIER_NOT_ALLOWED: - return !is_identifier_required_; - case EmeConfigRule::IDENTIFIER_REQUIRED: - // TODO(sandersd): Confirm if we should be refusing these rules when - // permission has been denied (as the spec currently says). - return !is_identifier_not_allowed_ && IsPermissionPossible(); - case EmeConfigRule::IDENTIFIER_RECOMMENDED: - return true; - case EmeConfigRule::PERSISTENCE_NOT_ALLOWED: - return !is_persistence_required_; - case EmeConfigRule::PERSISTENCE_REQUIRED: - return !is_persistence_not_allowed_; - case EmeConfigRule::IDENTIFIER_AND_PERSISTENCE_REQUIRED: - return !is_identifier_not_allowed_ && IsPermissionPossible() && - !is_persistence_not_allowed_; - case EmeConfigRule::HW_SECURE_CODECS_NOT_ALLOWED: - return !are_hw_secure_codecs_required_; - case EmeConfigRule::HW_SECURE_CODECS_REQUIRED: - return !are_hw_secure_codecs_not_allowed_; - case EmeConfigRule::IDENTIFIER_AND_HW_SECURE_CODECS_REQUIRED: - return !is_identifier_not_allowed_ && IsPermissionPossible() && - !are_hw_secure_codecs_not_allowed_; - case EmeConfigRule::IDENTIFIER_PERSISTENCE_AND_HW_SECURE_CODECS_REQUIRED: - return !is_identifier_not_allowed_ && IsPermissionPossible() && - !is_persistence_not_allowed_ && - !are_hw_secure_codecs_not_allowed_; - case EmeConfigRule::SUPPORTED: - return true; + bool IsRuleSupported(absl::optional<EmeConfigRule> rule) const { + bool result = true; + + // NOT_SUPPORTED + if (!rule.has_value()) { + return false; } - NOTREACHED(); - return false; + + // SUPPORTED + if (rule->hw_secure_codecs == EmeConfigRuleState::kUnset && + rule->persistence == EmeConfigRuleState::kUnset && + rule->identifier == EmeConfigRuleState::kUnset) { + return true; + } + + // For identifier, if the rule we are evaluating is kNotAllowed, + // as long as our rules does not have a rule in place already + // that says identifier = kRequired, then we can proceed + // to evaluating the other rules. + + // If the rule we are evaluating is kRequired, then we have to + // evaluate whether our rules does not have a rule in place already + // that says identifier = kNotAllowed and we have to make sure + // permission is possible. Then we can proceed to evaluating the + // other rules. + if (rule->identifier == EmeConfigRuleState::kNotAllowed) { + result = result && rules.identifier != EmeConfigRuleState::kRequired; + } else if (rule->identifier == EmeConfigRuleState::kRequired) { + result = result && rules.identifier != EmeConfigRuleState::kNotAllowed && + IsPermissionPossible(); + } + + // For persistence, if the rule we are evaluating is kNotAllowed, + // as long as our rules does not have a rule in place already + // that says persistence = kRequired, then we can proceed + // to evaluating the other rules. + + /// If the rule we are evaluating is kRequired, then we have to + // evaluate whether our rules does not have a rule in place already + // that says persistence = kNotAllowed. Then we can proceed to + // evaluating the other rules. + if (rule->persistence == EmeConfigRuleState::kNotAllowed) { + result = result && rules.persistence != EmeConfigRuleState::kRequired; + } else if (rule->persistence == EmeConfigRuleState::kRequired) { + result = result && rules.persistence != EmeConfigRuleState::kNotAllowed; + } + + // For hw_secure_codecs, if the rule we are evaluating is kNotAllowed, + // as long as our rules does not have a rule in place already + // that says hw_secure_codecs = kRequired, then we can proceed + // to evaluating the other rules. + + /// If the rule we are evaluating is kRequired, then we have to + // evaluate whether our rules does not have a rule in place already + // that says hw_secure_codecs = kNotAllowed. Then we can proceed to + // evaluating the other rules. + if (rule->hw_secure_codecs == EmeConfigRuleState::kNotAllowed) { + result = + result && rules.hw_secure_codecs != EmeConfigRuleState::kRequired; + } else if (rule->hw_secure_codecs == EmeConfigRuleState::kRequired) { + result = + result && rules.hw_secure_codecs != EmeConfigRuleState::kNotAllowed; + } + return result; } // Add a rule to the accumulated configuration state. - void AddRule(EmeConfigRule rule) { + void AddRule(absl::optional<EmeConfigRule> rule) { DCHECK(IsRuleSupported(rule)); - switch (rule) { - case EmeConfigRule::NOT_SUPPORTED: - NOTREACHED(); - return; - case EmeConfigRule::IDENTIFIER_NOT_ALLOWED: - is_identifier_not_allowed_ = true; - return; - case EmeConfigRule::IDENTIFIER_REQUIRED: - is_identifier_required_ = true; - return; - case EmeConfigRule::IDENTIFIER_RECOMMENDED: - is_identifier_recommended_ = true; - return; - case EmeConfigRule::PERSISTENCE_NOT_ALLOWED: - is_persistence_not_allowed_ = true; - return; - case EmeConfigRule::PERSISTENCE_REQUIRED: - is_persistence_required_ = true; - return; - case EmeConfigRule::IDENTIFIER_AND_PERSISTENCE_REQUIRED: - is_identifier_required_ = true; - is_persistence_required_ = true; - return; - case EmeConfigRule::HW_SECURE_CODECS_NOT_ALLOWED: - are_hw_secure_codecs_not_allowed_ = true; - return; - case EmeConfigRule::HW_SECURE_CODECS_REQUIRED: - are_hw_secure_codecs_required_ = true; - return; - case EmeConfigRule::IDENTIFIER_AND_HW_SECURE_CODECS_REQUIRED: - is_identifier_required_ = true; - are_hw_secure_codecs_required_ = true; - return; - case EmeConfigRule::IDENTIFIER_PERSISTENCE_AND_HW_SECURE_CODECS_REQUIRED: - is_identifier_required_ = true; - is_persistence_required_ = true; - are_hw_secure_codecs_required_ = true; - return; - case EmeConfigRule::SUPPORTED: - return; + + // No rule specified, this should not happen + if (!rule.has_value()) { + NOTREACHED(); + return; } - NOTREACHED(); + + // Rule does not require or prohibit anything, so can be skipped. + if (rule->hw_secure_codecs == EmeConfigRuleState::kUnset && + rule->persistence == EmeConfigRuleState::kUnset && + rule->identifier == EmeConfigRuleState::kUnset) { + return; + } + + // In the three statements below, we first check if the rule is + // not specified. Then, as long as the rule we are adding to our rules + // does not override a kNotAllowed or kRequired, or if the + // collection of rules does not have anything associated, we should + // change the value to the incoming rule. Else, we ignore. + if (rule->identifier != EmeConfigRuleState::kUnset) { + if (rule->identifier != EmeConfigRuleState::kRecommended || + rules.identifier == EmeConfigRuleState::kUnset) { + rules.identifier = rule->identifier; + } + } + if (rule->persistence != EmeConfigRuleState::kUnset) { + if (rule->persistence != EmeConfigRuleState::kRecommended || + rules.persistence == EmeConfigRuleState::kUnset) { + rules.persistence = rule->persistence; + } + } + if (rule->hw_secure_codecs != EmeConfigRuleState::kUnset) { + if (rule->hw_secure_codecs != EmeConfigRuleState::kRecommended && + rules.hw_secure_codecs == EmeConfigRuleState::kUnset) { + rules.hw_secure_codecs = rule->hw_secure_codecs; + } + } + return; } private: @@ -304,22 +336,7 @@ // (Not changed by adding rules.) bool is_permission_granted_; - // Whether a rule has been added that requires or blocks a distinctive - // identifier. - bool is_identifier_required_ = false; - bool is_identifier_not_allowed_ = false; - - // Whether a rule has been added that recommends a distinctive identifier. - bool is_identifier_recommended_ = false; - - // Whether a rule has been added that requires or blocks persistent state. - bool is_persistence_required_ = false; - bool is_persistence_not_allowed_ = false; - - // Whether a rule has been added that requires or blocks hardware-secure - // codecs. - bool are_hw_secure_codecs_required_ = false; - bool are_hw_secure_codecs_not_allowed_ = false; + EmeConfigRule rules = EmeConfigRule(); }; KeySystemConfigSelector::KeySystemConfigSelector( @@ -377,8 +394,9 @@ media::SplitCodecs(codecs, &codec_vector); // Check that |container_lower| and |codec_vector| are supported by the CDM. - EmeConfigRule codecs_rule = key_systems_->GetContentTypeConfigRule( - key_system, media_type, container_lower, codec_vector); + absl::optional<EmeConfigRule> codecs_rule = + key_systems_->GetContentTypeConfigRule(key_system, media_type, + container_lower, codec_vector); if (!config_state->IsRuleSupported(codecs_rule)) { DVLOG(3) << "Container mime type and codecs are not supported by CDM"; return false; @@ -388,7 +406,8 @@ return true; } -EmeConfigRule KeySystemConfigSelector::GetEncryptionSchemeConfigRule( +absl::optional<EmeConfigRule> +KeySystemConfigSelector::GetEncryptionSchemeConfigRule( const std::string& key_system, const EmeEncryptionScheme encryption_scheme) { switch (encryption_scheme) { @@ -415,11 +434,11 @@ // supported by implementation, continue to the next iteration." // The value provided was an empty string or some other value that is // not recognized, so treat it as a scheme that is not supported. - return EmeConfigRule::NOT_SUPPORTED; + return absl::nullopt; } NOTREACHED(); - return EmeConfigRule::NOT_SUPPORTED; + return absl::nullopt; } bool KeySystemConfigSelector::GetSupportedCapabilities( @@ -488,9 +507,10 @@ hw_secure_requirement = false; else hw_secure_requirement_ptr = nullptr; - EmeConfigRule robustness_rule = key_systems_->GetRobustnessConfigRule( - key_system, media_type, requested_robustness_ascii, - hw_secure_requirement_ptr); + absl::optional<EmeConfigRule> robustness_rule = + key_systems_->GetRobustnessConfigRule(key_system, media_type, + requested_robustness_ascii, + hw_secure_requirement_ptr); // 3.13. If the user agent and implementation definitely support playback of // encrypted media data for the combination of container, media types, @@ -504,7 +524,7 @@ // Check for encryption scheme support. // https://github.com/WICG/encrypted-media-encryption-scheme/blob/master/explainer.md. - EmeConfigRule encryption_scheme_rule = + absl::optional<EmeConfigRule> encryption_scheme_rule = GetEncryptionSchemeConfigRule(key_system, capability.encryption_scheme); if (!proposed_config_state.IsRuleSupported(encryption_scheme_rule)) { DVLOG(3) << "The current encryption scheme rule is not supported."; @@ -599,8 +619,11 @@ // 5. If distinctive identifier requirement is "optional" and Distinctive // Identifiers are not allowed according to restrictions, set distinctive // identifier requirement to "not-allowed". + + absl::optional<EmeConfigRule> identifier_required = + EmeConfigRule{.identifier = EmeConfigRuleState::kRequired}; if (distinctive_identifier == EmeFeatureRequirement::kOptional && - !config_state->IsRuleSupported(EmeConfigRule::IDENTIFIER_REQUIRED)) { + !config_state->IsRuleSupported(identifier_required)) { distinctive_identifier = EmeFeatureRequirement::kNotAllowed; } @@ -630,7 +653,7 @@ distinctive_identifier_support = EmeFeatureSupport::NOT_SUPPORTED; } #endif // !BUILDFLAG(IS_ANDROID) - EmeConfigRule di_rule = GetDistinctiveIdentifierConfigRule( + absl::optional<EmeConfigRule> di_rule = GetDistinctiveIdentifierConfigRule( distinctive_identifier_support, distinctive_identifier); if (!config_state->IsRuleSupported(di_rule)) { DVLOG(2) << "Rejecting requested configuration because " @@ -650,8 +673,10 @@ // 9. If persistent state requirement is "optional" and persisting state is // not allowed according to restrictions, set persistent state requirement // to "not-allowed". + absl::optional<EmeConfigRule> persistence_required = + EmeConfigRule{.persistence = EmeConfigRuleState::kRequired}; if (persistent_state == EmeFeatureRequirement::kOptional && - !config_state->IsRuleSupported(EmeConfigRule::PERSISTENCE_REQUIRED)) { + !config_state->IsRuleSupported(persistence_required)) { persistent_state = EmeFeatureRequirement::kNotAllowed; } @@ -674,7 +699,7 @@ return CONFIGURATION_NOT_SUPPORTED; persistent_state_support = EmeFeatureSupport::NOT_SUPPORTED; } - EmeConfigRule ps_rule = + absl::optional<EmeConfigRule> ps_rule = GetPersistentStateConfigRule(persistent_state_support, persistent_state); if (!config_state->IsRuleSupported(ps_rule)) { DVLOG(2) << "Rejecting requested configuration because " @@ -720,13 +745,13 @@ // 13.3. If the implementation does not support session type in combination // with accumulated configuration and restrictions for other reasons, // return NotSupported. - EmeConfigRule session_type_rule = EmeConfigRule::NOT_SUPPORTED; + absl::optional<EmeConfigRule> session_type_rule = absl::nullopt; switch (session_type) { case WebEncryptedMediaSessionType::kUnknown: NOTREACHED(); return CONFIGURATION_NOT_SUPPORTED; case WebEncryptedMediaSessionType::kTemporary: - session_type_rule = EmeConfigRule::SUPPORTED; + session_type_rule = EmeConfigRule(); break; case WebEncryptedMediaSessionType::kPersistentLicense: session_type_rule = @@ -829,12 +854,14 @@ // distinctiveIdentifier value to "not-allowed". if (accumulated_configuration->distinctive_identifier == EmeFeatureRequirement::kOptional) { - EmeConfigRule not_allowed_rule = GetDistinctiveIdentifierConfigRule( - key_systems_->GetDistinctiveIdentifierSupport(key_system), - EmeFeatureRequirement::kNotAllowed); - EmeConfigRule required_rule = GetDistinctiveIdentifierConfigRule( - key_systems_->GetDistinctiveIdentifierSupport(key_system), - EmeFeatureRequirement::kRequired); + absl::optional<EmeConfigRule> not_allowed_rule = + GetDistinctiveIdentifierConfigRule( + key_systems_->GetDistinctiveIdentifierSupport(key_system), + EmeFeatureRequirement::kNotAllowed); + absl::optional<EmeConfigRule> required_rule = + GetDistinctiveIdentifierConfigRule( + key_systems_->GetDistinctiveIdentifierSupport(key_system), + EmeFeatureRequirement::kRequired); bool not_allowed_supported = config_state->IsRuleSupported(not_allowed_rule); bool required_supported = config_state->IsRuleSupported(required_rule); @@ -869,17 +896,18 @@ // value to "not-allowed". if (accumulated_configuration->persistent_state == EmeFeatureRequirement::kOptional) { - EmeConfigRule not_allowed_rule = GetPersistentStateConfigRule( - key_systems_->GetPersistentStateSupport(key_system), - EmeFeatureRequirement::kNotAllowed); - EmeConfigRule required_rule = GetPersistentStateConfigRule( + absl::optional<EmeConfigRule> not_allowed_rule = + GetPersistentStateConfigRule( + key_systems_->GetPersistentStateSupport(key_system), + EmeFeatureRequirement::kNotAllowed); + absl::optional<EmeConfigRule> required_rule = GetPersistentStateConfigRule( key_systems_->GetPersistentStateSupport(key_system), EmeFeatureRequirement::kRequired); // |persistent_state| should not be affected after it is decided. - DCHECK(not_allowed_rule == EmeConfigRule::NOT_SUPPORTED || - not_allowed_rule == EmeConfigRule::PERSISTENCE_NOT_ALLOWED); - DCHECK(required_rule == EmeConfigRule::NOT_SUPPORTED || - required_rule == EmeConfigRule::PERSISTENCE_REQUIRED); + DCHECK(!not_allowed_rule.has_value() || + not_allowed_rule->persistence == EmeConfigRuleState::kNotAllowed); + DCHECK(!required_rule.has_value() || + required_rule->persistence == EmeConfigRuleState::kRequired); bool not_allowed_supported = config_state->IsRuleSupported(not_allowed_rule); bool required_supported = config_state->IsRuleSupported(required_rule);
diff --git a/third_party/blink/renderer/platform/media/key_system_config_selector_unittest.cc b/third_party/blink/renderer/platform/media/key_system_config_selector_unittest.cc index b148d937..27886dab 100644 --- a/third_party/blink/renderer/platform/media/key_system_config_selector_unittest.cc +++ b/third_party/blink/renderer/platform/media/key_system_config_selector_unittest.cc
@@ -16,6 +16,7 @@ #include "media/base/media_permission.h" #include "media/base/mime_util.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/blink/public/platform/web_content_settings_client.h" #include "third_party/blink/public/platform/web_encrypted_media_types.h" #include "third_party/blink/public/platform/web_media_key_system_configuration.h" @@ -25,6 +26,7 @@ namespace { using ::media::EmeConfigRule; +using ::media::EmeConfigRuleState; using ::media::EmeFeatureSupport; using ::media::EmeInitDataType; using ::media::EmeMediaType; @@ -242,32 +244,33 @@ return false; } - EmeConfigRule GetEncryptionSchemeConfigRule( + absl::optional<EmeConfigRule> GetEncryptionSchemeConfigRule( const std::string& key_system, media::EncryptionScheme encryption_scheme) const override { if (encryption_scheme == ConvertEncryptionScheme(kSupportedEncryptionScheme)) { - return EmeConfigRule::SUPPORTED; + return EmeConfigRule(); } if (encryption_scheme == ConvertEncryptionScheme(kDisallowHwSecureCodecEncryptionScheme)) { - return EmeConfigRule::HW_SECURE_CODECS_NOT_ALLOWED; + return EmeConfigRule{.hw_secure_codecs = EmeConfigRuleState::kNotAllowed}; } - return EmeConfigRule::NOT_SUPPORTED; + return absl::nullopt; } - EmeConfigRule GetContentTypeConfigRule( + absl::optional<EmeConfigRule> GetContentTypeConfigRule( const std::string& key_system, EmeMediaType media_type, const std::string& container_mime_type, const std::vector<std::string>& codecs) const override { DCHECK(IsValidContainerMimeType(container_mime_type)) << "Invalid container mime type should not be passed in"; + if (container_mime_type == kUnsupportedContainer || !IsCompatibleWithEmeMediaType(media_type, container_mime_type)) { - return EmeConfigRule::NOT_SUPPORTED; + return absl::nullopt; } bool hw_secure_codec_required_ = false; @@ -278,7 +281,7 @@ if (codec == kUnsupportedCodec || !IsCompatibleWithEmeMediaType(media_type, codec)) { - return EmeConfigRule::NOT_SUPPORTED; + return absl::nullopt; } else if (codec == kRequireHwSecureCodec) { hw_secure_codec_required_ = true; } else if (codec == kDisallowHwSecureCodec) { @@ -287,19 +290,21 @@ } if (hw_secure_codec_required_) { - if (hw_secure_codec_not_allowed_) - return EmeConfigRule::NOT_SUPPORTED; - else - return EmeConfigRule::HW_SECURE_CODECS_REQUIRED; + if (hw_secure_codec_not_allowed_) { + return absl::nullopt; + } else { + return EmeConfigRule{.hw_secure_codecs = EmeConfigRuleState::kRequired}; + } } - if (hw_secure_codec_not_allowed_) - return EmeConfigRule::HW_SECURE_CODECS_NOT_ALLOWED; + if (hw_secure_codec_not_allowed_) { + return EmeConfigRule{.hw_secure_codecs = EmeConfigRuleState::kNotAllowed}; + } - return EmeConfigRule::SUPPORTED; + return EmeConfigRule(); } - EmeConfigRule GetRobustnessConfigRule( + absl::optional<EmeConfigRule> GetRobustnessConfigRule( const std::string& key_system, EmeMediaType media_type, const std::string& requested_robustness, @@ -309,35 +314,43 @@ // done. We are only testing the explicit thing it is fixing here. if (hw_secure_requirement && *hw_secure_requirement && distinctive_identifier == EmeFeatureSupport::NOT_SUPPORTED) { - return EmeConfigRule::NOT_SUPPORTED; + return absl::nullopt; } - if (requested_robustness.empty()) - return EmeConfigRule::SUPPORTED; - if (requested_robustness == kSupportedRobustness) - return EmeConfigRule::SUPPORTED; - if (requested_robustness == kRequireIdentifierRobustness) - return EmeConfigRule::IDENTIFIER_REQUIRED; - if (requested_robustness == kRecommendIdentifierRobustness) - return EmeConfigRule::IDENTIFIER_RECOMMENDED; - if (requested_robustness == kDisallowHwSecureCodecRobustness) - return EmeConfigRule::HW_SECURE_CODECS_NOT_ALLOWED; - if (requested_robustness == kRequireHwSecureCodecRobustness) - return EmeConfigRule::HW_SECURE_CODECS_REQUIRED; - if (requested_robustness == kRequireIdentifierAndHwSecureCodecRobustness) - return EmeConfigRule::IDENTIFIER_AND_HW_SECURE_CODECS_REQUIRED; + if (requested_robustness.empty() || + requested_robustness == kSupportedRobustness) { + return EmeConfigRule(); + } + if (requested_robustness == kRequireIdentifierRobustness) { + return EmeConfigRule{.identifier = EmeConfigRuleState::kRequired}; + } + if (requested_robustness == kRecommendIdentifierRobustness) { + return EmeConfigRule{.identifier = EmeConfigRuleState::kRecommended}; + } + if (requested_robustness == kDisallowHwSecureCodecRobustness) { + return EmeConfigRule{.hw_secure_codecs = EmeConfigRuleState::kNotAllowed}; + } + if (requested_robustness == kRequireHwSecureCodecRobustness) { + return EmeConfigRule{.hw_secure_codecs = EmeConfigRuleState::kRequired}; + } + if (requested_robustness == kRequireIdentifierAndHwSecureCodecRobustness) { + return EmeConfigRule{.identifier = EmeConfigRuleState::kRequired, + .hw_secure_codecs = EmeConfigRuleState::kRequired}; + } if (requested_robustness == kRequireIdentifierPersistenceAndHwSecureCodecRobustness) { - return EmeConfigRule:: - IDENTIFIER_PERSISTENCE_AND_HW_SECURE_CODECS_REQUIRED; + return EmeConfigRule{.identifier = EmeConfigRuleState::kRequired, + .persistence = EmeConfigRuleState::kRequired, + .hw_secure_codecs = EmeConfigRuleState::kRequired}; } - if (requested_robustness == kUnsupportedRobustness) - return EmeConfigRule::NOT_SUPPORTED; + if (requested_robustness == kUnsupportedRobustness) { + return absl::nullopt; + } NOTREACHED(); - return EmeConfigRule::NOT_SUPPORTED; + return absl::nullopt; } - EmeConfigRule GetPersistentLicenseSessionSupport( + absl::optional<EmeConfigRule> GetPersistentLicenseSessionSupport( const std::string& key_system) const override { return persistent_license; } @@ -356,8 +369,7 @@ bool init_data_type_cenc_supported_ = false; bool init_data_type_keyids_supported_ = false; - // INVALID so that they must be set in any test that needs them. - EmeConfigRule persistent_license = EmeConfigRule::NOT_SUPPORTED; + absl::optional<EmeConfigRule> persistent_license = absl::nullopt; // Every test implicitly requires these, so they must be set. They are set to // values that are likely to cause tests to fail if they are accidentally @@ -876,7 +888,7 @@ TEST_F(KeySystemConfigSelectorTest, SessionTypes_SubsetSupported) { // Allow persistent state, as it would be required to be successful. key_systems_->persistent_state = EmeFeatureSupport::REQUESTABLE; - key_systems_->persistent_license = EmeConfigRule::NOT_SUPPORTED; + key_systems_->persistent_license = absl::nullopt; std::vector<WebEncryptedMediaSessionType> session_types; session_types.push_back(WebEncryptedMediaSessionType::kTemporary); @@ -892,7 +904,7 @@ TEST_F(KeySystemConfigSelectorTest, SessionTypes_AllSupported) { // Allow persistent state, and expect it to be required. key_systems_->persistent_state = EmeFeatureSupport::REQUESTABLE; - key_systems_->persistent_license = EmeConfigRule::SUPPORTED; + key_systems_->persistent_license = EmeConfigRule(); std::vector<WebEncryptedMediaSessionType> session_types; session_types.push_back(WebEncryptedMediaSessionType::kTemporary); @@ -916,7 +928,8 @@ key_systems_->distinctive_identifier = EmeFeatureSupport::REQUESTABLE; key_systems_->persistent_state = EmeFeatureSupport::REQUESTABLE; key_systems_->persistent_license = - EmeConfigRule::IDENTIFIER_AND_PERSISTENCE_REQUIRED; + EmeConfigRule{.identifier = EmeConfigRuleState::kRequired, + .persistence = EmeConfigRuleState::kRequired}; std::vector<WebEncryptedMediaSessionType> session_types; session_types.push_back(WebEncryptedMediaSessionType::kPersistentLicense);
diff --git a/third_party/blink/renderer/platform/scheduler/common/process_state.cc b/third_party/blink/renderer/platform/scheduler/common/process_state.cc index a769976..3556ae4b 100644 --- a/third_party/blink/renderer/platform/scheduler/common/process_state.cc +++ b/third_party/blink/renderer/platform/scheduler/common/process_state.cc
@@ -12,7 +12,8 @@ namespace { -base::LazyInstance<ProcessState>::Leaky g_process_state; +base::LazyInstance<ProcessState>::Leaky g_process_state = + LAZY_INSTANCE_INITIALIZER; } // namespace
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 bcef9794..bdf443f0 100644 --- a/third_party/blink/renderer/platform/scheduler/common/tracing_helper.cc +++ b/third_party/blink/renderer/platform/scheduler/common/tracing_helper.cc
@@ -153,6 +153,9 @@ case TaskType::kInternalNavigationAssociatedUnfreezable: return RendererMainThreadTaskExecution:: TASK_TYPE_INTERNAL_NAVIGATION_ASSOCIATED_UNFREEZABLE; + case TaskType::kInternalNavigationCancellation: + return RendererMainThreadTaskExecution:: + TASK_TYPE_INTERNAL_NAVIGATION_CANCELLATION; case TaskType::kInternalContinueScriptLoading: return RendererMainThreadTaskExecution:: TASK_TYPE_INTERNAL_CONTINUE_SCRIPT_LOADING;
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 4ebfe058..3adbada 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
@@ -469,6 +469,9 @@ } case TaskType::kInternalNavigationAssociated: return FreezableTaskQueueTraits(); + case TaskType::kInternalNavigationCancellation: + return FreezableTaskQueueTraits().SetPrioritisationType( + QueueTraits::PrioritisationType::kInternalNavigationCancellation); case TaskType::kInternalInputBlocking: return InputBlockingQueueTraits(); // Some tasks in the tests need to run when objects are paused e.g. to hook @@ -988,6 +991,9 @@ case MainThreadTaskQueue::QueueTraits::PrioritisationType:: kPostMessageForwarding: return TaskQueue::QueuePriority::kVeryHighPriority; + case MainThreadTaskQueue::QueueTraits::PrioritisationType:: + kInternalNavigationCancellation: + return TaskQueue::QueuePriority::kVeryHighPriority; default: break; }
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 1e190be..d1dc0a2 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
@@ -155,10 +155,11 @@ TaskType::kInternalInputBlocking, TaskType::kWakeLock, TaskType::kWebGPU, - TaskType::kInternalPostMessageForwarding}; + TaskType::kInternalPostMessageForwarding, + TaskType::kInternalNavigationCancellation}; static_assert( - static_cast<int>(TaskType::kMaxValue) == 79, + static_cast<int>(TaskType::kMaxValue) == 80, "When adding a TaskType, make sure that kAllFrameTaskTypes is updated."); void AppendToVectorTestTask(Vector<String>* vector, String value) {
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h index 181d8272..f0b8bd2 100644 --- a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h +++ b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h
@@ -160,8 +160,9 @@ kCompositor = 9, // Main-thread only. kInput = 10, kPostMessageForwarding = 11, + kInternalNavigationCancellation = 12, - kCount = 12 + kCount = 13 }; // kPrioritisationTypeWidthBits is the number of bits required
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 a3dbd92..52f0dfc 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
@@ -131,6 +131,8 @@ return "InternalNavigationAssociated"; case TaskType::kInternalNavigationAssociatedUnfreezable: return "InternalNavigationAssociatedUnfreezable"; + case TaskType::kInternalNavigationCancellation: + return "InternalNavigationCancellation"; case TaskType::kInternalContinueScriptLoading: return "InternalContinueScriptLoading"; case TaskType::kWebSchedulingPostedTask:
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 d95e032..88501b9 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
@@ -185,6 +185,7 @@ case TaskType::kInternalUserInteraction: case TaskType::kInternalIntersectionObserver: case TaskType::kInternalNavigationAssociated: + case TaskType::kInternalNavigationCancellation: case TaskType::kInternalContinueScriptLoading: case TaskType::kWakeLock: // UnthrottledTaskRunner is generally discouraged in future.
diff --git a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py index f6b1282..b5acecc 100755 --- a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py +++ b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
@@ -653,6 +653,7 @@ 'ui::AXEventIntent', 'ui::AXMode', 'ui::AXNodeData', + 'ui::AXRelativeBounds', 'ui::AXTreeID', 'ui::kAXModeBasic', 'ui::kAXModeComplete',
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index 5908d3e..d9cc169 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -27,7 +27,7 @@ accessibility/slot-poison.html [ Failure ] # Temporarily disabled for a DevTools roll. -crbug.com/1343290 http/tests/devtools/elements/elements-tab-stops.js [ Failure Pass ] +crbug.com/1313690 http/tests/devtools/elements/iframe-load-event.js [ Failure Pass ] # Temporarily disabled for DevTools. @@ -3420,6 +3420,7 @@ crbug.com/626703 [ Win ] virtual/partitioned-cookies/http/tests/inspector-protocol/network/disabled-cache-navigation.js [ Failure ] # ====== New tests from wpt-importer added here ====== +crbug.com/626703 [ Win10.20h2 ] external/wpt/credential-management/fedcm-network-requests.sub.https.html [ Timeout ] crbug.com/626703 external/wpt/css/cssom/caretPositionFromPoint-with-transformation.html [ Timeout ] crbug.com/626703 [ Mac11-arm64 ] virtual/fenced-frame-mparch/wpt_internal/fenced_frame/key-scrolling.https.html [ Failure Timeout ] crbug.com/626703 virtual/conversions-debug-mode/wpt_internal/attribution-reporting/trigger-registration.sub.https.html?method=xhr [ Pass Timeout ] @@ -7109,7 +7110,10 @@ # Sheriff 2022-07-12 crbug.com/1343674 [ Linux ] editing/deleting/460938.html [ Failure Pass ] crbug.com/1343664 external/wpt/dom/events/non-cancelable-when-passive/non-passive-mousewheel-event-listener-on-document.html [ Failure Pass ] -crbug.com/1343651 external/wpt/credential-management/fedcm-network-requests.sub.https.html [ Crash Pass ] +crbug.com/1343651 [ Fuchsia ] external/wpt/credential-management/fedcm-network-requests.sub.https.html [ Crash Pass ] +crbug.com/1343651 [ Linux ] external/wpt/credential-management/fedcm-network-requests.sub.https.html [ Crash Pass ] +crbug.com/1343651 [ Mac ] external/wpt/credential-management/fedcm-network-requests.sub.https.html [ Crash Pass ] +crbug.com/1343651 [ Win11 ] external/wpt/credential-management/fedcm-network-requests.sub.https.html [ Crash Pass ] crbug.com/1343698 [ Mac Release ] external/wpt/webmessaging/postMessage_asterisk_xorigin.sub.htm [ Failure Pass ] crbug.com/1343698 [ Release Win10.20h2 ] external/wpt/webmessaging/postMessage_asterisk_xorigin.sub.htm [ Failure Pass ] @@ -7144,3 +7148,6 @@ crbug.com/1345235 external/wpt/content-security-policy/style-src/stylehash-basic-blocked.sub.html [ Skip ] crbug.com/1345233 [ Mac12 ] virtual/off-main-thread-css-paint/external/wpt/css/css-paint-api/registered-property-value-010.https.html [ Crash Failure Pass ] crbug.com/1334674 [ Mac11 ] http/tests/devtools/oopif/oopif-presentation-console-messages.js [ Failure Pass ] + +# Sheriff 2022-07-19 +crbug.com/1345745 virtual/async-script-scheduling-first-paint-or-finished-parsing/wpt_internal/async-script-scheduling/execution-order.html [ Skip ]
diff --git a/third_party/blink/web_tests/external/Version b/third_party/blink/web_tests/external/Version index f1a4c77..f47c225 100644 --- a/third_party/blink/web_tests/external/Version +++ b/third_party/blink/web_tests/external/Version
@@ -1 +1 @@ -Version: 4d2d72a77c336a552866e955557e63fd54f8615c +Version: 9deda95926faed241b9090ff4770561c24e9137d
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 57425049..880b256 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
@@ -237507,7 +237507,7 @@ }, "the-iframe-element": { "iframe-initially-empty-is-updated.html": [ - "3ad5b0f9f14e9df53f3a9087a8087ed5b8767334", + "818ec0362ef0fa8f474fe0dde0829a1b846fb72d", [ null, [ @@ -251423,7 +251423,7 @@ [] ], "accept-ch-test.js": [ - "e8438829d8850eb9cb7fe777967d80d5517f5e8d", + "192fcc4c8b856da452e358af0f64c7b94d6ff343", [] ], "accept-ch.html": [ @@ -251482,6 +251482,14 @@ "27140bf36e4dbd22b8f7190587f42a570c9d12bd", [] ], + "meta-equiv-delegate-ch.html": [ + "7d7c4ccdf7d5e3f391d265c158c9bfdd7717dd63", + [] + ], + "meta-equiv-delegate-ch.html.headers": [ + "27140bf36e4dbd22b8f7190587f42a570c9d12bd", + [] + ], "meta-name-accept-ch.html": [ "525faaae0d5709542f924526efe697424ec545a8", [] @@ -251520,6 +251528,10 @@ "34edb7b82b9657e0beaf9b1669d0854d365770ed", [] ], + "meta-equiv-delegate-ch-merge.https.html.headers": [ + "34edb7b82b9657e0beaf9b1669d0854d365770ed", + [] + ], "meta-name-accept-ch-merge.https.html.headers": [ "34edb7b82b9657e0beaf9b1669d0854d365770ed", [] @@ -361019,8 +361031,80 @@ } ] ], + "meta-equiv-delegate-ch-cross-origin-iframe-with-hints.https.sub.html": [ + "0a2c4897bc58325a5130311b3278f91bb29c37d3", + [ + null, + { + "timeout": "long" + } + ] + ], + "meta-equiv-delegate-ch-cross-origin-iframe-without-hints.https.sub.html": [ + "b79a941237aec284ea66350989949f89c5c38aab", + [ + null, + { + "timeout": "long" + } + ] + ], + "meta-equiv-delegate-ch-cross-origin-subresource-with-hints.https.sub.html": [ + "bd39cbaff421acceddfc9083b5064747553aa7c6", + [ + null, + { + "timeout": "long" + } + ] + ], + "meta-equiv-delegate-ch-cross-origin-subresource-without-hints.https.sub.html": [ + "20a3357fb6736107615365441c4826919426eb6a", + [ + null, + { + "timeout": "long" + } + ] + ], + "meta-name-accept-ch-cross-origin-iframe-with-hints.https.sub.html": [ + "6145f717c3dab86e0c86d7693d1eb7e699f0ca1f", + [ + null, + { + "timeout": "long" + } + ] + ], + "meta-name-accept-ch-cross-origin-iframe-without-hints.https.sub.html": [ + "276c34ff2e863133e1c7292ab1c9399b6fa2d590", + [ + null, + { + "timeout": "long" + } + ] + ], + "meta-name-accept-ch-cross-origin-subresource-with-hints.https.sub.html": [ + "bc93f005d4dadc1827e75c1c24fad7b08f0d40dc", + [ + null, + { + "timeout": "long" + } + ] + ], + "meta-name-accept-ch-cross-origin-subresource-without-hints.https.sub.html": [ + "7b121294d1e8ba5d295505883468c5b37e1d57de", + [ + null, + { + "timeout": "long" + } + ] + ], "meta-name-cross-origin-iframe-not-setting-other-origins.https.html": [ - "9c263ee789d29184e90257bf07691eb5da22e8c5", + "2a4e3b1295213d9274f887d13549efd784aee6c1", [ null, { @@ -361029,25 +361113,7 @@ ] ], "meta-name-cross-origin-iframe-not-setting-own-origin.https.html": [ - "1e8d1b6a63102456e1c6baec33753bbd98f61601", - [ - null, - { - "timeout": "long" - } - ] - ], - "meta-name-cross-origin-iframe-with-hints.https.sub.html": [ - "f74e4f4c34bdfd3bae08dad2ee949637b1d1bca9", - [ - null, - { - "timeout": "long" - } - ] - ], - "meta-name-cross-origin-iframe-without-hints.https.sub.html": [ - "bb9ced2c8695e63dd286dbee48b8cba306ad9b5c", + "2c17fd47ff3bb4262546034c6ee86fb0347ba560", [ null, { @@ -361056,25 +361122,7 @@ ] ], "meta-name-cross-origin-navigation.https.html": [ - "d5a46ed2d11d330ceb5b26bdfce0b40340286878", - [ - null, - { - "timeout": "long" - } - ] - ], - "meta-name-cross-origin-subresource-with-hints.https.sub.html": [ - "67c0727eb79f09d92821223fbe54c568ea6a8bd6", - [ - null, - { - "timeout": "long" - } - ] - ], - "meta-name-cross-origin-subresource-without-hints.https.sub.html": [ - "a96ec4d794682c7eb74e24f9746789c3a610fe77", + "c7ab68e1e1544e9b80643da966ac37299b56ce35", [ null, { @@ -361083,7 +361131,7 @@ ] ], "meta-name-cross-origin-subresource.https.html": [ - "f29a4bec458f408ffae0067cd4d3b632f23c3a33", + "b2a4103f1a443e0e52312c727c321ef6f5ec3e89", [ null, { @@ -361092,14 +361140,14 @@ ] ], "meta-name-same-origin-iframe.https.html": [ - "73201072084dd181d97bc66cc302e9ff04335565", + "3f240c9c21e434dc4715656c63adbb190b6d577a", [ null, {} ] ], "meta-name-same-origin-navigation.https.html": [ - "6e9dc706fefc1d91ee6b8dbfa89a77b94ebf0044", + "4561553a8c267b9c07ed452b8c410a7e55e55494", [ null, { @@ -361108,7 +361156,7 @@ ] ], "meta-name-same-origin-subresource.https.html": [ - "98b41674e9f6f0b564b60bed8ec0667a9e0e070e", + "3c0447c94d7a6e46d1b65a9f135316e1077aa08a", [ null, { @@ -361336,6 +361384,41 @@ {} ] ], + "meta-equiv-delegate-ch-iframe.https.html": [ + "2ce9c63c18a6a9455e31bf96dba82097056ccbd2", + [ + null, + {} + ] + ], + "meta-equiv-delegate-ch-injection.https.html": [ + "94c0f251a475ee430e9d9b0bdde40b5b9dc3d9a3", + [ + null, + {} + ] + ], + "meta-equiv-delegate-ch-malformed-header.https.html": [ + "a4b91fd99bc42a9942b7e3a6b57c1924e213feda", + [ + null, + {} + ] + ], + "meta-equiv-delegate-ch-merge.https.html": [ + "36fd44940411605ec30f2c4e0b72744d438e0fbd", + [ + null, + {} + ] + ], + "meta-equiv-delegate-ch-non-secure.http.html": [ + "1fbe62c281eb493bb92654ded75af973c4cf55ae", + [ + null, + {} + ] + ], "meta-name-accept-ch-iframe.https.html": [ "6332decd3288ce7f92a8b8be930c32488430da57", [ @@ -371015,7 +371098,7 @@ }, "path": { "default.html": [ - "031bc748408baf209c9973235753782678772408", + "dbe99a7ee59ab05ae5663cf1cb53099e5012eecd", [ null, { @@ -371024,7 +371107,7 @@ ] ], "match.html": [ - "35402839fc1e3b8808bc5ca75ed266a07c0cb5da", + "d517836e4dd64d03c3b38886f812a65026d6d53a", [ null, { @@ -442997,7 +443080,7 @@ ] ], "browsing-context.html": [ - "b2900d367a4b310ab8b08e37aaae604152b58be1", + "59367b0428822c7218d62b7da277b53c22e40d54", [ null, {}
diff --git a/third_party/blink/web_tests/external/wpt/cookies/path/default.html b/third_party/blink/web_tests/external/wpt/cookies/path/default.html index 031bc74..dbe99a7 100644 --- a/third_party/blink/web_tests/external/wpt/cookies/path/default.html +++ b/third_party/blink/web_tests/external/wpt/cookies/path/default.html
@@ -31,13 +31,13 @@ !!iframe.contentWindow.isCookieSet('cookies-path-default'), 'cookie can be retrieved from expected path' ); - iframe.contentWindow.expireCookies().then(() => { + iframe.contentWindow.expireCookies().then(t.step_func(function () { assert_false( !!iframe.contentWindow.isCookieSet('cookies-path-default'), 'cookie can be referenced using the expected path' ); t.done(); - }); + })); }); createIframe('/cookies/resources/echo-cookie.html', t.step_func(function (_iframe) {
diff --git a/third_party/blink/web_tests/external/wpt/cookies/path/match.html b/third_party/blink/web_tests/external/wpt/cookies/path/match.html index 35402839..d517836 100644 --- a/third_party/blink/web_tests/external/wpt/cookies/path/match.html +++ b/third_party/blink/web_tests/external/wpt/cookies/path/match.html
@@ -41,14 +41,14 @@ iframe.contentWindow.fetchCookieThen('header-' + testCase.name, testCase.path).then(test.step_func(function (response) { assert_true(response.ok); var cookieSet = iframe.contentWindow.isCookieSet('header-' + testCase.name, testCase.path); - iframe.contentWindow.expireCookies().then(() => { + iframe.contentWindow.expireCookies().then(test.step_func(function () { if (testCase.match === false) { assert_equals(cookieSet, null); } else { assert_not_equals(cookieSet, null, "Cookie path from header should not be `null`"); } test.done(); - }); + })); })).catch(test.unreached_func()); })); };
diff --git a/third_party/blink/web_tests/external/wpt/css/css-cascade/layer-statement-copy-crash.html b/third_party/blink/web_tests/external/wpt/css/css-cascade/layer-statement-copy-crash.html new file mode 100644 index 0000000..f183ab3 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-cascade/layer-statement-copy-crash.html
@@ -0,0 +1,10 @@ +<!DOCTYPE html> +<title>Chromium bug: Crash when copying layer statement rule from memory cache</title> +<link rel="help" href="https://www.w3.org/TR/css-cascade-5/#layer-empty"> +<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1345181"> +<link rel="author" href="mailto:xiaochengh@chromium.org"> +<link rel="stylesheet" href="data:text/css,@layer foo;@media(all){}"> +<link rel="stylesheet" href="data:text/css,@layer foo;@media(all){}"> +<body> + <p style="color: green">Test passes if it does not crash.</p> +</body>
diff --git a/third_party/blink/web_tests/platform/generic/http/tests/devtools/elements/iframe-load-event-expected.txt b/third_party/blink/web_tests/platform/generic/http/tests/devtools/elements/iframe-load-event-expected.txt index f338ff6..f907cb9 100644 --- a/third_party/blink/web_tests/platform/generic/http/tests/devtools/elements/iframe-load-event-expected.txt +++ b/third_party/blink/web_tests/platform/generic/http/tests/devtools/elements/iframe-load-event-expected.txt
@@ -14,7 +14,6 @@ <head></head> - <body> <div id="iframe-2-element"></div> - #top-layer </body> </html> </iframe>
diff --git a/third_party/nearby/README.chromium b/third_party/nearby/README.chromium index 01f113f9..37976356 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: bbf6de9d12bcbe2e709ea06b2ec06b4598295fe5 +Version: eaac8d045d44a2592c927f0440328b1b96538b59 License: Apache 2.0 License File: LICENSE Security Critical: yes
diff --git a/third_party/protobuf/README.chromium b/third_party/protobuf/README.chromium index f2cfe81b..bfcfd86 100644 --- a/third_party/protobuf/README.chromium +++ b/third_party/protobuf/README.chromium
@@ -116,3 +116,11 @@ See https://github.com/protocolbuffers/protobuf/issues/10186. See https://bugs.chromium.org/p/chromium/issues/detail?id=1294200#c26. + +- 0032-cxx20.patch + + Fixes necessary to build in --std=c++20 mode. + + Imports https://critique.corp.google.com/cl/451177197 (a portion of + https://github.com/protocolbuffers/protobuf/commit/6dd8af4ecfa7987bddb309862932886b84f1e4ef + ). \ No newline at end of file
diff --git a/third_party/protobuf/patches/0032-cxx20.patch b/third_party/protobuf/patches/0032-cxx20.patch new file mode 100644 index 0000000..2805819 --- /dev/null +++ b/third_party/protobuf/patches/0032-cxx20.patch
@@ -0,0 +1,114 @@ +diff --git a/src/google/protobuf/generated_message_tctable_impl.h b/src/google/protobuf/generated_message_tctable_impl.h +index 441a4293a9985..147c7727afd04 100644 +--- a/src/google/protobuf/generated_message_tctable_impl.h ++++ b/src/google/protobuf/generated_message_tctable_impl.h +@@ -183,48 +183,48 @@ static_assert(kFmtShift + kFmtBits <= 16, "too many bits"); + // Convenience aliases (16 bits, with format): + enum FieldType : uint16_t { + // Numeric types: +- kBool = kFkVarint | kRep8Bits, +- +- kFixed32 = kFkFixed | kRep32Bits | kFmtUnsigned, +- kUInt32 = kFkVarint | kRep32Bits | kFmtUnsigned, +- kSFixed32 = kFkFixed | kRep32Bits | kFmtSigned, +- kInt32 = kFkVarint | kRep32Bits | kFmtSigned, +- kSInt32 = kFkVarint | kRep32Bits | kFmtSigned | kTvZigZag, +- kFloat = kFkFixed | kRep32Bits | kFmtFloating, +- kEnum = kFkVarint | kRep32Bits | kFmtEnum | kTvEnum, +- kEnumRange = kFkVarint | kRep32Bits | kFmtEnum | kTvRange, +- kOpenEnum = kFkVarint | kRep32Bits | kFmtEnum, +- +- kFixed64 = kFkFixed | kRep64Bits | kFmtUnsigned, +- kUInt64 = kFkVarint | kRep64Bits | kFmtUnsigned, +- kSFixed64 = kFkFixed | kRep64Bits | kFmtSigned, +- kInt64 = kFkVarint | kRep64Bits | kFmtSigned, +- kSInt64 = kFkVarint | kRep64Bits | kFmtSigned | kTvZigZag, +- kDouble = kFkFixed | kRep64Bits | kFmtFloating, +- +- kPackedBool = kFkPackedVarint | kRep8Bits, +- +- kPackedFixed32 = kFkPackedFixed | kRep32Bits | kFmtUnsigned, +- kPackedUInt32 = kFkPackedVarint | kRep32Bits | kFmtUnsigned, +- kPackedSFixed32 = kFkPackedFixed | kRep32Bits | kFmtSigned, +- kPackedInt32 = kFkPackedVarint | kRep32Bits | kFmtSigned, +- kPackedSInt32 = kFkPackedVarint | kRep32Bits | kFmtSigned | kTvZigZag, +- kPackedFloat = kFkPackedFixed | kRep32Bits | kFmtFloating, +- kPackedEnum = kFkPackedVarint | kRep32Bits | kFmtEnum | kTvEnum, +- kPackedEnumRange = kFkPackedVarint | kRep32Bits | kFmtEnum | kTvRange, +- kPackedOpenEnum = kFkPackedVarint | kRep32Bits | kFmtEnum, +- +- kPackedFixed64 = kFkPackedFixed | kRep64Bits | kFmtUnsigned, +- kPackedUInt64 = kFkPackedVarint | kRep64Bits | kFmtUnsigned, +- kPackedSFixed64 = kFkPackedFixed | kRep64Bits | kFmtSigned, +- kPackedInt64 = kFkPackedVarint | kRep64Bits | kFmtSigned, +- kPackedSInt64 = kFkPackedVarint | kRep64Bits | kFmtSigned | kTvZigZag, +- kPackedDouble = kFkPackedFixed | kRep64Bits | kFmtFloating, ++ kBool = 0 | kFkVarint | kRep8Bits, ++ ++ kFixed32 = 0 | kFkFixed | kRep32Bits | kFmtUnsigned, ++ kUInt32 = 0 | kFkVarint | kRep32Bits | kFmtUnsigned, ++ kSFixed32 = 0 | kFkFixed | kRep32Bits | kFmtSigned, ++ kInt32 = 0 | kFkVarint | kRep32Bits | kFmtSigned, ++ kSInt32 = 0 | kFkVarint | kRep32Bits | kFmtSigned | kTvZigZag, ++ kFloat = 0 | kFkFixed | kRep32Bits | kFmtFloating, ++ kEnum = 0 | kFkVarint | kRep32Bits | kFmtEnum | kTvEnum, ++ kEnumRange = 0 | kFkVarint | kRep32Bits | kFmtEnum | kTvRange, ++ kOpenEnum = 0 | kFkVarint | kRep32Bits | kFmtEnum, ++ ++ kFixed64 = 0 | kFkFixed | kRep64Bits | kFmtUnsigned, ++ kUInt64 = 0 | kFkVarint | kRep64Bits | kFmtUnsigned, ++ kSFixed64 = 0 | kFkFixed | kRep64Bits | kFmtSigned, ++ kInt64 = 0 | kFkVarint | kRep64Bits | kFmtSigned, ++ kSInt64 = 0 | kFkVarint | kRep64Bits | kFmtSigned | kTvZigZag, ++ kDouble = 0 | kFkFixed | kRep64Bits | kFmtFloating, ++ ++ kPackedBool = 0 | kFkPackedVarint | kRep8Bits, ++ ++ kPackedFixed32 = 0 | kFkPackedFixed | kRep32Bits | kFmtUnsigned, ++ kPackedUInt32 = 0 | kFkPackedVarint | kRep32Bits | kFmtUnsigned, ++ kPackedSFixed32 = 0 | kFkPackedFixed | kRep32Bits | kFmtSigned, ++ kPackedInt32 = 0 | kFkPackedVarint | kRep32Bits | kFmtSigned, ++ kPackedSInt32 = 0 | kFkPackedVarint | kRep32Bits | kFmtSigned | kTvZigZag, ++ kPackedFloat = 0 | kFkPackedFixed | kRep32Bits | kFmtFloating, ++ kPackedEnum = 0 | kFkPackedVarint | kRep32Bits | kFmtEnum | kTvEnum, ++ kPackedEnumRange = 0 | kFkPackedVarint | kRep32Bits | kFmtEnum | kTvRange, ++ kPackedOpenEnum = 0 | kFkPackedVarint | kRep32Bits | kFmtEnum, ++ ++ kPackedFixed64 = 0 | kFkPackedFixed | kRep64Bits | kFmtUnsigned, ++ kPackedUInt64 = 0 | kFkPackedVarint | kRep64Bits | kFmtUnsigned, ++ kPackedSFixed64 = 0 | kFkPackedFixed | kRep64Bits | kFmtSigned, ++ kPackedInt64 = 0 | kFkPackedVarint | kRep64Bits | kFmtSigned, ++ kPackedSInt64 = 0 | kFkPackedVarint | kRep64Bits | kFmtSigned | kTvZigZag, ++ kPackedDouble = 0 | kFkPackedFixed | kRep64Bits | kFmtFloating, + + // String types: +- kBytes = kFkString | kFmtArray, +- kRawString = kFkString | kFmtUtf8 | kTvUtf8Debug, +- kUtf8String = kFkString | kFmtUtf8 | kTvUtf8, ++ kBytes = 0 | kFkString | kFmtArray, ++ kRawString = 0 | kFkString | kFmtUtf8 | kTvUtf8Debug, ++ kUtf8String = 0 | kFkString | kFmtUtf8 | kTvUtf8, + + // Message types: + kMessage = kFkMessage, +@@ -232,7 +232,6 @@ enum FieldType : uint16_t { + // Map types: + kMap = kFkMap, + }; +- + // clang-format on + } // namespace field_layout + +diff --git a/src/google/protobuf/stubs/common.cc b/src/google/protobuf/stubs/common.cc +index 82d46531f2f55..bec0cabeff8cf 100644 +--- a/src/google/protobuf/stubs/common.cc ++++ b/src/google/protobuf/stubs/common.cc +@@ -178,7 +178,7 @@ void NullLogHandler(LogLevel /* level */, const char* /* filename */, + } + + static LogHandler* log_handler_ = &DefaultLogHandler; +-static std::atomic<int> log_silencer_count_ = ATOMIC_VAR_INIT(0); ++static std::atomic<int> log_silencer_count_{0}; + + LogMessage& LogMessage::operator<<(const std::string& value) { + message_ += value;
diff --git a/third_party/protobuf/src/google/protobuf/generated_message_tctable_impl.h b/third_party/protobuf/src/google/protobuf/generated_message_tctable_impl.h index 441a429..147c7727 100644 --- a/third_party/protobuf/src/google/protobuf/generated_message_tctable_impl.h +++ b/third_party/protobuf/src/google/protobuf/generated_message_tctable_impl.h
@@ -183,48 +183,48 @@ // Convenience aliases (16 bits, with format): enum FieldType : uint16_t { // Numeric types: - kBool = kFkVarint | kRep8Bits, + kBool = 0 | kFkVarint | kRep8Bits, - kFixed32 = kFkFixed | kRep32Bits | kFmtUnsigned, - kUInt32 = kFkVarint | kRep32Bits | kFmtUnsigned, - kSFixed32 = kFkFixed | kRep32Bits | kFmtSigned, - kInt32 = kFkVarint | kRep32Bits | kFmtSigned, - kSInt32 = kFkVarint | kRep32Bits | kFmtSigned | kTvZigZag, - kFloat = kFkFixed | kRep32Bits | kFmtFloating, - kEnum = kFkVarint | kRep32Bits | kFmtEnum | kTvEnum, - kEnumRange = kFkVarint | kRep32Bits | kFmtEnum | kTvRange, - kOpenEnum = kFkVarint | kRep32Bits | kFmtEnum, + kFixed32 = 0 | kFkFixed | kRep32Bits | kFmtUnsigned, + kUInt32 = 0 | kFkVarint | kRep32Bits | kFmtUnsigned, + kSFixed32 = 0 | kFkFixed | kRep32Bits | kFmtSigned, + kInt32 = 0 | kFkVarint | kRep32Bits | kFmtSigned, + kSInt32 = 0 | kFkVarint | kRep32Bits | kFmtSigned | kTvZigZag, + kFloat = 0 | kFkFixed | kRep32Bits | kFmtFloating, + kEnum = 0 | kFkVarint | kRep32Bits | kFmtEnum | kTvEnum, + kEnumRange = 0 | kFkVarint | kRep32Bits | kFmtEnum | kTvRange, + kOpenEnum = 0 | kFkVarint | kRep32Bits | kFmtEnum, - kFixed64 = kFkFixed | kRep64Bits | kFmtUnsigned, - kUInt64 = kFkVarint | kRep64Bits | kFmtUnsigned, - kSFixed64 = kFkFixed | kRep64Bits | kFmtSigned, - kInt64 = kFkVarint | kRep64Bits | kFmtSigned, - kSInt64 = kFkVarint | kRep64Bits | kFmtSigned | kTvZigZag, - kDouble = kFkFixed | kRep64Bits | kFmtFloating, + kFixed64 = 0 | kFkFixed | kRep64Bits | kFmtUnsigned, + kUInt64 = 0 | kFkVarint | kRep64Bits | kFmtUnsigned, + kSFixed64 = 0 | kFkFixed | kRep64Bits | kFmtSigned, + kInt64 = 0 | kFkVarint | kRep64Bits | kFmtSigned, + kSInt64 = 0 | kFkVarint | kRep64Bits | kFmtSigned | kTvZigZag, + kDouble = 0 | kFkFixed | kRep64Bits | kFmtFloating, - kPackedBool = kFkPackedVarint | kRep8Bits, + kPackedBool = 0 | kFkPackedVarint | kRep8Bits, - kPackedFixed32 = kFkPackedFixed | kRep32Bits | kFmtUnsigned, - kPackedUInt32 = kFkPackedVarint | kRep32Bits | kFmtUnsigned, - kPackedSFixed32 = kFkPackedFixed | kRep32Bits | kFmtSigned, - kPackedInt32 = kFkPackedVarint | kRep32Bits | kFmtSigned, - kPackedSInt32 = kFkPackedVarint | kRep32Bits | kFmtSigned | kTvZigZag, - kPackedFloat = kFkPackedFixed | kRep32Bits | kFmtFloating, - kPackedEnum = kFkPackedVarint | kRep32Bits | kFmtEnum | kTvEnum, - kPackedEnumRange = kFkPackedVarint | kRep32Bits | kFmtEnum | kTvRange, - kPackedOpenEnum = kFkPackedVarint | kRep32Bits | kFmtEnum, + kPackedFixed32 = 0 | kFkPackedFixed | kRep32Bits | kFmtUnsigned, + kPackedUInt32 = 0 | kFkPackedVarint | kRep32Bits | kFmtUnsigned, + kPackedSFixed32 = 0 | kFkPackedFixed | kRep32Bits | kFmtSigned, + kPackedInt32 = 0 | kFkPackedVarint | kRep32Bits | kFmtSigned, + kPackedSInt32 = 0 | kFkPackedVarint | kRep32Bits | kFmtSigned | kTvZigZag, + kPackedFloat = 0 | kFkPackedFixed | kRep32Bits | kFmtFloating, + kPackedEnum = 0 | kFkPackedVarint | kRep32Bits | kFmtEnum | kTvEnum, + kPackedEnumRange = 0 | kFkPackedVarint | kRep32Bits | kFmtEnum | kTvRange, + kPackedOpenEnum = 0 | kFkPackedVarint | kRep32Bits | kFmtEnum, - kPackedFixed64 = kFkPackedFixed | kRep64Bits | kFmtUnsigned, - kPackedUInt64 = kFkPackedVarint | kRep64Bits | kFmtUnsigned, - kPackedSFixed64 = kFkPackedFixed | kRep64Bits | kFmtSigned, - kPackedInt64 = kFkPackedVarint | kRep64Bits | kFmtSigned, - kPackedSInt64 = kFkPackedVarint | kRep64Bits | kFmtSigned | kTvZigZag, - kPackedDouble = kFkPackedFixed | kRep64Bits | kFmtFloating, + kPackedFixed64 = 0 | kFkPackedFixed | kRep64Bits | kFmtUnsigned, + kPackedUInt64 = 0 | kFkPackedVarint | kRep64Bits | kFmtUnsigned, + kPackedSFixed64 = 0 | kFkPackedFixed | kRep64Bits | kFmtSigned, + kPackedInt64 = 0 | kFkPackedVarint | kRep64Bits | kFmtSigned, + kPackedSInt64 = 0 | kFkPackedVarint | kRep64Bits | kFmtSigned | kTvZigZag, + kPackedDouble = 0 | kFkPackedFixed | kRep64Bits | kFmtFloating, // String types: - kBytes = kFkString | kFmtArray, - kRawString = kFkString | kFmtUtf8 | kTvUtf8Debug, - kUtf8String = kFkString | kFmtUtf8 | kTvUtf8, + kBytes = 0 | kFkString | kFmtArray, + kRawString = 0 | kFkString | kFmtUtf8 | kTvUtf8Debug, + kUtf8String = 0 | kFkString | kFmtUtf8 | kTvUtf8, // Message types: kMessage = kFkMessage, @@ -232,7 +232,6 @@ // Map types: kMap = kFkMap, }; - // clang-format on } // namespace field_layout
diff --git a/third_party/protobuf/src/google/protobuf/stubs/common.cc b/third_party/protobuf/src/google/protobuf/stubs/common.cc index 82d4653..bec0cab 100644 --- a/third_party/protobuf/src/google/protobuf/stubs/common.cc +++ b/third_party/protobuf/src/google/protobuf/stubs/common.cc
@@ -178,7 +178,7 @@ } static LogHandler* log_handler_ = &DefaultLogHandler; -static std::atomic<int> log_silencer_count_ = ATOMIC_VAR_INIT(0); +static std::atomic<int> log_silencer_count_{0}; LogMessage& LogMessage::operator<<(const std::string& value) { message_ += value;
diff --git a/third_party/unrar/patches/chromium_changes.v6.0.3.patch b/third_party/unrar/patches/chromium_changes.v6.0.3.patch index 2c98ab5..8da395a 100644 --- a/third_party/unrar/patches/chromium_changes.v6.0.3.patch +++ b/third_party/unrar/patches/chromium_changes.v6.0.3.patch
@@ -221,7 +221,7 @@ \ No newline at end of file +#endif diff --git a/third_party/unrar/src/extract.hpp b/third_party/unrar/src/extract.hpp -index 159759b563f5f..9a659591d4f35 100644 +index 159759b563f5f..d38ff8658ecdd 100644 --- a/third_party/unrar/src/extract.hpp +++ b/third_party/unrar/src/extract.hpp @@ -37,8 +37,8 @@ class CmdExtract @@ -235,13 +235,14 @@ // If any non-zero solid file was successfully unpacked before current. // If true and if current encrypted file is broken, obviously -@@ -62,6 +62,10 @@ class CmdExtract +@@ -62,6 +62,11 @@ class CmdExtract void ExtractArchiveInit(Archive &Arc); bool ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat); static void UnstoreFile(ComprDataIO &DataIO,int64 DestUnpSize); + +#if defined(CHROMIUM_UNRAR) + int64 GetCurrentFileSize() { return DataIO.CurUnpWrite; } ++ bool IsMissingNextVolume() { return DataIO.NextVolumeMissing; } +#endif };
diff --git a/third_party/unrar/src/extract.hpp b/third_party/unrar/src/extract.hpp index 9a65959..d38ff865 100644 --- a/third_party/unrar/src/extract.hpp +++ b/third_party/unrar/src/extract.hpp
@@ -65,6 +65,7 @@ #if defined(CHROMIUM_UNRAR) int64 GetCurrentFileSize() { return DataIO.CurUnpWrite; } + bool IsMissingNextVolume() { return DataIO.NextVolumeMissing; } #endif };
diff --git a/third_party/unrar/src/unrar_wrapper.cc b/third_party/unrar/src/unrar_wrapper.cc index 827514b..b20de6fe 100644 --- a/third_party/unrar/src/unrar_wrapper.cc +++ b/third_party/unrar/src/unrar_wrapper.cc
@@ -65,7 +65,24 @@ current_entry_.is_directory = archive_->FileHead.Dir; current_entry_.is_encrypted = archive_->FileHead.Encrypted; current_entry_.file_size = extractor_->GetCurrentFileSize(); - return true; + + if (success) { + return true; + } + + if (archive_->FileHead.Encrypted) { + // Since Chromium doesn't have the password, manually skip over the + // encrypted data and fill in the metadata we do have. + archive_->SeekToNext(); + return true; + } + + if (extractor_->IsMissingNextVolume()) { + // Since Chromium doesn't have the next volume, manually skip over this + // file, but report the metadata we do have. + archive_->SeekToNext(); + return true; + } } }
diff --git a/tools/.gitignore b/tools/.gitignore new file mode 100644 index 0000000..b70f6a3 --- /dev/null +++ b/tools/.gitignore
@@ -0,0 +1 @@ +bazel
diff --git a/tools/infra/builder-cache-clobber.py b/tools/infra/builder-cache-clobber.py index 8bf60f4..9a09809 100755 --- a/tools/infra/builder-cache-clobber.py +++ b/tools/infra/builder-cache-clobber.py
@@ -33,7 +33,7 @@ clobber_cache_utils.clobber_caches(args.swarming_server, pool, - 'chromium:%s' % args.bucket, + '%s:%s' % (args.project, args.bucket), cache, 'cache/builder', args.dry_run,
diff --git a/tools/infra/clobber_cache_utils.py b/tools/infra/clobber_cache_utils.py index 09e19b3..0cd455a 100644 --- a/tools/infra/clobber_cache_utils.py +++ b/tools/infra/clobber_cache_utils.py
@@ -115,6 +115,10 @@ bots = [bot_id] else: bots = _get_bots(swarming_server, pool, cache) + if not bots: + print(f'There are no bots on swarming server {swarming_server}' + f' in pool {pool} that have cache {cache}') + return 0 print('The following bots will be clobbered:') print()
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index bfce1cbf..cc03626 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -3972,6 +3972,11 @@ <int value="8" label="Hash code collides with multiple accounts"/> </enum> +<enum name="ArcAuthReauthReason"> + <int value="0" label="AndroidID is missing"/> + <int value="1" label="Main account is missing"/> +</enum> + <enum name="ArcBootContinueCodeInstallationResult"> <int value="0" label="Success"/> <int value="1" label="Host side code is not ready"/> @@ -18975,6 +18980,14 @@ <int value="3" label="Invalid data"/> </enum> +<enum name="ConversionDestinationLimitResult"> + <int value="0" label="Allowed by pending, allowed by unexpired"/> + <int value="1" label="Allowed by pending, dropped by unexpired"/> + <int value="2" label="Dropped by pending, allowed by unexpired"/> + <int value="3" label="Dropped by pending, dropped by unexpired"/> + <int value="4" label="Error"/> +</enum> + <enum name="ConversionNavigationDataHostStatus"> <int value="0" label="Registered"/> <int value="1" label="Not found"/> @@ -55765,6 +55778,7 @@ <int value="-1897800883" label="OpenscreenCastStreamingSession:enabled"/> <int value="-1896871201" label="CrossOriginOpenerPolicyReporting:enabled"/> <int value="-1896733769" label="CheckOfflineCapability:disabled"/> + <int value="-1896571373" label="RegionCaptureExperimentalSubtypes:disabled"/> <int value="-1896394207" label="PasswordChange:disabled"/> <int value="-1895719323" label="VrBrowsingTabsView:enabled"/> <int value="-1895050832" label="GlobalMediaControlsCastStartStop:disabled"/> @@ -58089,6 +58103,7 @@ <int value="-444867364" label="Metal:enabled"/> <int value="-442352394" label="IframeOneGoogleBar:disabled"/> <int value="-438379844" label="SwapSideVolumeButtonsForOrientation:enabled"/> + <int value="-438029951" label="RegionCaptureExperimentalSubtypes:enabled"/> <int value="-437292646" label="DeferBeginMainFrameDuringLoading:enabled"/> <int value="-436470115" label="TouchpadAndWheelScrollLatching:enabled"/> <int value="-435914745" label="ClipboardContentSetting:disabled"/> @@ -71884,6 +71899,18 @@ <int value="59" label="Ecosia"/> </enum> +<enum name="OmniboxSuggestionUiType"> + <int value="0" label="DEFAULT"/> + <int value="1" label="EDIT_URL_SUGGESTION"/> + <int value="2" label="ANSWER_SUGGESTION"/> + <int value="3" label="ENTITY_SUGGESTION"/> + <int value="4" label="TAIL_SUGGESTION"/> + <int value="5" label="CLIPBOARD_SUGGESTION"/> + <int value="6" label="HEADER"/> + <int value="7" label="TILE_NAVSUGGEST"/> + <int value="8" label="PEDAL_SUGGESTION"/> +</enum> + <enum name="OmniboxSuggestRequests"> <int value="1" label="requests sent"/> <int value="2" label="requests invalidated"/>
diff --git a/tools/metrics/histograms/metadata/android/histograms.xml b/tools/metrics/histograms/metadata/android/histograms.xml index 6678412..303106c 100644 --- a/tools/metrics/histograms/metadata/android/histograms.xml +++ b/tools/metrics/histograms/metadata/android/histograms.xml
@@ -2667,6 +2667,29 @@ </token> </histogram> +<histogram name="Android.Omnibox.SuggestionView.CreatedType" + enum="OmniboxSuggestionUiType" expires_after="2023-07-01"> + <owner>ender@google.com</owner> + <owner>gangwu@chromium.org</owner> + <owner>rongtan@chromium.org</owner> + <summary> + Records the type of suggestion that was reused with the help of + RecyclerView. + + This histogram drives OmniboxSuggestionsDropdown optimization, helping us + find the balance between the volume of suggestions and amount of memory we + delegate to re-use the pre-constructed suggestion views. + + Along with the Android.Omnibox.SuggestionView.ReusedType, the two histograms + paint the picture of which suggestions need to be created more often than + others vs which suggestions have more capacity than is actually needed. + Higher reuse means lower latency at the expense of slight increase of memory + consumption. + + This histogram is related to Android.Omnibox.SuggestionView.ReusedType. + </summary> +</histogram> + <histogram name="Android.Omnibox.SuggestionView.CreateTime" units="microseconds" expires_after="2022-06-19"> <obsolete> @@ -2747,6 +2770,29 @@ </summary> </histogram> +<histogram name="Android.Omnibox.SuggestionView.ReusedType" + enum="OmniboxSuggestionUiType" expires_after="2023-07-01"> + <owner>ender@google.com</owner> + <owner>gangwu@chromium.org</owner> + <owner>rongtan@chromium.org</owner> + <summary> + Records the type of suggestion that was reused with the help of + RecyclerView. + + This histogram drives OmniboxSuggestionsDropdown optimization, helping us + find the balance between the volume of suggestions and amount of memory we + delegate to re-use the pre-constructed suggestion views. + + Along with the Android.Omnibox.SuggestionView.CreatedType, the two + histograms paint the picture of which suggestions need to be created more + often than others vs which suggestions have more capacity than is actually + needed. Higher reuse means lower latency at the expense of slight increase + of memory consumption. + + This histogram is related to Android.Omnibox.SuggestionView.CreatedType. + </summary> +</histogram> + <histogram name="Android.Omnibox.UsedSuggestionFromCache" enum="Boolean" expires_after="2022-09-04"> <owner>ender@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/arc/histograms.xml b/tools/metrics/histograms/metadata/arc/histograms.xml index 4a17871..9366a4b 100644 --- a/tools/metrics/histograms/metadata/arc/histograms.xml +++ b/tools/metrics/histograms/metadata/arc/histograms.xml
@@ -539,6 +539,18 @@ </summary> </histogram> +<histogram name="Arc.Auth.Reauth.Reason{ArcUserTypes}" + enum="ArcAuthReauthReason" expires_after="2022-12-04"> + <owner>mhasank@google.com</owner> + <owner>arc-core@google.com</owner> + <summary> + Records why ARC restarted the provisioning flow by reauthenticating and + adding the user to ARC. This happens when ARC detects missing AndroidID or + primary user in the Account Manager. {ArcUserTypes} + </summary> + <token key="ArcUserTypes" variants="ArcUserTypes"/> +</histogram> + <histogram name="Arc.Auth.RequestAccountInfoResult.Primary" enum="ArcAuthCodeStatus" expires_after="2022-12-04"> <owner>anastasiian@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/navigation/histograms.xml b/tools/metrics/histograms/metadata/navigation/histograms.xml index cbfc167..4a0a330 100644 --- a/tools/metrics/histograms/metadata/navigation/histograms.xml +++ b/tools/metrics/histograms/metadata/navigation/histograms.xml
@@ -1186,6 +1186,19 @@ <token key="FrameType" variants="FrameTypes"/> </histogram> +<histogram + name="Navigation.RendererInitiatedCancellation.DeferStartToCancellationWindowEnd" + units="ms" expires_after="2022-10-21"> + <owner>rakina@chromium.org</owner> + <owner>dcheng@chromium.org</owner> + <summary> + Measures the amount of time it takes from + RendererCancellationThrottle::WillProcessResponse() to + RendererCancellationThrottle::NavigationCancellationWindowEnded. Recorded + for each navigation that gets deferred by RendererCancellationThrottle. + </summary> +</histogram> + <histogram name="Navigation.RequiresDedicatedProcess" enum="NavigationRequiresDedicatedProcess" expires_after="2022-10-09"> <owner>alexmos@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/new_tab_page/histograms.xml b/tools/metrics/histograms/metadata/new_tab_page/histograms.xml index f81e297..231f798 100644 --- a/tools/metrics/histograms/metadata/new_tab_page/histograms.xml +++ b/tools/metrics/histograms/metadata/new_tab_page/histograms.xml
@@ -104,6 +104,20 @@ </summary> </histogram> +<histogram name="NewTabPage.Carts.CartImageCount" units="count" + expires_after="2022-12-25"> + <owner>yuezhanggg@chromium.org</owner> + <owner>chrome-shopping@google.com</owner> + <summary> + Logged when the cart module is created and is recorded once for every cart. + It records the number of product images in this cart (could be zero). This + is not logged when welcome surface is showing. Only logged on the 1P NTP. + Note that even if the user has Google as their default search engine, + Incognito and Guest mode NTPs are not considered 1P and don't log this + histogram. + </summary> +</histogram> + <histogram name="NewTabPage.Carts.ClickCart" units="index" expires_after="2022-11-20"> <owner>wychen@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/others/histograms.xml b/tools/metrics/histograms/metadata/others/histograms.xml index 925201d8..bbe950b3 100644 --- a/tools/metrics/histograms/metadata/others/histograms.xml +++ b/tools/metrics/histograms/metadata/others/histograms.xml
@@ -4067,6 +4067,19 @@ </summary> </histogram> +<histogram name="Conversions.UniqueDestinationLimitForUnexpiredSourcesResult" + enum="ConversionDestinationLimitResult" expires_after="2023-01-06"> + <owner>linnan@chromium.org</owner> + <owner>johnidel@chromium.org</owner> + <owner>measurement-api-dev+metrics@google.com</owner> + <summary> + Records the result of checking whether an attribution source is allowed by + the unique destination limit covered by unexpired sources, compared with the + result covered by pending sources. Recorded once for each source + registration if there is capacity to store sources. + </summary> +</histogram> + <histogram name="Conversions.UniqueReportingOriginsPerPage.Conversions" units="origins" expires_after="2022-10-04"> <obsolete>
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json index 3003aad..bfa6b37 100644 --- a/tools/perf/core/perfetto_binary_roller/binary_deps.json +++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -5,8 +5,8 @@ "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux_arm64/49b4b5dcbc312d8d2c3751cf29238b8efeb4e494/trace_processor_shell" }, "win": { - "hash": "8a7722a7f65befafb85267321827bb143efd170f", - "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/5c68a10eb7b4ef9cc13dcd5d0a7b9b2f1c65e710/trace_processor_shell.exe" + "hash": "9c7a24c9249a1d939eba719007fca355cd420dde", + "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/ac8e40ad9eda05b00c491201b9cffbeaad8f566e/trace_processor_shell.exe" }, "linux_arm": { "hash": "58893933be305d3bfe0a72ebebcacde2ac3ca893",
diff --git a/tools/rust/README.md b/tools/rust/README.md new file mode 100644 index 0000000..de65d4a --- /dev/null +++ b/tools/rust/README.md
@@ -0,0 +1,115 @@ +# //tools/rust + +This directory contains scripts for building, packaging, and distributing the +Rust toolchain (the Rust compiler, and also C++/Rust FFI tools like +[Crubit](https://github.com/google/crubit)). + + +## Rolling Rust compiler and other Rust tools + +Steps to roll the Rust compiler (and other Rust tools like `rustfmt`) to +a new version: +- Locally, update `RUST_REVISION` in `update_rust.py`. + (Update `RUST_SUB_REVISION` when the build or packaging is changed, but + the upstream Rust revision we build from is not changed.) +- Follow the general roll process below + + +## Rolling Crubit tools + +Steps to roll the Crubit tools (e.g. `rs_bindings_from_cc` tool) +to a new version: + +- Locally, update `CRUBIT_REVISION` in `build_crubit.py`. + (Update `CRUBIT_SUB_REVISION` when the build or packaging is changed, but + the upstream Rust revision we build from is not changed.) + TODO(https://crbug.com/1329611): Move `CRUBIT_REVISION` to + `update_rust.py` (see WIP CL: https://crrev.com/c/3718281). + +- Locally, update `crubit_revision` in `//DEPS`, so that it matches + the revision from the previous bullet item. + +- Run manual tests locally (see the "Building and testing the tools locally" + section below). + TODO(https://crbug.com/1329611): These manual steps should + be made obsolete once Rust-specific tryjobs cover Crubit + tests. + +- Follow the general roll process below + + +## General roll process + +- Author a CL that updates `CRUBIT_REVISION` and/or `RUST_REVISION` + (see one of the sections above for details). + +- Upload the CL to Gerrit. + Ask [CQ](//docs/infra/cq.md) for Rust-specific tryjobs in the CL description: + `Cq-Include-Tryjobs: + luci.chromium.try:linux-rust-x64-rel,linux-rust-x64-dbg,android-rust-arm-rel,android-rust-arm-dbg`. + +- Run `linux_upload_clang` tryjob. This will run `package_rust.py` which will + `build_rust.py` and then upload a new version of the Rust toolchain package to + the staging bucket. + TODO(https://crbug.com/1329611): In the future this will also run + `build_crubit.py` - we should update the docs once that happens. + +- Move the new toolchain package from staging to prod. + (A small set of people have the permission for this. There are + some Google-internal docs with more details.) + +- Run CQ (see also `Cq-Include-Tryjobs` suggested above). + This step will test that `gclient sync` can fetch the new Rust toolchain + package + that the new package works fine in Chromium build. + +- Land the CL. The new package won't be used outside of this CL + until this step. + + +## Building and testing the tools locally + +### Prerequisites + +`build_crubit.py` depends on having a locally-built LLVM/Clang: +`tools/clang/scripts/build.py --bootstrap --without-android --without-fuchsia`. +Among other things this prerequisite is required to generate +`third_party/llvm-bootstrap-install` where `build_crubit.py` will look for +LLVM/Clang libs and headers). + +`build_crubit.py` depends on Bazel. +TODO(https://crbug.com/1329611): Provide instructions for using `checkout_bazel` +in `.gclient` after https://crrev.com/c/3763581 lands. + +So far `build_crubit.py` has only been tested on Linux hosts. + +### Building + +Just run `tools/rust/build_rust.py` or `tools/rust/build_crubit.py`. + +### Deploying + +`build_rust.py` by default copies the newly build executables/binaries into +`//third_party/rust-toolchain`. Currently a manual step is needed to copy +Crubit binaries (note that the `_impl` suffix has been dropped from the binary +name during the copy - this is expected): + +```sh +cp \ + third_party/crubit/bazel-bin/rs_bindings_from_cc/rs_bindings_from_cc_impl \ + third_party/rust-toolchain/rs_bindings_from_cc +``` + +### Testing + +Ensure that `args.gn` contains `enable_rust = true` and then build +`//build/rust/tests` directory - e.g. `ninja -C out/rust build/rust/tests`. + +Native Rust tests from `//build/rust` can be run via +`out/rust/bin/run_build_rust_tests`. + +Crubit tests are under `//build/rust/tests/test_rs_bindings_from_cc`. Until +Crubit is built on the bots, the tests are commented out in +`//build/rust/tests/BUILD.gn`, but they should still be built and run before +rolling Crubit. TODO(https://crbug.com/1329611): Rephrase this paragraph +after Crubit is built and tested on the bots. +
diff --git a/tools/rust/build_crubit.py b/tools/rust/build_crubit.py index e6ac86f5..ebb42123 100755 --- a/tools/rust/build_crubit.py +++ b/tools/rust/build_crubit.py
@@ -35,18 +35,20 @@ STAGE0_JSON_SHA256, THIRD_PARTY_DIR, GetPackageVersion) -# Trunk on 2022-07-13. +# Trunk on 2022-07-14. # # The revision specified below should typically be the same as the -# `crubit_revision` specified in the //DEPS file. +# `crubit_revision` specified in the //DEPS file. More details and roll +# instructions can be found in tools/rust/README.md. # # TODO(https://crbug.com/1329611): Move `CRUBIT_REVISION` to `update_rust.py` # (see WIP CL: https://crrev.com/c/3718281). -CRUBIT_REVISION = '07b3390a62412543c80226db44eecc317bbfcee0' +CRUBIT_REVISION = 'd9b0ad4c09b46328dcc7a5ec28ce86cca56e0389' CRUBIT_SUB_REVISION = 1 THIRD_PARTY_DIR = os.path.join(CHROMIUM_DIR, 'third_party') CRUBIT_SRC_DIR = os.path.join(THIRD_PARTY_DIR, 'crubit', 'src') +BAZEL_EXE = os.path.join(CHROMIUM_DIR, 'tools', 'bazel', 'bazel') def RunCommand(command, env=None, cwd=None, fail_hard=True): @@ -137,7 +139,7 @@ # 2. extra_args += ["--dynamic_mode=off"] # Run bazel build ... - args = ["bazel", "build", "rs_bindings_from_cc:rs_bindings_from_cc_impl"] + args = [BAZEL_EXE, "build", "rs_bindings_from_cc:rs_bindings_from_cc_impl"] RunCommand(args + extra_args, env=env, cwd=CRUBIT_SRC_DIR) @@ -145,7 +147,7 @@ # This needs to use the same arguments as BuildCrubit, because otherwise # we get: WARNING: Running Bazel server needs to be killed, because the # startup options are different. - RunCommand(["bazel", "shutdown"], cwd=CRUBIT_SRC_DIR) + RunCommand([BAZEL_EXE, "shutdown"], cwd=CRUBIT_SRC_DIR) def main():
diff --git a/tools/traffic_annotation/auditor/chromeos/safe_list.txt b/tools/traffic_annotation/auditor/chromeos/safe_list.txt index d61897e..8f0599fe 100644 --- a/tools/traffic_annotation/auditor/chromeos/safe_list.txt +++ b/tools/traffic_annotation/auditor/chromeos/safe_list.txt
@@ -28,10 +28,10 @@ all,chrome/browser/ash/net/network_diagnostics/tls_prober.cc all,ash/quick_pair/repository/fast_pair/fast_pair_image_decoder.cc all,chrome/browser/search/background/ntp_background_service.cc -all,chromeos/components/quick_answers/result_loader.cc all,chrome/browser/apps/app_service/webapk/webapk_install_task.cc all,chrome/browser/ash/login/saml/password_sync_token_fetcher.cc all,chrome/browser/ash/login/screens/recommend_apps/recommend_apps_fetcher_impl.cc all,chrome/browser/ash/wilco_dtc_supportd/wilco_dtc_supportd_web_request_service.cc all,chrome/browser/ui/app_list/search/arc/recommend_apps_fetcher_impl.cc -all,chromeos/components/projector_app/projector_xhr_sender.cc +all,chrome/services/cups_proxy/socket_manager.cc +all,chromeos/components/projector_app/projector_xhr_sender.cc \ No newline at end of file
diff --git a/tools/traffic_annotation/summary/annotations.xml b/tools/traffic_annotation/summary/annotations.xml index 04c19690..e15c6ad 100644 --- a/tools/traffic_annotation/summary/annotations.xml +++ b/tools/traffic_annotation/summary/annotations.xml
@@ -379,6 +379,7 @@ <item id="pending_beacon_api" added_in_milestone="105" content_hash_code="02288864" os_list="linux,windows,android,chromeos" file_path="content/browser/renderer_host/pending_beacon_service.cc" /> <item id="printing_server_printers_query" added_in_milestone="106" content_hash_code="06f4759c" os_list="chromeos" file_path="chrome/browser/ash/printing/server_printers_fetcher.cc" /> <item id="download_bubble_retry_download" added_in_milestone="105" content_hash_code="000b1439" os_list="linux,windows,chromeos" file_path="chrome/browser/download/bubble/download_bubble_controller.cc" /> + <item id="quick_answers_loader" added_in_milestone="105" content_hash_code="01dd7d56" os_list="chromeos" file_path="chromeos/components/quick_answers/result_loader.cc" /> <item id="chrome_search_suggest_service" added_in_milestone="105" content_hash_code="04d973c6" os_list="linux,windows,android" file_path="components/search/start_suggest_service.cc" /> <item id="coupon_persisted_tab_data" added_in_milestone="105" content_hash_code="006dcd97" os_list="android" file_path="chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/state/CouponPersistedTabData.java" /> </annotations>
diff --git a/tools/traffic_annotation/summary/grouping.xml b/tools/traffic_annotation/summary/grouping.xml index 4a4d941..5718720 100644 --- a/tools/traffic_annotation/summary/grouping.xml +++ b/tools/traffic_annotation/summary/grouping.xml
@@ -249,6 +249,7 @@ <annotation id="borealis_splash_logo_loader"/> <annotation id="pending_beacon_api"/> <annotation id="download_bubble_retry_download"/> + <annotation id="quick_answers_loader"/> <annotation id="chrome_search_suggest_service"/> <annotation id="coupon_persisted_tab_data"/> </sender>
diff --git a/ui/accelerated_widget_mac/io_surface_context.h b/ui/accelerated_widget_mac/io_surface_context.h index a468782..e891ca3 100644 --- a/ui/accelerated_widget_mac/io_surface_context.h +++ b/ui/accelerated_widget_mac/io_surface_context.h
@@ -52,7 +52,7 @@ IOSurfaceContext( Type type, base::ScopedTypeRef<CGLContextObj> clg_context_strong); - virtual ~IOSurfaceContext(); + ~IOSurfaceContext() override; Type type_; base::ScopedTypeRef<CGLContextObj> cgl_context_;
diff --git a/ui/accessibility/mojom/BUILD.gn b/ui/accessibility/mojom/BUILD.gn index 226bbaa1..af01cc9 100644 --- a/ui/accessibility/mojom/BUILD.gn +++ b/ui/accessibility/mojom/BUILD.gn
@@ -27,7 +27,27 @@ "//url/mojom:url_mojom_gurl", ] - cpp_typemaps = [ + common_typemaps = [ + { + types = [ + { + mojom = "ax.mojom.AXRelativeBounds" + cpp = "::ui::AXRelativeBounds" + }, + ] + traits_headers = [ "ax_relative_bounds_mojom_traits.h" ] + traits_public_deps = [ + ":mojom_traits", + "//ui/gfx", + "//ui/gfx/geometry/mojom", + "//ui/gfx/geometry/mojom:mojom_traits", + "//ui/gfx/mojom", + ] + }, + ] + + cpp_typemaps = common_typemaps + cpp_typemaps += [ { types = [ { @@ -79,12 +99,10 @@ cpp = "::ui::AXRelativeBounds" }, ] - traits_sources = [ "ax_relative_bounds_mojom_traits.cc" ] traits_headers = [ "ax_relative_bounds_mojom_traits.h" ] traits_public_deps = [ - "//ui/gfx", + "//ui/accessibility:ax_base", "//ui/gfx/geometry/mojom", - "//ui/gfx/geometry/mojom:mojom_traits", "//ui/gfx/mojom", ] }, @@ -122,7 +140,10 @@ traits_public_deps = [ "//ui/accessibility:ax_base" ] }, ] + + blink_cpp_typemaps = common_typemaps } + mojom("ax_assistant_mojom") { sources = [ "ax_assistant_structure.mojom" ] @@ -161,3 +182,17 @@ "//url/mojom:url_mojom_gurl", ] } + +source_set("mojom_traits") { + sources = [ + "ax_relative_bounds_mojom_traits.cc", + "ax_relative_bounds_mojom_traits.h", + ] + public_deps = [ + "//ui/accessibility:ax_base", + "//ui/accessibility/mojom:mojom_shared_cpp_sources", + "//ui/gfx", + "//ui/gfx/geometry/mojom:mojom_traits", + "//ui/gfx/mojom:mojom", + ] +}
diff --git a/ui/android/java/src/org/chromium/ui/base/WindowAndroid.java b/ui/android/java/src/org/chromium/ui/base/WindowAndroid.java index 5830d97..93aeb50c 100644 --- a/ui/android/java/src/org/chromium/ui/base/WindowAndroid.java +++ b/ui/android/java/src/org/chromium/ui/base/WindowAndroid.java
@@ -719,7 +719,7 @@ // result returning value. private Window getWindow() { Activity activity = ContextUtils.activityFromContext(mContextRef.get()); - if (activity == null) return null; + if (activity == null || activity.isFinishing()) return null; return activity.getWindow(); } @@ -843,8 +843,7 @@ /** * Return the current window token, or null. */ - @CalledByNative - protected IBinder getWindowToken() { + public IBinder getWindowToken() { Window window = getWindow(); if (window == null) return null; View decorView = window.peekDecorView();
diff --git a/ui/android/window_android.cc b/ui/android/window_android.cc index 42cc265c..3c4a288 100644 --- a/ui/android/window_android.cc +++ b/ui/android/window_android.cc
@@ -250,11 +250,6 @@ return const_cast<WindowAndroid*>(this); } -ScopedJavaLocalRef<jobject> WindowAndroid::GetWindowToken() { - JNIEnv* env = AttachCurrentThread(); - return Java_WindowAndroid_getWindowToken(env, GetJavaObject()); -} - display::Display WindowAndroid::GetDisplayWithWindowColorSpace() { display::Display display = display::Screen::GetScreen()->GetDisplayNearestWindow(this);
diff --git a/ui/android/window_android.h b/ui/android/window_android.h index 5ffff2c..25abcac 100644 --- a/ui/android/window_android.h +++ b/ui/android/window_android.h
@@ -107,9 +107,6 @@ static std::unique_ptr<ScopedWindowAndroidForTesting> CreateForTesting(); - // Return the window token for this window, if one exists. - base::android::ScopedJavaLocalRef<jobject> GetWindowToken(); - // This should return the same Display as Screen::GetDisplayNearestWindow // except the color space depends on the status of this particular window // rather than the display itself.
diff --git a/ui/display/manager/display_configurator.cc b/ui/display/manager/display_configurator.cc index 804f0343..af9f38e 100644 --- a/ui/display/manager/display_configurator.cc +++ b/ui/display/manager/display_configurator.cc
@@ -127,6 +127,7 @@ const std::vector<DisplaySnapshot*>& displays, MultipleDisplayState new_display_state, chromeos::DisplayPowerState new_power_state, + RefreshRateThrottleState new_throttle_state, std::vector<DisplayConfigureRequest>* requests) const override; DisplayStateList GetDisplayStates() const override; bool IsMirroring() const override; @@ -251,6 +252,7 @@ const std::vector<DisplaySnapshot*>& displays, MultipleDisplayState new_display_state, chromeos::DisplayPowerState new_power_state, + RefreshRateThrottleState new_throttle_state, std::vector<DisplayConfigureRequest>* requests) const { std::vector<DisplayState> states = ParseDisplays(displays); std::vector<bool> display_power; @@ -375,6 +377,24 @@ break; } } + + // DisplayConfigureRequest for internal displays should already be configured + // to request their native modes, which should be the highest refresh rate. + if (new_throttle_state == kRefreshRateThrottleEnabled) { + for (DisplayConfigureRequest& request : *requests) { + if (request.display->type() != DISPLAY_CONNECTION_TYPE_INTERNAL) + continue; + + std::vector<const DisplayMode*> modes = + GetSeamlessRefreshRateModes(*request.display, *request.mode); + if (modes.size() < 2) + break; + + DCHECK_GT(request.mode->refresh_rate(), (*modes.begin())->refresh_rate()); + request.mode = (*modes.begin()); + } + } + DCHECK(new_display_state == MULTIPLE_DISPLAY_STATE_HEADLESS || !size.IsEmpty()); return true; @@ -744,7 +764,8 @@ configuration_task_ = std::make_unique<UpdateDisplayConfigurationTask>( native_display_delegate_.get(), layout_manager_.get(), requested_display_state_, GetRequestedPowerState(), - kSetDisplayPowerForceProbe, /*force_configure=*/true, + kSetDisplayPowerForceProbe, kRefreshRateThrottleDisabled, + /*force_configure=*/true, base::BindOnce(&DisplayConfigurator::OnConfigured, weak_ptr_factory_.GetWeakPtr())); configuration_task_->Run(); @@ -901,8 +922,39 @@ void DisplayConfigurator::MaybeSetRefreshRateThrottleState( int64_t display_id, RefreshRateThrottleState state) { - VLOG(4) << "Request refresh rate throttle state for display_id: " - << display_id << " to state: " << state; + DisplaySnapshot* display = nullptr; + for (DisplaySnapshot* cached_display : cached_displays_) { + if (cached_display->display_id() == display_id) { + display = cached_display; + break; + } + } + if (display == nullptr) { + LOG(ERROR) << "Did not find display with id: " << display_id; + return; + } + if (display->type() != DISPLAY_CONNECTION_TYPE_INTERNAL) { + LOG(ERROR) << "Can't throttle refresh rate for non-internal display: " + << display_id; + return; + } + if (display->current_mode() == nullptr) { + VLOG(4) << "Mode not set for display."; + return; + } + + std::vector<const DisplayMode*> matching_modes = + GetSeamlessRefreshRateModes(*display, *display->current_mode()); + if (matching_modes.size() < 2) { + VLOG(4) << "No mode candidates for seamless refresh rate change."; + return; + } + + if ((state == kRefreshRateThrottleEnabled) != + (display->current_mode() == *matching_modes.begin())) { + pending_refresh_rate_throttle_state_ = state; + RunPendingConfiguration(); + } } void DisplayConfigurator::SuspendDisplays(ConfigurationCallback callback) { @@ -978,6 +1030,8 @@ configuration_task_ = std::make_unique<UpdateDisplayConfigurationTask>( native_display_delegate_.get(), layout_manager_.get(), requested_display_state_, pending_power_state_, pending_power_flags_, + pending_refresh_rate_throttle_state_.value_or( + kRefreshRateThrottleDisabled), force_configure_, base::BindOnce(&DisplayConfigurator::OnConfigured, weak_ptr_factory_.GetWeakPtr())); @@ -988,6 +1042,7 @@ pending_power_flags_ = kSetDisplayPowerNoFlags; has_pending_power_state_ = false; requested_display_state_ = MULTIPLE_DISPLAY_STATE_INVALID; + pending_refresh_rate_throttle_state_ = absl::nullopt; DCHECK(in_progress_configuration_callbacks_.empty()); in_progress_configuration_callbacks_.swap(queued_configuration_callbacks_); @@ -1062,6 +1117,10 @@ if (has_pending_power_state_) return true; + // Schedule if there is a pending request to change the refresh rate. + if (pending_refresh_rate_throttle_state_) + return true; + return false; }
diff --git a/ui/display/manager/display_configurator.h b/ui/display/manager/display_configurator.h index 438bb8c4..57a0e0c 100644 --- a/ui/display/manager/display_configurator.h +++ b/ui/display/manager/display_configurator.h
@@ -404,6 +404,9 @@ // Bitwise-or value of the |kSetDisplayPower*| flags defined above. int pending_power_flags_; + // Stores the requested refresh rate throttle state. + absl::optional<RefreshRateThrottleState> pending_refresh_rate_throttle_state_; + // List of callbacks from callers waiting for the display configuration to // start/finish. Note these callbacks belong to the pending request, not a // request currently active.
diff --git a/ui/display/manager/display_layout_manager.h b/ui/display/manager/display_layout_manager.h index ae7c492..b1cdf39 100644 --- a/ui/display/manager/display_layout_manager.h +++ b/ui/display/manager/display_layout_manager.h
@@ -39,6 +39,7 @@ const std::vector<DisplaySnapshot*>& displays, MultipleDisplayState new_display_state, chromeos::DisplayPowerState new_power_state, + RefreshRateThrottleState new_throttle_state, std::vector<DisplayConfigureRequest>* requests) const = 0; virtual std::vector<DisplaySnapshot*> GetDisplayStates() const = 0;
diff --git a/ui/display/manager/display_manager_util.cc b/ui/display/manager/display_manager_util.cc index 2e413365..4ae7692 100644 --- a/ui/display/manager/display_manager_util.cc +++ b/ui/display/manager/display_manager_util.cc
@@ -34,6 +34,18 @@ } } +std::string RefreshRateThrottleStateToString(RefreshRateThrottleState state) { + switch (state) { + case kRefreshRateThrottleEnabled: + return "THROTTLE_ENABLED"; + case kRefreshRateThrottleDisabled: + return "THROTTLE_DISABLED"; + } + NOTREACHED(); + return "unknown refresh rate throttle state (" + base::NumberToString(state) + + ")"; +} + int GetDisplayPower(const std::vector<DisplaySnapshot*>& displays, chromeos::DisplayPowerState state, std::vector<bool>* display_power) { @@ -56,6 +68,36 @@ return num_on_displays; } +std::vector<const DisplayMode*> GetSeamlessRefreshRateModes( + const DisplaySnapshot& display, + const DisplayMode& matching_mode) { + const float kMinRefreshRate = 60.f; + const float kEpsilon = 0.01f; + + std::vector<const DisplayMode*> matching_modes; + for (const std::unique_ptr<const display::DisplayMode>& mode : + display.modes()) { + if (matching_mode.is_interlaced() != mode->is_interlaced()) + continue; + // Filter out modes that are less than 60 Hz. Account for floating point + // inaccuracies so we don't filter out 59.997 mistakenly. + if (mode->refresh_rate() < (kMinRefreshRate - kEpsilon)) + continue; + + // Filter out modes whose refresh rate is quicker than the preferred mode. + if (display.native_mode()->refresh_rate() < mode->refresh_rate()) + continue; + + if (matching_mode.size() == mode->size()) + matching_modes.push_back(mode.get()); + } + auto refresh_lt = [](const DisplayMode* a, const DisplayMode* b) -> bool { + return a->refresh_rate() < b->refresh_rate(); + }; + std::sort(matching_modes.begin(), matching_modes.end(), refresh_lt); + return matching_modes; +} + #endif // BUILDFLAG(IS_CHROMEOS_ASH) bool WithinEpsilon(float a, float b) {
diff --git a/ui/display/manager/display_manager_util.h b/ui/display/manager/display_manager_util.h index c37a695..77a0f51 100644 --- a/ui/display/manager/display_manager_util.h +++ b/ui/display/manager/display_manager_util.h
@@ -18,6 +18,7 @@ namespace display { +class DisplayMode; class DisplaySnapshot; class ManagedDisplayMode; @@ -25,6 +26,9 @@ // Returns a string describing |state|. std::string DisplayPowerStateToString(chromeos::DisplayPowerState state); +// Returns a string describing |state|. +std::string RefreshRateThrottleStateToString(RefreshRateThrottleState state); + // Returns the number of displays in |displays| that should be turned on, per // |state|. If |display_power| is non-NULL, it is updated to contain the // on/off state of each corresponding entry in |displays|. @@ -33,6 +37,15 @@ chromeos::DisplayPowerState state, std::vector<bool>* display_power); +// Get a vector of DisplayMode pointers from |display|'s set of modes that +// should be considered for seamless refresh rate switching. These will have the +// same refresh rate as |matching_mode|, be no slower than 60 Hz, and no faster +// than the display's native mode. The vector will be ordered by refresh rate, +// with the slowest refresh rate at index 0. +std::vector<const DisplayMode*> GetSeamlessRefreshRateModes( + const DisplaySnapshot& display, + const DisplayMode& matching_mode); + #endif // BUILDFLAG(IS_CHROMEOS_ASH) // Determines whether |a| is within an epsilon of |b|.
diff --git a/ui/display/manager/test/test_display_layout_manager.cc b/ui/display/manager/test/test_display_layout_manager.cc index 460b0d82..6eb29b0 100644 --- a/ui/display/manager/test/test_display_layout_manager.cc +++ b/ui/display/manager/test/test_display_layout_manager.cc
@@ -41,6 +41,7 @@ const std::vector<DisplaySnapshot*>& displays, MultipleDisplayState new_display_state, chromeos::DisplayPowerState new_power_state, + RefreshRateThrottleState new_throttle_state, std::vector<DisplayConfigureRequest>* requests) const { NOTREACHED(); return false;
diff --git a/ui/display/manager/test/test_display_layout_manager.h b/ui/display/manager/test/test_display_layout_manager.h index 5178f3a..78bfc21 100644 --- a/ui/display/manager/test/test_display_layout_manager.h +++ b/ui/display/manager/test/test_display_layout_manager.h
@@ -43,6 +43,7 @@ const std::vector<DisplaySnapshot*>& displays, MultipleDisplayState new_display_state, chromeos::DisplayPowerState new_power_state, + RefreshRateThrottleState new_throttle_state, std::vector<DisplayConfigureRequest>* requests) const override; std::vector<DisplaySnapshot*> GetDisplayStates() const override; bool IsMirroring() const override;
diff --git a/ui/display/manager/update_display_configuration_task.cc b/ui/display/manager/update_display_configuration_task.cc index 75df3bb5..7182fd1 100644 --- a/ui/display/manager/update_display_configuration_task.cc +++ b/ui/display/manager/update_display_configuration_task.cc
@@ -16,6 +16,28 @@ #include "ui/display/types/native_display_delegate.h" namespace display { +namespace { +bool InternalDisplayThrottled( + const std::vector<DisplaySnapshot*>& cached_displays) { + for (const DisplaySnapshot* display : cached_displays) { + if (display->type() == DISPLAY_CONNECTION_TYPE_INTERNAL) { + if (!display->current_mode()) + return false; + + std::vector<const DisplayMode*> modes = + GetSeamlessRefreshRateModes(*display, *display->current_mode()); + + // Can't be throttled if there are not multiple candidate modes. + if (modes.size() < 2) + return false; + + return display->current_mode() == *modes.begin(); + } + } + // No internal displays + return false; +} +} // namespace UpdateDisplayConfigurationTask::UpdateDisplayConfigurationTask( NativeDisplayDelegate* delegate, @@ -23,6 +45,7 @@ MultipleDisplayState new_display_state, chromeos::DisplayPowerState new_power_state, int power_flags, + RefreshRateThrottleState refresh_rate_throttle_state, bool force_configure, ResponseCallback callback) : delegate_(delegate), @@ -30,6 +53,7 @@ new_display_state_(new_display_state), new_power_state_(new_power_state), power_flags_(power_flags), + refresh_rate_throttle_state_(refresh_rate_throttle_state), force_configure_(force_configure), callback_(std::move(callback)), requesting_displays_(false) { @@ -73,7 +97,8 @@ VLOG(1) << "OnDisplaysUpdated: new_display_state=" << MultipleDisplayStateToString(new_display_state_) << " new_power_state=" << DisplayPowerStateToString(new_power_state_) - << " flags=" << power_flags_ + << " flags=" << power_flags_ << " refresh_rate_throttle_state_=" + << RefreshRateThrottleStateToString(refresh_rate_throttle_state_) << " force_configure=" << force_configure_ << " display_count=" << cached_displays_.size(); if (ShouldConfigure()) { @@ -91,12 +116,15 @@ ConfigureDisplaysTask::ResponseCallback callback) { VLOG(2) << "EnterState"; std::vector<DisplayConfigureRequest> requests; - if (!layout_manager_->GetDisplayLayout(cached_displays_, new_display_state_, - new_power_state_, &requests)) { + if (!layout_manager_->GetDisplayLayout( + cached_displays_, new_display_state_, new_power_state_, + refresh_rate_throttle_state_, &requests)) { std::move(callback).Run(ConfigureDisplaysTask::ERROR); return; } if (!requests.empty()) { + // TODO(b:238361145) Plumb seamless modeset for refresh rate throttle + // changes. configure_task_ = std::make_unique<ConfigureDisplaysTask>( delegate_, requests, std::move(callback)); configure_task_->Run(); @@ -184,6 +212,10 @@ if (new_display_state_ != layout_manager_->GetDisplayState()) return true; + if ((refresh_rate_throttle_state_ == kRefreshRateThrottleEnabled) != + InternalDisplayThrottled(cached_displays_)) + return true; + return false; }
diff --git a/ui/display/manager/update_display_configuration_task.h b/ui/display/manager/update_display_configuration_task.h index e9fe25e..c9d1b2ce 100644 --- a/ui/display/manager/update_display_configuration_task.h +++ b/ui/display/manager/update_display_configuration_task.h
@@ -32,13 +32,15 @@ /*new_display_state=*/MultipleDisplayState, /*new_power_state=*/chromeos::DisplayPowerState)>; - UpdateDisplayConfigurationTask(NativeDisplayDelegate* delegate, - DisplayLayoutManager* layout_manager, - MultipleDisplayState new_display_state, - chromeos::DisplayPowerState new_power_state, - int power_flags, - bool force_configure, - ResponseCallback callback); + UpdateDisplayConfigurationTask( + NativeDisplayDelegate* delegate, + DisplayLayoutManager* layout_manager, + MultipleDisplayState new_display_state, + chromeos::DisplayPowerState new_power_state, + int power_flags, + RefreshRateThrottleState refresh_rate_throttle_state, + bool force_configure, + ResponseCallback callback); UpdateDisplayConfigurationTask(const UpdateDisplayConfigurationTask&) = delete; @@ -96,6 +98,10 @@ // DisplayConfigurator. int power_flags_; + // Whether the configuration task should select a low refresh rate + // for the internal display. + RefreshRateThrottleState refresh_rate_throttle_state_; + bool force_configure_; // Used to signal that the task has finished.
diff --git a/ui/display/manager/update_display_configuration_task_unittest.cc b/ui/display/manager/update_display_configuration_task_unittest.cc index 71628b829..474fbf1 100644 --- a/ui/display/manager/update_display_configuration_task_unittest.cc +++ b/ui/display/manager/update_display_configuration_task_unittest.cc
@@ -95,6 +95,7 @@ const std::vector<DisplaySnapshot*>& displays, MultipleDisplayState new_display_state, chromeos::DisplayPowerState new_power_state, + RefreshRateThrottleState new_throttle_state, std::vector<DisplayConfigureRequest>* requests) const override { gfx::Point origin; for (DisplaySnapshot* display : displays) { @@ -233,7 +234,7 @@ { UpdateDisplayConfigurationTask task( &delegate_, &layout_manager_, MULTIPLE_DISPLAY_STATE_HEADLESS, - chromeos::DISPLAY_POWER_ALL_ON, 0, false, + chromeos::DISPLAY_POWER_ALL_ON, 0, kRefreshRateThrottleEnabled, false, base::BindOnce(&UpdateDisplayConfigurationTaskTest::ResponseCallback, base::Unretained(this))); task.Run(); @@ -252,7 +253,7 @@ { UpdateDisplayConfigurationTask task( &delegate_, &layout_manager_, MULTIPLE_DISPLAY_STATE_SINGLE, - chromeos::DISPLAY_POWER_ALL_ON, 0, false, + chromeos::DISPLAY_POWER_ALL_ON, 0, kRefreshRateThrottleEnabled, false, base::BindOnce(&UpdateDisplayConfigurationTaskTest::ResponseCallback, base::Unretained(this))); task.Run(); @@ -275,7 +276,7 @@ { UpdateDisplayConfigurationTask task( &delegate_, &layout_manager_, MULTIPLE_DISPLAY_STATE_MULTI_EXTENDED, - chromeos::DISPLAY_POWER_ALL_ON, 0, false, + chromeos::DISPLAY_POWER_ALL_ON, 0, kRefreshRateThrottleEnabled, false, base::BindOnce(&UpdateDisplayConfigurationTaskTest::ResponseCallback, base::Unretained(this))); task.Run(); @@ -303,7 +304,7 @@ { UpdateDisplayConfigurationTask task( &delegate_, &layout_manager_, MULTIPLE_DISPLAY_STATE_MULTI_MIRROR, - chromeos::DISPLAY_POWER_ALL_ON, 0, false, + chromeos::DISPLAY_POWER_ALL_ON, 0, kRefreshRateThrottleEnabled, false, base::BindOnce(&UpdateDisplayConfigurationTaskTest::ResponseCallback, base::Unretained(this))); task.Run(); @@ -330,7 +331,7 @@ { UpdateDisplayConfigurationTask task( &delegate_, &layout_manager_, MULTIPLE_DISPLAY_STATE_MULTI_MIRROR, - chromeos::DISPLAY_POWER_ALL_ON, 0, false, + chromeos::DISPLAY_POWER_ALL_ON, 0, kRefreshRateThrottleEnabled, false, base::BindOnce(&UpdateDisplayConfigurationTaskTest::ResponseCallback, base::Unretained(this))); task.Run(); @@ -348,7 +349,7 @@ { UpdateDisplayConfigurationTask task( &delegate_, &layout_manager_, MULTIPLE_DISPLAY_STATE_MULTI_EXTENDED, - chromeos::DISPLAY_POWER_ALL_ON, 0, false, + chromeos::DISPLAY_POWER_ALL_ON, 0, kRefreshRateThrottleEnabled, false, base::BindOnce(&UpdateDisplayConfigurationTaskTest::ResponseCallback, base::Unretained(this))); task.Run(); @@ -402,7 +403,7 @@ { UpdateDisplayConfigurationTask task( &delegate_, &layout_manager_, MULTIPLE_DISPLAY_STATE_SINGLE, - chromeos::DISPLAY_POWER_ALL_ON, 0, false, + chromeos::DISPLAY_POWER_ALL_ON, 0, kRefreshRateThrottleEnabled, false, base::BindOnce(&UpdateDisplayConfigurationTaskTest::ResponseCallback, base::Unretained(this))); task.Run(); @@ -422,7 +423,7 @@ { UpdateDisplayConfigurationTask task( &delegate_, &layout_manager_, MULTIPLE_DISPLAY_STATE_SINGLE, - chromeos::DISPLAY_POWER_ALL_OFF, 0, false, + chromeos::DISPLAY_POWER_ALL_OFF, 0, kRefreshRateThrottleEnabled, false, base::BindOnce(&UpdateDisplayConfigurationTaskTest::ResponseCallback, base::Unretained(this))); task.Run(); @@ -447,7 +448,7 @@ { UpdateDisplayConfigurationTask task( &delegate_, &layout_manager_, MULTIPLE_DISPLAY_STATE_MULTI_EXTENDED, - chromeos::DISPLAY_POWER_ALL_ON, 0, false, + chromeos::DISPLAY_POWER_ALL_ON, 0, kRefreshRateThrottleEnabled, false, base::BindOnce(&UpdateDisplayConfigurationTaskTest::ResponseCallback, base::Unretained(this))); task.Run(); @@ -458,7 +459,7 @@ { UpdateDisplayConfigurationTask task( &delegate_, &layout_manager_, MULTIPLE_DISPLAY_STATE_MULTI_MIRROR, - chromeos::DISPLAY_POWER_ALL_ON, 0, false, + chromeos::DISPLAY_POWER_ALL_ON, 0, kRefreshRateThrottleEnabled, false, base::BindOnce(&UpdateDisplayConfigurationTaskTest::ResponseCallback, base::Unretained(this))); task.Run(); @@ -481,7 +482,7 @@ { UpdateDisplayConfigurationTask task( &delegate_, &layout_manager_, MULTIPLE_DISPLAY_STATE_MULTI_EXTENDED, - chromeos::DISPLAY_POWER_ALL_ON, 0, false, + chromeos::DISPLAY_POWER_ALL_ON, 0, kRefreshRateThrottleEnabled, false, base::BindOnce(&UpdateDisplayConfigurationTaskTest::ResponseCallback, base::Unretained(this))); task.Run(); @@ -492,7 +493,8 @@ { UpdateDisplayConfigurationTask task( &delegate_, &layout_manager_, MULTIPLE_DISPLAY_STATE_MULTI_MIRROR, - chromeos::DISPLAY_POWER_ALL_ON, 0, true /* force_configure */, + chromeos::DISPLAY_POWER_ALL_ON, 0, kRefreshRateThrottleEnabled, + true /* force_configure */, base::BindOnce(&UpdateDisplayConfigurationTaskTest::ResponseCallback, base::Unretained(this))); task.Run();
diff --git a/ui/gfx/geometry/linear_gradient.h b/ui/gfx/geometry/linear_gradient.h index 1ad025f..3e95a89 100644 --- a/ui/gfx/geometry/linear_gradient.h +++ b/ui/gfx/geometry/linear_gradient.h
@@ -54,9 +54,9 @@ // Gets/Sets an angle (in degrees). int16_t angle() const { return angle_; } - void set_angle(int16_t degree) { angle_ = degree % 360; } + void set_angle(int16_t degree) { angle_ = degree; } - // Reverse the step 180 degree. + // Reverse the steps. void ReverseSteps(); // Transform the angle.
diff --git a/ui/gfx/render_text_api_fuzzer.cc b/ui/gfx/render_text_api_fuzzer.cc index ac2c4f84..38f7a3bf 100644 --- a/ui/gfx/render_text_api_fuzzer.cc +++ b/ui/gfx/render_text_api_fuzzer.cc
@@ -342,7 +342,7 @@ break; case RenderTextAPI::kApplyColor: - if (generate_only_homogeneous_styles) { + if (!generate_only_homogeneous_styles) { render_text->ApplyColor( ConsumeSkColor(&fdp), ConsumeRange(&fdp, render_text->text().length())); @@ -354,7 +354,7 @@ break; case RenderTextAPI::kApplyStyle: - if (generate_only_homogeneous_styles) { + if (!generate_only_homogeneous_styles) { render_text->ApplyStyle( ConsumeStyle(&fdp), fdp.ConsumeBool(), ConsumeRange(&fdp, render_text->text().length())); @@ -366,7 +366,7 @@ break; case RenderTextAPI::kApplyWeight: - if (generate_only_homogeneous_styles) { + if (!generate_only_homogeneous_styles) { render_text->ApplyWeight( ConsumeWeight(&fdp), ConsumeRange(&fdp, render_text->text().length()));
diff --git a/ui/gl/direct_composition_surface_win.cc b/ui/gl/direct_composition_surface_win.cc index a69d7c3..8a51c6e 100644 --- a/ui/gl/direct_composition_surface_win.cc +++ b/ui/gl/direct_composition_surface_win.cc
@@ -79,10 +79,12 @@ base::AutoLock auto_lock(GetOverlayLock()); return g_overlay_caps_valid; } + void SetOverlayCapsValid(bool valid) { base::AutoLock auto_lock(GetOverlayLock()); g_overlay_caps_valid = valid; } + // A warpper of IDXGIOutput4::CheckOverlayColorSpaceSupport() bool CheckOverlayColorSpaceSupport( DXGI_FORMAT dxgi_format, @@ -108,9 +110,6 @@ IDCompositionDevice2* g_dcomp_device = nullptr; -DirectCompositionSurfaceWin::OverlayHDRInfoUpdateCallback - g_overlay_hdr_gpu_info_callback; - // Preferred overlay format set when detecting overlay support during // initialization. Set to NV12 by default so that it's used when enabling // overlays using command line flags. @@ -363,11 +362,6 @@ g_overlay_format_used_hdr = overlay_format_used_hdr; } -void RunOverlayHdrGpuInfoUpdateCallback() { - if (g_overlay_hdr_gpu_info_callback) - g_overlay_hdr_gpu_info_callback.Run(); -} - void UpdateMonitorInfo() { g_num_of_monitors = GetSystemMetrics(SM_CMONITORS); @@ -400,12 +394,9 @@ settings.disable_nv12_dynamic_textures, settings.disable_vp_scaling, settings.disable_vp_super_resolution, - settings.no_downscaled_overlay_promotion)) { - ui::GpuSwitchingManager::GetInstance()->AddObserver(this); -} + settings.no_downscaled_overlay_promotion)) {} DirectCompositionSurfaceWin::~DirectCompositionSurfaceWin() { - ui::GpuSwitchingManager::GetInstance()->RemoveObserver(this); Destroy(); } @@ -551,7 +542,8 @@ // static void DirectCompositionSurfaceWin::DisableOverlays() { SetSupportsOverlays(false); - RunOverlayHdrGpuInfoUpdateCallback(); + DirectCompositionOverlayCapsMonitor::GetInstance() + ->NotifyOverlayCapsChanged(); } // static @@ -560,11 +552,6 @@ } // static -void DirectCompositionSurfaceWin::InvalidateOverlayCaps() { - SetOverlayCapsValid(false); -} - -// static bool DirectCompositionSurfaceWin::AreScaledOverlaysSupported() { UpdateOverlaySupport(); if (g_overlay_format_used == DXGI_FORMAT_NV12) { @@ -761,12 +748,6 @@ } // static -void DirectCompositionSurfaceWin::SetOverlayHDRGpuInfoUpdateCallback( - OverlayHDRInfoUpdateCallback callback) { - g_overlay_hdr_gpu_info_callback = std::move(callback); -} - -// static void DirectCompositionSurfaceWin::EnableBGRA8OverlaysWithYUVOverlaySupport() { // This has to be set before initializing overlay caps. DCHECK(!OverlayCapsValid()); @@ -929,7 +910,8 @@ bool result = root_surface_->SetDrawRectangle(rectangle); if (!result && DirectCompositionChildSurfaceWin::IsDirectCompositionSwapChainFailed()) { - RunOverlayHdrGpuInfoUpdateCallback(); + DirectCompositionOverlayCapsMonitor::GetInstance() + ->NotifyOverlayCapsChanged(); } return result; @@ -947,29 +929,6 @@ root_surface_->SetGpuVSyncEnabled(enabled); } -void DirectCompositionSurfaceWin::OnGpuSwitched( - gl::GpuPreference active_gpu_heuristic) {} - -void DirectCompositionSurfaceWin::OnDisplayAdded() { - InvalidateOverlayCaps(); - UpdateOverlaySupport(); - UpdateMonitorInfo(); - layer_tree_->GetHDRMetadataHelper()->UpdateDisplayMetadata(); - RunOverlayHdrGpuInfoUpdateCallback(); -} - -void DirectCompositionSurfaceWin::OnDisplayRemoved() { - InvalidateOverlayCaps(); - UpdateOverlaySupport(); - UpdateMonitorInfo(); - layer_tree_->GetHDRMetadataHelper()->UpdateDisplayMetadata(); - RunOverlayHdrGpuInfoUpdateCallback(); -} - -void DirectCompositionSurfaceWin::OnDisplayMetricsChanged() { - UpdateMonitorInfo(); -} - bool DirectCompositionSurfaceWin::SupportsDelegatedInk() { return layer_tree_->SupportsDelegatedInk(); } @@ -1022,4 +981,65 @@ g_primary_monitor_size = monitor_size; } -} // namespace gl \ No newline at end of file +// For DirectComposition Display Monitor. +DirectCompositionOverlayCapsMonitor::DirectCompositionOverlayCapsMonitor() + : observer_list_(new base::ObserverListThreadSafe< + DirectCompositionOverlayCapsObserver>()) { + ui::GpuSwitchingManager::GetInstance()->AddObserver(this); +} + +DirectCompositionOverlayCapsMonitor::~DirectCompositionOverlayCapsMonitor() { + ui::GpuSwitchingManager::GetInstance()->RemoveObserver(this); +} + +// static +DirectCompositionOverlayCapsMonitor* +DirectCompositionOverlayCapsMonitor::GetInstance() { + static base::NoDestructor<DirectCompositionOverlayCapsMonitor> + direct_compoisition_overlay_cap_monitor; + return direct_compoisition_overlay_cap_monitor.get(); +} + +void DirectCompositionOverlayCapsMonitor::AddObserver( + DirectCompositionOverlayCapsObserver* observer) { + observer_list_->AddObserver(observer); +} + +void DirectCompositionOverlayCapsMonitor::RemoveObserver( + DirectCompositionOverlayCapsObserver* observer) { + observer_list_->RemoveObserver(observer); +} + +void DirectCompositionOverlayCapsMonitor::NotifyOverlayCapsChanged() { + observer_list_->Notify( + FROM_HERE, &DirectCompositionOverlayCapsObserver::OnOverlayCapsChanged); +} + +// Called from GpuSwitchingObserver on the GPU main thread. +void DirectCompositionOverlayCapsMonitor::OnGpuSwitched( + gl::GpuPreference active_gpu_heuristic) {} + +// Called from GpuSwitchingObserver on the GPU main thread. +void DirectCompositionOverlayCapsMonitor::OnDisplayAdded() { + SetOverlayCapsValid(false); + UpdateOverlaySupport(); + UpdateMonitorInfo(); + + NotifyOverlayCapsChanged(); +} + +// Called from GpuSwitchingObserver on the GPU main thread. +void DirectCompositionOverlayCapsMonitor::OnDisplayRemoved() { + SetOverlayCapsValid(false); + UpdateOverlaySupport(); + UpdateMonitorInfo(); + + NotifyOverlayCapsChanged(); +} + +// Called from GpuSwitchingObserver on the GPU main thread. +void DirectCompositionOverlayCapsMonitor::OnDisplayMetricsChanged() { + UpdateMonitorInfo(); +} + +} // namespace gl
diff --git a/ui/gl/direct_composition_surface_win.h b/ui/gl/direct_composition_surface_win.h index d3bd7438..abd46d4 100644 --- a/ui/gl/direct_composition_surface_win.h +++ b/ui/gl/direct_composition_surface_win.h
@@ -10,7 +10,9 @@ #include <dcomp.h> #include <wrl/client.h> -#include "base/callback.h" +#include "base/memory/scoped_refptr.h" +#include "base/no_destructor.h" +#include "base/observer_list_threadsafe.h" #include "base/time/time.h" #include "mojo/public/cpp/bindings/pending_receiver.h" #include "ui/gfx/geometry/transform.h" @@ -32,8 +34,7 @@ class DCLayerTree; class DirectCompositionChildSurfaceWin; -class GL_EXPORT DirectCompositionSurfaceWin : public GLSurfaceEGL, - public ui::GpuSwitchingObserver { +class GL_EXPORT DirectCompositionSurfaceWin : public GLSurfaceEGL { public: using VSyncCallback = base::RepeatingCallback<void(base::TimeTicks, base::TimeDelta)>; @@ -91,9 +92,6 @@ // Similar to the above but disables software overlay support. static void DisableSoftwareOverlays(); - // Indicate the overlay caps are invalid. - static void InvalidateOverlayCaps(); - // Returns true if scaled hardware overlays are supported. static bool AreScaledOverlaysSupported(); @@ -124,9 +122,6 @@ static void SetOverlayFormatUsedForTesting(DXGI_FORMAT format); - static void SetOverlayHDRGpuInfoUpdateCallback( - OverlayHDRInfoUpdateCallback callback); - // On Intel GPUs where YUV overlays are supported, BGRA8 overlays are // supported as well but IDXGIOutput3::CheckOverlaySupport() returns // unsupported. So allow manually enabling BGRA8 overlay support. @@ -181,12 +176,6 @@ std::unique_ptr<ui::DCRendererLayerParams> params) override; void SetFrameRate(float frame_rate) override; - // Implements GpuSwitchingObserver. - void OnGpuSwitched(gl::GpuPreference active_gpu_heuristic) override; - void OnDisplayAdded() override; - void OnDisplayRemoved() override; - void OnDisplayMetricsChanged() override; - bool SupportsDelegatedInk() override; void SetDelegatedInkTrailStartPoint( std::unique_ptr<gfx::DelegatedInkMetadata> metadata) override; @@ -227,6 +216,54 @@ std::unique_ptr<DCLayerTree> layer_tree_; }; +class GL_EXPORT DirectCompositionOverlayCapsObserver + : public base::CheckedObserver { + public: + virtual void OnOverlayCapsChanged() = 0; + + protected: + ~DirectCompositionOverlayCapsObserver() override = default; +}; + +// Upon receiving display notifications from ui::GpuSwitchingManager, +// DirectCompositionOverlayCapsMonitor updates its overlay caps with the new +// display setting and notifies DirectCompositionOverlayCapsObserver for the +// overlay cap change. +class GL_EXPORT DirectCompositionOverlayCapsMonitor + : public ui::GpuSwitchingObserver { + public: + DirectCompositionOverlayCapsMonitor( + const DirectCompositionOverlayCapsMonitor&) = delete; + DirectCompositionOverlayCapsMonitor& operator=( + const DirectCompositionOverlayCapsMonitor&) = delete; + + static DirectCompositionOverlayCapsMonitor* GetInstance(); + + // DirectCompositionOverlayCapsMonitor is running on GpuMain thread. + // AddObserver()/RemoveObserver() are thread safe. + void AddObserver(DirectCompositionOverlayCapsObserver* observer); + void RemoveObserver(DirectCompositionOverlayCapsObserver* observer); + + // Called when the overlay caps have changed in DirectCompositionSurfaceWin. + void NotifyOverlayCapsChanged(); + + // Implements GpuSwitchingObserver. + void OnGpuSwitched(gl::GpuPreference active_gpu_heuristic) override; + void OnDisplayAdded() override; + void OnDisplayRemoved() override; + void OnDisplayMetricsChanged() override; + + private: + friend class base::NoDestructor<DirectCompositionOverlayCapsMonitor>; + + DirectCompositionOverlayCapsMonitor(); + ~DirectCompositionOverlayCapsMonitor() override; + + scoped_refptr< + base::ObserverListThreadSafe<DirectCompositionOverlayCapsObserver>> + observer_list_; +}; + } // namespace gl #endif // UI_GL_DIRECT_COMPOSITION_SURFACE_WIN_H_
diff --git a/ui/gl/gl_display.h b/ui/gl/gl_display.h index 5d0a6e8..6114678 100644 --- a/ui/gl/gl_display.h +++ b/ui/gl/gl_display.h
@@ -135,6 +135,7 @@ class EGLGpuSwitchingObserver final : public ui::GpuSwitchingObserver { public: explicit EGLGpuSwitchingObserver(EGLDisplay display); + ~EGLGpuSwitchingObserver() override = default; void OnGpuSwitched(GpuPreference active_gpu_heuristic) override; private:
diff --git a/ui/gl/gpu_switching_manager.cc b/ui/gl/gpu_switching_manager.cc index 136e276..c6b2e0da 100644 --- a/ui/gl/gpu_switching_manager.cc +++ b/ui/gl/gpu_switching_manager.cc
@@ -13,9 +13,9 @@ return base::Singleton<GpuSwitchingManager>::get(); } -GpuSwitchingManager::GpuSwitchingManager() {} +GpuSwitchingManager::GpuSwitchingManager() = default; -GpuSwitchingManager::~GpuSwitchingManager() {} +GpuSwitchingManager::~GpuSwitchingManager() = default; void GpuSwitchingManager::AddObserver(GpuSwitchingObserver* observer) { observer_list_.AddObserver(observer);
diff --git a/ui/gl/gpu_switching_manager.h b/ui/gl/gpu_switching_manager.h index caaea0db..a0d9a93 100644 --- a/ui/gl/gpu_switching_manager.h +++ b/ui/gl/gpu_switching_manager.h
@@ -13,7 +13,8 @@ #include "ui/gl/gpu_switching_observer.h" namespace ui { - +// GpuSwitchingManager is not thread safe. It is running on the browser main +// thread in the browser and/or on the gpu main thread in the GPU process. class GL_EXPORT GpuSwitchingManager { public: // Getter for the singleton. This will return NULL on failure.
diff --git a/ui/gl/gpu_switching_observer.h b/ui/gl/gpu_switching_observer.h index 6c921883..2920abe 100644 --- a/ui/gl/gpu_switching_observer.h +++ b/ui/gl/gpu_switching_observer.h
@@ -12,6 +12,8 @@ class GL_EXPORT GpuSwitchingObserver { public: + virtual ~GpuSwitchingObserver() = default; + // Called for any observer when the system switches to a different GPU. virtual void OnGpuSwitched(gl::GpuPreference active_gpu_heuristic) {}
diff --git a/ui/gl/hdr_metadata_helper_win.cc b/ui/gl/hdr_metadata_helper_win.cc index d09e5b6d..80b63e0 100644 --- a/ui/gl/hdr_metadata_helper_win.cc +++ b/ui/gl/hdr_metadata_helper_win.cc
@@ -3,6 +3,7 @@ // found in the LICENSE file. #include "ui/gl/hdr_metadata_helper_win.h" +#include "ui/gl/gpu_switching_manager.h" namespace { @@ -19,9 +20,12 @@ Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device) : d3d11_device_(std::move(d3d11_device)) { UpdateDisplayMetadata(); + ui::GpuSwitchingManager::GetInstance()->AddObserver(this); } -HDRMetadataHelperWin::~HDRMetadataHelperWin() = default; +HDRMetadataHelperWin::~HDRMetadataHelperWin() { + ui::GpuSwitchingManager::GetInstance()->RemoveObserver(this); +} absl::optional<DXGI_HDR_METADATA_HDR10> HDRMetadataHelperWin::GetDisplayMetadata() { @@ -131,4 +135,11 @@ return metadata; } +void HDRMetadataHelperWin::OnDisplayAdded() { + UpdateDisplayMetadata(); +} + +void HDRMetadataHelperWin::OnDisplayRemoved() { + UpdateDisplayMetadata(); +} } // namespace gl
diff --git a/ui/gl/hdr_metadata_helper_win.h b/ui/gl/hdr_metadata_helper_win.h index 0551518..6d1277c 100644 --- a/ui/gl/hdr_metadata_helper_win.h +++ b/ui/gl/hdr_metadata_helper_win.h
@@ -12,13 +12,14 @@ #include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/gfx/hdr_metadata.h" #include "ui/gl/gl_export.h" +#include "ui/gl/gpu_switching_observer.h" namespace gl { // This is a very hacky way to get the display characteristics. // It should be replaced by something that actually knows which // display is going to be used for, well, display. -class GL_EXPORT HDRMetadataHelperWin { +class GL_EXPORT HDRMetadataHelperWin : ui::GpuSwitchingObserver { public: explicit HDRMetadataHelperWin( Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device); @@ -26,7 +27,7 @@ HDRMetadataHelperWin(const HDRMetadataHelperWin&) = delete; HDRMetadataHelperWin& operator=(const HDRMetadataHelperWin&) = delete; - ~HDRMetadataHelperWin(); + ~HDRMetadataHelperWin() override; // Return the metadata for the display, if available. Must call // UpdateDisplayMetadata first. @@ -40,6 +41,10 @@ static DXGI_HDR_METADATA_HDR10 HDRMetadataToDXGI( const gfx::HDRMetadata& hdr_metadata); + // Implements GpuSwitchingObserver + void OnDisplayAdded() override; + void OnDisplayRemoved() override; + private: Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device_; absl::optional<DXGI_HDR_METADATA_HDR10> hdr_metadata_;
diff --git a/ui/ozone/platform/wayland/emulate/wayland_input_emulate.cc b/ui/ozone/platform/wayland/emulate/wayland_input_emulate.cc index 785010a..b534ddc9 100644 --- a/ui/ozone/platform/wayland/emulate/wayland_input_emulate.cc +++ b/ui/ozone/platform/wayland/emulate/wayland_input_emulate.cc
@@ -188,15 +188,6 @@ return; } - auto* wayland_proxy = wl::WaylandProxy::GetInstance(); - DCHECK(wayland_proxy); - - auto* wlsurface = wayland_proxy->GetWlSurfaceForAcceleratedWidget(widget); - - // Raise the window and set keyboard focus. - if (!wayland_proxy->WindowHasKeyboardFocus(widget)) - weston_test_activate_surface(weston_test_, wlsurface); - timespec ts = (base::TimeTicks::Now() - base::TimeTicks()).ToTimeSpec(); weston_test_send_key(weston_test_, static_cast<uint64_t>(ts.tv_sec) >> 32, ts.tv_sec & 0xffffffff, ts.tv_nsec, @@ -204,6 +195,8 @@ (event_type == ui::EventType::ET_KEY_PRESSED ? WL_KEYBOARD_KEY_STATE_PRESSED : WL_KEYBOARD_KEY_STATE_RELEASED)); + auto* wayland_proxy = wl::WaylandProxy::GetInstance(); + DCHECK(wayland_proxy); wayland_proxy->ScheduleDisplayFlush(); } @@ -223,26 +216,14 @@ return; } - auto* wayland_proxy = wl::WaylandProxy::GetInstance(); - DCHECK(wayland_proxy); - - auto* wlsurface = wayland_proxy->GetWlSurfaceForAcceleratedWidget(widget); - - // If it's a toplevel window, activate it. This results in raising the the - // parent window and its children windows. - auto window_type = wayland_proxy->GetWindowType(widget); - if (window_type != ui::PlatformWindowType::kTooltip && - window_type != ui::PlatformWindowType::kMenu && - !wayland_proxy->WindowHasPointerFocus(widget)) { - weston_test_activate_surface(weston_test_, wlsurface); - } - timespec ts = (base::TimeTicks::Now() - base::TimeTicks()).ToTimeSpec(); weston_test_send_touch(weston_test_, static_cast<uint64_t>(ts.tv_sec) >> 32, ts.tv_sec & 0xffffffff, ts.tv_nsec, id, wl_fixed_from_int(touch_screen_loc.x()), wl_fixed_from_int(touch_screen_loc.y()), EventTypeToWaylandTouchType(event_type)); + auto* wayland_proxy = wl::WaylandProxy::GetInstance(); + DCHECK(wayland_proxy); wayland_proxy->ScheduleDisplayFlush(); }
diff --git a/ui/views/accessibility/ax_aura_obj_cache_unittest.cc b/ui/views/accessibility/ax_aura_obj_cache_unittest.cc index 12fa9db..6e6a9d1 100644 --- a/ui/views/accessibility/ax_aura_obj_cache_unittest.cc +++ b/ui/views/accessibility/ax_aura_obj_cache_unittest.cc
@@ -27,7 +27,6 @@ #include "ui/views/accessibility/view_accessibility.h" #include "ui/views/controls/button/label_button.h" #include "ui/views/test/widget_test.h" -#include "ui/views/widget/unique_widget_ptr.h" #include "ui/views/widget/widget_delegate.h" namespace views { @@ -94,6 +93,10 @@ ASSERT_NE(cache.GetID(widget.get()), ui::kInvalidAXNodeID); ASSERT_EQ(ui::kInvalidAXNodeID, cache.GetID(parent)); ASSERT_EQ(ui::kInvalidAXNodeID, cache.GetID(child)); + + // Explicitly delete |parent| to prevent a memory leak, since calling + // RemoveChildView() doesn't delete it. + delete parent; } // Helper for the ViewDestruction test. @@ -157,8 +160,9 @@ // the cache. AXAuraObjCache* cache = new AXAuraObjCache(); - UniqueWidgetPtr widget = std::make_unique<Widget>(); + Widget* widget = new Widget(); Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW); + params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; params.bounds = gfx::Rect(0, 0, 200, 200); widget->Init(std::move(params)); cache->OnRootWindowObjCreated(widget->GetNativeWindow()); @@ -166,36 +170,41 @@ widget->Activate(); base::RunLoop().RunUntilIdle(); - cache->GetOrCreate(widget.get()); + cache->GetOrCreate(widget); // Everything should have an ID, indicating it's in the cache. - EXPECT_NE(cache->GetID(widget.get()), ui::kInvalidAXNodeID); + EXPECT_NE(cache->GetID(widget), ui::kInvalidAXNodeID); // Create a second top-level widget to ensure |root_windows_| isn't empty. - UniqueWidgetPtr widget2 = std::make_unique<Widget>(); + Widget* widget2 = new Widget(); Widget::InitParams params2 = CreateParams(Widget::InitParams::TYPE_WINDOW); + params2.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; params2.bounds = gfx::Rect(0, 0, 200, 200); widget2->Init(std::move(params2)); cache->OnRootWindowObjCreated(widget2->GetNativeWindow()); - cache->GetOrCreate(widget2.get()); + cache->GetOrCreate(widget2); widget2->Activate(); base::RunLoop().RunUntilIdle(); // Everything should have an ID, indicating it's in the cache. - EXPECT_NE(cache->GetID(widget2.get()), ui::kInvalidAXNodeID); + EXPECT_NE(cache->GetID(widget2), ui::kInvalidAXNodeID); // Delete the first widget, then delete the cache. cache->OnRootWindowObjDestroyed(widget->GetNativeWindow()); - widget.reset(); + delete widget; delete cache; + + // Delete |widget2| so it doesn't leak. + delete widget2; } TEST_F(AXAuraObjCacheTest, ValidTree) { // Create a parent window. - UniqueWidgetPtr parent_widget = std::make_unique<Widget>(); + std::unique_ptr<Widget> parent_widget = std::make_unique<Widget>(); Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW); params.bounds = gfx::Rect(0, 0, 200, 200); + params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; parent_widget->Init(std::move(params)); parent_widget->GetNativeWindow()->SetTitle(u"ParentWindow"); parent_widget->Show(); @@ -238,9 +247,10 @@ TEST_F(AXAuraObjCacheTest, GetFocusIsUnignoredAncestor) { AXAuraObjCache cache; - UniqueWidgetPtr widget = std::make_unique<Widget>(); + std::unique_ptr<Widget> widget = std::make_unique<Widget>(); Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW); params.bounds = gfx::Rect(0, 0, 200, 200); + params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; params.activatable = views::Widget::InitParams::Activatable::kYes; widget->Init(std::move(params)); widget->Show(); @@ -365,9 +375,10 @@ TEST_F(AXAuraObjCacheTest, VirtualViews) { AXAuraObjCache cache; - UniqueWidgetPtr widget = std::make_unique<Widget>(); + std::unique_ptr<Widget> widget = std::make_unique<Widget>(); Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW); params.bounds = gfx::Rect(0, 0, 200, 200); + params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; params.activatable = views::Widget::InitParams::Activatable::kYes; widget->Init(std::move(params)); widget->Show();
diff --git a/ui/views/accessibility/ax_tree_source_views_unittest.cc b/ui/views/accessibility/ax_tree_source_views_unittest.cc index f640535..b5a6963 100644 --- a/ui/views/accessibility/ax_tree_source_views_unittest.cc +++ b/ui/views/accessibility/ax_tree_source_views_unittest.cc
@@ -22,8 +22,6 @@ #include "ui/views/controls/label.h" #include "ui/views/controls/textfield/textfield.h" #include "ui/views/test/views_test_base.h" -#include "ui/views/test/widget_test.h" -#include "ui/views/widget/unique_widget_ptr.h" #include "ui/views/widget/widget.h" namespace views { @@ -51,6 +49,7 @@ ViewsTestBase::SetUp(); widget_ = std::make_unique<Widget>(); Widget::InitParams params(Widget::InitParams::TYPE_WINDOW_FRAMELESS); + params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; params.bounds = gfx::Rect(11, 22, 333, 444); params.context = GetContext(); widget_->Init(std::move(params)); @@ -74,7 +73,7 @@ ViewsTestBase::TearDown(); } - UniqueWidgetPtr widget_; + std::unique_ptr<Widget> widget_; raw_ptr<Label> label1_ = nullptr; // Owned by views hierarchy. raw_ptr<Label> label2_ = nullptr; // Owned by views hierarchy. raw_ptr<Textfield> textfield_ = nullptr; // Owned by views hierarchy. @@ -199,14 +198,9 @@ // GetFocus() reflects the focused child window. EXPECT_NE(nullptr, cache.GetFocus()); - test::WidgetDestroyedWaiter waiter(widget_.get()); - // Close the widget to destroy the child. widget_.reset(); - // Wait for the async widget close. - waiter.Wait(); - // GetFocus() should return null and no use-after-free to call it. EXPECT_EQ(nullptr, cache.GetFocus()); }
diff --git a/ui/views/accessibility/view_ax_platform_node_delegate_auralinux_unittest.cc b/ui/views/accessibility/view_ax_platform_node_delegate_auralinux_unittest.cc index e2882f8..4447036 100644 --- a/ui/views/accessibility/view_ax_platform_node_delegate_auralinux_unittest.cc +++ b/ui/views/accessibility/view_ax_platform_node_delegate_auralinux_unittest.cc
@@ -10,7 +10,6 @@ #include "ui/accessibility/platform/ax_platform_node.h" #include "ui/views/controls/textfield/textfield.h" #include "ui/views/test/views_test_base.h" -#include "ui/views/widget/unique_widget_ptr.h" namespace views { namespace test { @@ -26,11 +25,12 @@ }; TEST_F(ViewAXPlatformNodeDelegateAuraLinuxTest, TextfieldAccessibility) { - UniqueWidgetPtr widget = std::make_unique<Widget>(); + Widget widget; Widget::InitParams init_params = CreateParams(Widget::InitParams::TYPE_POPUP); - widget->Init(std::move(init_params)); + init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + widget.Init(std::move(init_params)); - View* content = widget->SetContentsView(std::make_unique<View>()); + View* content = widget.SetContentsView(std::make_unique<View>()); Textfield* textfield = new Textfield; textfield->SetAccessibleName(u"Name"); @@ -101,28 +101,30 @@ } TEST_F(ViewAXPlatformNodeDelegateAuraLinuxTest, AuraChildWidgets) { - // Create the parent widget-> - UniqueWidgetPtr widget = std::make_unique<Widget>(); + // Create the parent widget. + Widget widget; Widget::InitParams init_params = CreateParams(Widget::InitParams::TYPE_WINDOW); + init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; init_params.bounds = gfx::Rect(0, 0, 400, 200); - widget->Init(std::move(init_params)); - widget->Show(); + widget.Init(std::move(init_params)); + widget.Show(); // Initially it has 1 child. AtkObject* root_view_accessible = - widget->GetRootView()->GetNativeViewAccessible(); + widget.GetRootView()->GetNativeViewAccessible(); ASSERT_EQ(1, atk_object_get_n_accessible_children(root_view_accessible)); // Create the child widget, one of two ways (see below). - UniqueWidgetPtr child_widget = std::make_unique<Widget>(); + Widget child_widget; Widget::InitParams child_init_params = CreateParams(Widget::InitParams::TYPE_BUBBLE); - child_init_params.parent = widget->GetNativeView(); + child_init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + child_init_params.parent = widget.GetNativeView(); child_init_params.bounds = gfx::Rect(30, 40, 100, 50); child_init_params.child = false; - child_widget->Init(std::move(child_init_params)); - child_widget->Show(); + child_widget.Init(std::move(child_init_params)); + child_widget.Show(); // Now the AtkObject for the parent widget should have 2 children. ASSERT_EQ(2, atk_object_get_n_accessible_children(root_view_accessible)); @@ -130,7 +132,7 @@ // Make sure that querying the parent of the child gets us back to // the original parent. AtkObject* child_widget_accessible = - child_widget->GetRootView()->GetNativeViewAccessible(); + child_widget.GetRootView()->GetNativeViewAccessible(); ASSERT_EQ(atk_object_get_parent(child_widget_accessible), root_view_accessible); @@ -143,20 +145,22 @@ } // Tests if atk_object_get_index_in_parent doesn't DCHECK after the -// corresponding View is removed from a widget-> +// corresponding View is removed from a Widget. TEST_F(ViewAXPlatformNodeDelegateAuraLinuxTest, IndexInParent) { // Create the Widget that will represent the application - UniqueWidgetPtr parent_widget = std::make_unique<Widget>(); + Widget parent_widget; Widget::InitParams init_params = CreateParams(Widget::InitParams::TYPE_WINDOW); - parent_widget->Init(std::move(init_params)); - parent_widget->Show(); + init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + parent_widget.Init(std::move(init_params)); + parent_widget.Show(); // |widget| will be destroyed later. - UniqueWidgetPtr widget = std::make_unique<Widget>(); + std::unique_ptr<Widget> widget = std::make_unique<Widget>(); Widget::InitParams child_init_params = CreateParams(Widget::InitParams::TYPE_POPUP); - child_init_params.parent = parent_widget->GetNativeView(); + child_init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + child_init_params.parent = parent_widget.GetNativeView(); widget->Init(std::move(child_init_params)); widget->Show();
diff --git a/ui/views/accessibility/view_ax_platform_node_delegate_unittest.cc b/ui/views/accessibility/view_ax_platform_node_delegate_unittest.cc index 3c6255e..e857b113 100644 --- a/ui/views/accessibility/view_ax_platform_node_delegate_unittest.cc +++ b/ui/views/accessibility/view_ax_platform_node_delegate_unittest.cc
@@ -35,7 +35,6 @@ #include "ui/views/controls/table/table_view.h" #include "ui/views/test/menu_test_utils.h" #include "ui/views/test/views_test_base.h" -#include "ui/views/widget/unique_widget_ptr.h" #include "ui/views/widget/widget.h" namespace views { @@ -252,6 +251,7 @@ owner_ = std::make_unique<Widget>(); Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); + params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; owner_->Init(std::move(params)); owner_->Show(); @@ -303,7 +303,7 @@ raw_ptr<SubmenuView> submenu_ = nullptr; std::unique_ptr<TestMenuDelegate> menu_delegate_; std::unique_ptr<MenuRunner> runner_; - UniqueWidgetPtr owner_; + std::unique_ptr<Widget> owner_; }; TEST_F(ViewAXPlatformNodeDelegateTest, FocusBehaviorShouldAffectIgnoredState) { @@ -1116,8 +1116,9 @@ // this observer to simulate it. AXAuraObjCache cache; TestAXEventObserver observer(&cache); - UniqueWidgetPtr widget = std::make_unique<Widget>(); + std::unique_ptr<Widget> widget(new Widget); Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); + params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; widget->Init(std::move(params)); widget->Show();
diff --git a/ui/views/accessibility/view_ax_platform_node_delegate_win_unittest.cc b/ui/views/accessibility/view_ax_platform_node_delegate_win_unittest.cc index 94b960d..8a6e215 100644 --- a/ui/views/accessibility/view_ax_platform_node_delegate_win_unittest.cc +++ b/ui/views/accessibility/view_ax_platform_node_delegate_win_unittest.cc
@@ -23,7 +23,6 @@ #include "ui/views/controls/scroll_view.h" #include "ui/views/controls/textfield/textfield.h" #include "ui/views/test/views_test_base.h" -#include "ui/views/widget/unique_widget_ptr.h" using base::win::ScopedBstr; using base::win::ScopedVariant; @@ -96,11 +95,12 @@ }; TEST_F(ViewAXPlatformNodeDelegateWinTest, TextfieldAccessibility) { - UniqueWidgetPtr widget = std::make_unique<Widget>(); + Widget widget; Widget::InitParams init_params = CreateParams(Widget::InitParams::TYPE_POPUP); - widget->Init(std::move(init_params)); + init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + widget.Init(std::move(init_params)); - View* content = widget->SetContentsView(std::make_unique<View>()); + View* content = widget.SetContentsView(std::make_unique<View>()); Textfield* textfield = new Textfield; textfield->SetAccessibleName(u"Name"); @@ -142,11 +142,12 @@ } TEST_F(ViewAXPlatformNodeDelegateWinTest, TextfieldAssociatedLabel) { - UniqueWidgetPtr widget = std::make_unique<Widget>(); + Widget widget; Widget::InitParams init_params = CreateParams(Widget::InitParams::TYPE_POPUP); - widget->Init(std::move(init_params)); + init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + widget.Init(std::move(init_params)); - View* content = widget->SetContentsView(std::make_unique<View>()); + View* content = widget.SetContentsView(std::make_unique<View>()); Label* label = new Label(u"Label"); content->AddChildView(label); @@ -209,35 +210,37 @@ TEST_P(ViewAXPlatformNodeDelegateWinTestWithBoolChildFlag, AuraChildWidgets) { // Create the parent widget. - UniqueWidgetPtr widget = std::make_unique<Widget>(); + Widget widget; Widget::InitParams init_params = CreateParams(Widget::InitParams::TYPE_WINDOW); + init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; init_params.bounds = gfx::Rect(0, 0, 400, 200); - widget->Init(std::move(init_params)); - widget->Show(); + widget.Init(std::move(init_params)); + widget.Show(); // Initially it has 1 child. ComPtr<IAccessible> root_view_accessible( - widget->GetRootView()->GetNativeViewAccessible()); + widget.GetRootView()->GetNativeViewAccessible()); LONG child_count = 0; ASSERT_EQ(S_OK, root_view_accessible->get_accChildCount(&child_count)); ASSERT_EQ(1L, child_count); // Create the child widget, one of two ways (see below). - UniqueWidgetPtr child_widget = std::make_unique<Widget>(); + Widget child_widget; Widget::InitParams child_init_params = CreateParams(Widget::InitParams::TYPE_BUBBLE); - child_init_params.parent = widget->GetNativeView(); + child_init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + child_init_params.parent = widget.GetNativeView(); child_init_params.bounds = gfx::Rect(30, 40, 100, 50); // NOTE: this test is run two times, GetParam() returns a different // value each time. The first time we test with child = false, // making this an owned widget (a transient child). The second time - // we test with child = true, making it a child widget-> + // we test with child = true, making it a child widget. child_init_params.child = GetParam(); - child_widget->Init(std::move(child_init_params)); - child_widget->Show(); + child_widget.Init(std::move(child_init_params)); + child_widget.Show(); // Now the IAccessible for the parent widget should have 2 children. ASSERT_EQ(S_OK, root_view_accessible->get_accChildCount(&child_count)); @@ -254,7 +257,7 @@ EXPECT_EQ(200, height); // Get the IAccessible for the second child of the parent widget, - // which should be the one for our child widget-> + // which should be the one for our child widget. ComPtr<IDispatch> child_widget_dispatch; ComPtr<IAccessible> child_widget_accessible; ScopedVariant child_index_2(2); @@ -262,7 +265,7 @@ &child_widget_dispatch)); ASSERT_EQ(S_OK, child_widget_dispatch.As(&child_widget_accessible)); - // Check the bounds of the IAccessible for the child widget-> + // Check the bounds of the IAccessible for the child widget. // This is a sanity check to make sure we have the right object // and not some other view. ASSERT_EQ(S_OK, child_widget_accessible->accLocation(&x, &y, &width, &height, @@ -285,11 +288,12 @@ // Flaky on Windows: https://crbug.com/461837. TEST_F(ViewAXPlatformNodeDelegateWinTest, DISABLED_RetrieveAllAlerts) { - UniqueWidgetPtr widget = std::make_unique<Widget>(); + Widget widget; Widget::InitParams init_params = CreateParams(Widget::InitParams::TYPE_POPUP); - widget->Init(std::move(init_params)); + init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + widget.Init(std::move(init_params)); - View* content = widget->SetContentsView(std::make_unique<View>()); + View* content = widget.SetContentsView(std::make_unique<View>()); View* infobar = new View; content->AddChildView(infobar); @@ -346,7 +350,6 @@ } // Test trying to retrieve child widgets during window close does not crash. -// TODO(crbug.com/1218885): Remove this after WIDGET_OWNS_NATIVE_WIDGET is gone. TEST_F(ViewAXPlatformNodeDelegateWinTest, GetAllOwnedWidgetsCrash) { Widget widget; Widget::InitParams init_params = @@ -365,14 +368,14 @@ TEST_F(ViewAXPlatformNodeDelegateWinTest, WindowHasRoleApplication) { // We expect that our internal window object does not expose // ROLE_SYSTEM_WINDOW, but ROLE_SYSTEM_PANE instead. - UniqueWidgetPtr widget = std::make_unique<Widget>(); + Widget widget; Widget::InitParams init_params = CreateParams(Widget::InitParams::TYPE_WINDOW); init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; - widget->Init(std::move(init_params)); + widget.Init(std::move(init_params)); ComPtr<IAccessible> accessible( - widget->GetRootView()->GetNativeViewAccessible()); + widget.GetRootView()->GetNativeViewAccessible()); ScopedVariant childid_self(CHILDID_SELF); ScopedVariant role; EXPECT_EQ(S_OK, accessible->get_accRole(childid_self, role.Receive())); @@ -383,11 +386,12 @@ TEST_F(ViewAXPlatformNodeDelegateWinTest, Overrides) { // We expect that our internal window object does not expose // ROLE_SYSTEM_WINDOW, but ROLE_SYSTEM_PANE instead. - UniqueWidgetPtr widget = std::make_unique<Widget>(); + Widget widget; Widget::InitParams init_params = CreateParams(Widget::InitParams::TYPE_POPUP); - widget->Init(std::move(init_params)); + init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + widget.Init(std::move(init_params)); - View* contents_view = widget->SetContentsView(std::make_unique<View>()); + View* contents_view = widget.SetContentsView(std::make_unique<View>()); View* alert_view = new ScrollView; alert_view->GetViewAccessibility().OverrideRole(ax::mojom::Role::kAlert); @@ -440,11 +444,12 @@ } TEST_F(ViewAXPlatformNodeDelegateWinTest, GridRowColumnCount) { - UniqueWidgetPtr widget = std::make_unique<Widget>(); + Widget widget; Widget::InitParams init_params = CreateParams(Widget::InitParams::TYPE_POPUP); - widget->Init(std::move(init_params)); + init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + widget.Init(std::move(init_params)); - View* content = widget->SetContentsView(std::make_unique<View>()); + View* content = widget.SetContentsView(std::make_unique<View>()); TestListGridView* grid = new TestListGridView(); content->AddChildView(grid); @@ -523,11 +528,12 @@ // Since we can't test IsUIAControl directly, we go through the // UIA_IsControlElementPropertyId, which is computed using IsUIAControl. - UniqueWidgetPtr widget = std::make_unique<Widget>(); + Widget widget; Widget::InitParams init_params = CreateParams(Widget::InitParams::TYPE_POPUP); - widget->Init(std::move(init_params)); + init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + widget.Init(std::move(init_params)); - View* content = widget->SetContentsView(std::make_unique<View>()); + View* content = widget.SetContentsView(std::make_unique<View>()); Textfield* text_field = new Textfield(); text_field->SetReadOnly(true); @@ -582,7 +588,7 @@ std::make_unique<TableView>(model_.get(), columns, TEXT_ONLY, true); table_ = table.get(); - widget_ = std::make_unique<Widget>(); + widget_ = new Widget; Widget::InitParams init_params = CreateParams(Widget::InitParams::TYPE_POPUP); init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; @@ -611,7 +617,7 @@ protected: std::unique_ptr<TestTableModel> model_; - UniqueWidgetPtr widget_; + raw_ptr<Widget> widget_ = nullptr; raw_ptr<TableView> table_ = nullptr; // Owned by parent. };
diff --git a/ui/views/accessibility/views_ax_tree_manager_unittest.cc b/ui/views/accessibility/views_ax_tree_manager_unittest.cc index 6d4f5c9..dcf27f4 100644 --- a/ui/views/accessibility/views_ax_tree_manager_unittest.cc +++ b/ui/views/accessibility/views_ax_tree_manager_unittest.cc
@@ -29,7 +29,6 @@ #include "ui/views/controls/label.h" #include "ui/views/test/views_test_base.h" #include "ui/views/view.h" -#include "ui/views/widget/unique_widget_ptr.h" #include "ui/views/widget/widget.h" namespace views { @@ -49,6 +48,7 @@ public ::testing::WithParamInterface<bool> { public: ViewsAXTreeManagerTest() = default; + ~ViewsAXTreeManagerTest() override = default; ViewsAXTreeManagerTest(const ViewsAXTreeManagerTest&) = delete; ViewsAXTreeManagerTest& operator=(const ViewsAXTreeManagerTest&) = delete; @@ -60,19 +60,12 @@ const std::string& name_or_value) const; void WaitFor(const ui::AXEventGenerator::Event event); - Widget* widget() const { return widget_.get(); } + Widget* widget() const { return widget_; } Button* button() const { return button_; } Label* label() const { return label_; } - ViewsAXTreeManager* manager() const { - return features::IsAccessibilityTreeForViewsEnabled() - ? absl::get<raw_ptr<ViewsAXTreeManager>>(manager_).get() - : absl::get<std::unique_ptr<ViewsAXTreeManager>>(manager_).get(); - } + ViewsAXTreeManager* manager() const { return manager_.get(); } private: - using TestOwnedManager = std::unique_ptr<ViewsAXTreeManager>; - using WidgetOwnedManager = raw_ptr<ViewsAXTreeManager>; - ui::AXNode* FindNodeInSubtree(ui::AXNode* root, const ax::mojom::Role role, const std::string& name_or_value) const; @@ -80,10 +73,10 @@ ui::AXEventGenerator::Event event, ui::AXNodeID node_id); - UniqueWidgetPtr widget_; + raw_ptr<Widget> widget_ = nullptr; raw_ptr<Button> button_ = nullptr; raw_ptr<Label> label_ = nullptr; - absl::variant<TestOwnedManager, WidgetOwnedManager> manager_; + std::unique_ptr<ViewsAXTreeManager> manager_; ui::AXEventGenerator::Event event_to_wait_for_; std::unique_ptr<base::RunLoop> loop_runner_; base::test::ScopedFeatureList scoped_feature_list_; @@ -97,8 +90,9 @@ {features::kEnableAccessibilityTreeForViews}, {}); } - widget_ = std::make_unique<Widget>(); + widget_ = new Widget; Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW); + params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; params.bounds = gfx::Rect(0, 0, 200, 200); widget_->Init(std::move(params)); @@ -114,12 +108,13 @@ // AccessibilityTreeForViewsEnabled will create and manage its own // ViewsAXTreeManager, so we don't need to create one for testing. if (features::IsAccessibilityTreeForViewsEnabled()) { - manager_ = widget_->GetRootView()->GetViewAccessibility().AXTreeManager(); + manager_.reset( + widget_->GetRootView()->GetViewAccessibility().AXTreeManager()); } else { - manager_ = std::make_unique<ViewsAXTreeManager>(widget_.get()); + manager_ = std::make_unique<ViewsAXTreeManager>(widget_); } - ASSERT_NE(nullptr, manager()); + ASSERT_NE(nullptr, manager_); manager()->SetGeneratedEventCallbackForTesting(base::BindRepeating( &ViewsAXTreeManagerTest::OnGeneratedEvent, base::Unretained(this))); WaitFor(ui::AXEventGenerator::Event::SUBTREE_CREATED); @@ -128,11 +123,7 @@ void ViewsAXTreeManagerTest::TearDown() { if (manager()) manager()->UnsetGeneratedEventCallbackForTesting(); - if (features::IsAccessibilityTreeForViewsEnabled()) - manager_.emplace<WidgetOwnedManager>(nullptr); - else - manager_.emplace<TestOwnedManager>(nullptr); - + manager_.reset(); CloseWidget(); ViewsTestBase::TearDown(); } @@ -224,6 +215,23 @@ WaitFor(ui::AXEventGenerator::Event::CHECKED_STATE_CHANGED); } +TEST_P(ViewsAXTreeManagerTest, CloseWidget) { + // This test is only relevant when IsAccessibilityTreeForViewsEnabled is set, + // as it tests the lifetime management of ViewsAXTreeManager when a Widget is + // closed. + if (!features::IsAccessibilityTreeForViewsEnabled()) + return; + + ui::AXNode* ax_button = FindNode(ax::mojom::Role::kButton, ""); + ASSERT_NE(nullptr, ax_button); + + CloseWidget(); + + // Looking up a node after its Widget has been closed should return nullptr. + ax_button = FindNode(ax::mojom::Role::kButton, ""); + EXPECT_EQ(nullptr, ax_button); +} + TEST_P(ViewsAXTreeManagerTest, MultipleTopLevelWidgets) { // This test is only relevant when IsAccessibilityTreeForViewsEnabled is set, // as it tests the lifetime management of ViewsAXTreeManager when a Widget is @@ -231,8 +239,9 @@ if (!features::IsAccessibilityTreeForViewsEnabled()) return; - UniqueWidgetPtr second_widget = std::make_unique<Widget>(); + std::unique_ptr<Widget> second_widget = std::make_unique<Widget>(); Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW); + params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; params.bounds = gfx::Rect(0, 0, 200, 200); second_widget->Init(std::move(params));
diff --git a/ui/views_content_client/views_content_main_delegate.cc b/ui/views_content_client/views_content_main_delegate.cc index e891e1a..442fcf8 100644 --- a/ui/views_content_client/views_content_main_delegate.cc +++ b/ui/views_content_client/views_content_main_delegate.cc
@@ -43,7 +43,7 @@ ViewsContentMainDelegate::~ViewsContentMainDelegate() { } -bool ViewsContentMainDelegate::BasicStartupComplete(int* exit_code) { +absl::optional<int> ViewsContentMainDelegate::BasicStartupComplete() { const base::CommandLine& command_line = *base::CommandLine::ForCurrentProcess(); std::string process_type = @@ -60,7 +60,7 @@ content::RegisterShellPathProvider(); - return false; + return absl::nullopt; } void ViewsContentMainDelegate::PreSandboxStartup() { @@ -85,9 +85,14 @@ views_content_client_->OnResourcesLoaded(); } -void ViewsContentMainDelegate::PreBrowserMain() { - content::ContentMainDelegate::PreBrowserMain(); +absl::optional<int> ViewsContentMainDelegate::PreBrowserMain() { + absl::optional<int> exit_code = + content::ContentMainDelegate::PreBrowserMain(); + if (exit_code.has_value()) + return exit_code; + ViewsContentClientMainParts::PreBrowserMain(); + return absl::nullopt; } content::ContentClient* ViewsContentMainDelegate::CreateContentClient() {
diff --git a/ui/views_content_client/views_content_main_delegate.h b/ui/views_content_client/views_content_main_delegate.h index 10fdc8d..a474e47 100644 --- a/ui/views_content_client/views_content_main_delegate.h +++ b/ui/views_content_client/views_content_main_delegate.h
@@ -26,9 +26,9 @@ ~ViewsContentMainDelegate() override; // content::ContentMainDelegate implementation - bool BasicStartupComplete(int* exit_code) override; + absl::optional<int> BasicStartupComplete() override; void PreSandboxStartup() override; - void PreBrowserMain() override; + absl::optional<int> PreBrowserMain() override; content::ContentClient* CreateContentClient() override; content::ContentBrowserClient* CreateContentBrowserClient() override;
diff --git a/ui/webui/resources/mojo/BUILD.gn b/ui/webui/resources/mojo/BUILD.gn index be2fcb4f2..dcd74878 100644 --- a/ui/webui/resources/mojo/BUILD.gn +++ b/ui/webui/resources/mojo/BUILD.gn
@@ -50,11 +50,13 @@ in_files += [ "ui/gfx/range/mojom/range.mojom-webui.js", "chromeos/services/bluetooth_config/public/mojom/cros_bluetooth_config.mojom-webui.js", + "chromeos/ash/services/auth_factor_config/public/mojom/auth_factor_config.mojom-webui.js", "chromeos/services/network_config/public/mojom/network_types.mojom-webui.js", "chromeos/services/network_health/public/mojom/network_diagnostics.mojom-webui.js", "chromeos/services/network_health/public/mojom/network_health.mojom-webui.js", ] extra_deps += [ + "//chromeos/ash/services/auth_factor_config/public/mojom:mojom_js__generator", "//chromeos/services/bluetooth_config/public/mojom:mojom_js__generator", "//chromeos/services/network_config/public/mojom:network_types_js__generator", "//chromeos/services/network_health/public/mojom:mojom_js__generator",
diff --git a/weblayer/app/content_main_delegate_impl.cc b/weblayer/app/content_main_delegate_impl.cc index 193aa97..cfc1316 100644 --- a/weblayer/app/content_main_delegate_impl.cc +++ b/weblayer/app/content_main_delegate_impl.cc
@@ -154,11 +154,7 @@ ContentMainDelegateImpl::~ContentMainDelegateImpl() = default; -bool ContentMainDelegateImpl::BasicStartupComplete(int* exit_code) { - int dummy; - if (!exit_code) - exit_code = &dummy; - +absl::optional<int> ContentMainDelegateImpl::BasicStartupComplete() { // Disable features which are not currently supported in WebLayer. This allows // sites to do feature detection, and prevents crashes in some not fully // implemented features. @@ -233,7 +229,7 @@ RegisterPathProvider(); - return false; + return absl::nullopt; } bool ContentMainDelegateImpl::ShouldCreateFeatureList(InvokedIn invoked_in) { @@ -299,9 +295,11 @@ #endif } -void ContentMainDelegateImpl::PostEarlyInitialization(InvokedIn invoked_in) { +absl::optional<int> ContentMainDelegateImpl::PostEarlyInitialization( + InvokedIn invoked_in) { if (absl::holds_alternative<InvokedInBrowserProcess>(invoked_in)) browser_client_->CreateFeatureListAndFieldTrials(); + return absl::nullopt; } absl::variant<int, content::MainFunctionParams>
diff --git a/weblayer/app/content_main_delegate_impl.h b/weblayer/app/content_main_delegate_impl.h index 151ecc6..9268e56 100644 --- a/weblayer/app/content_main_delegate_impl.h +++ b/weblayer/app/content_main_delegate_impl.h
@@ -28,11 +28,11 @@ ~ContentMainDelegateImpl() override; // ContentMainDelegate implementation: - bool BasicStartupComplete(int* exit_code) override; + absl::optional<int> BasicStartupComplete() override; bool ShouldCreateFeatureList(InvokedIn invoked_in) override; variations::VariationsIdsProvider* CreateVariationsIdsProvider() override; void PreSandboxStartup() override; - void PostEarlyInitialization(InvokedIn invoked_in) override; + absl::optional<int> PostEarlyInitialization(InvokedIn invoked_in) override; absl::variant<int, content::MainFunctionParams> RunProcess( const std::string& process_type, content::MainFunctionParams main_function_params) override;