diff --git a/DEPS b/DEPS index fa37d7e..0df12657 100644 --- a/DEPS +++ b/DEPS
@@ -133,9 +133,6 @@ # Fetch clang-tidy into the same bin/ directory as our clang binary. 'checkout_clang_tidy': False, - # Fetch clang libraries and headers in order to build clang tooling. - 'checkout_clang_libs': False, - # Fetch clangd into the same bin/ directory as our clang binary. 'checkout_clangd': False, @@ -241,27 +238,12 @@ # instead of downloading the prebuilt pinned revision. 'llvm_force_head_revision': False, - # Fetch Rust toolchain built against our LLVM revision instead of the Android - # Rust toolchain. Experimental. The corresponding GN arg - # use_chromium_rust_toolchain directs the build to use this toolchain instead - # of the Android toolchain. - # - # We avoid doing this on toolchain build bots (where - # `checkout_rust_toolchain_deps` is set) since they are building the Rust - # toolchain. - 'checkout_rust': 'host_os == "linux" and not checkout_rust_toolchain_deps', + # Fetch Rust toolchain. + 'checkout_rust': 'host_os == "linux"', # Fetch the Android team's Rust toolchain. 'fetch_android_chromium_rust_toolchain': False, - # Build in-tree Rust toolchain. checkout_clang_libs must also be True. The - # corresponding GN arg use_chromium_rust_toolchain directs the build to use - # the in-tree toolchain instead of the Android toolchain. - # - # This is not intended for local development. - # Prefer using //tools/rust/build_rust.py directly. - 'build_chromium_rust_toolchain': False, - # See //docs/testing/regression-test-selection.md # for info on RTS 'checkout_rts_model': False, @@ -289,12 +271,6 @@ # siso CIPD package version. 'siso_version': 'latest', - # Fetch dependencies needed to build Rust toolchain. Not needed if developing - # Rust code in Chromium; instead enable checkout_rust - # (which is gradually being made the default across different platforms). - # Only use if building the Rust toolchain. - 'checkout_rust_toolchain_deps': False, - 'android_git': 'https://android.googlesource.com', 'aomedia_git': 'https://aomedia.googlesource.com', 'boringssl_git': 'https://boringssl.googlesource.com', @@ -309,15 +285,15 @@ # 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': 'b0c40a307d34a229b789420f5f149d734d84e47c', + 'skia_revision': '2594f990d87beb02837a22a78ec4810f95b25bc9', # 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': 'ac70c755230f2856e08aa06d6fecbc3f01822758', + 'v8_revision': '18894416c9de759907fc9bf7dbb2b6747edd3db3', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ANGLE # and whatever else without interference from each other. - 'angle_revision': '32fa13927f8125b97a4c59edf7347c9a01674285', + 'angle_revision': '735fb48079650cec97ea286e5775f277d90a2cc0', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. @@ -380,7 +356,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling catapult # and whatever else without interference from each other. - 'catapult_revision': 'c5af5d5bf547def27a6b44f119de028ccee76971', + 'catapult_revision': '53cc27b20f1bd1d5118ad1e066af46565e943013', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling CrossBench # and whatever else without interference from each other. @@ -456,7 +432,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libavif # and whatever else without interference from each other. - 'libavif_revision': '901c53bbabfb5d26aa372a1dfc1aa899a85ae264', + 'libavif_revision': '1da58dc6d96ef3a096564037ff447b868be74624', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling nearby # and whatever else without interference from each other. @@ -795,7 +771,7 @@ 'src/clank': { 'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' + - '675aa3a3fdf33d17a7f36132f8c8879b0fd6b370', + 'b65b833c6bbfe6b9eeb583162a968d4b31ceaf4f', 'condition': 'checkout_android and checkout_src_internal', }, @@ -984,7 +960,7 @@ 'packages': [ { 'package': 'chromium/third_party/androidx', - 'version': 'orhmWBieV2HQe8r_6lHZ2myJN0FSXpNO-X_GaO9A5lgC', + 'version': 'pY61Naw_tF_wdhH7RNSoEoedMS5fPOzV1TdWCMRd_kUC', }, ], 'condition': 'checkout_android', @@ -1219,13 +1195,13 @@ }, 'src/third_party/depot_tools': - Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '3ca8d0d0caa46532b338c221dbff03220a64bfc1', + Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '4a2243196c2b9c2fc1a040429dad67cbff5aa703', 'src/third_party/devtools-frontend/src': Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'), 'src/third_party/devtools-frontend-internal': { - 'url': Var('chrome_git') + '/devtools/devtools-internal.git' + '@' + '82ce0c2b01d5f959d297b0b0a5b4363b75143249', + 'url': Var('chrome_git') + '/devtools/devtools-internal.git' + '@' + '0f7452c2ee63313e10790f31f5a094baf47fa444', 'condition': 'checkout_src_internal', }, @@ -1700,7 +1676,7 @@ }, 'src/third_party/perfetto': - Var('android_git') + '/platform/external/perfetto.git' + '@' + 'b57a685175d3070783d25958e0851b8d077b6280', + Var('android_git') + '/platform/external/perfetto.git' + '@' + 'd4f6e083e11e78c7370e0ce938be04c5d556cb0f', 'src/third_party/perl': { 'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3', @@ -1882,10 +1858,10 @@ Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'd1b65aa5a88f6efd900604dfcda840154e9f16e2', 'src/third_party/webgpu-cts/src': - Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '0ac5d460dab4d56f3c07c43eee895557c9d3b9e4', + Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '3171daccdd89ae5c693399bc0c18db4c381527a1', 'src/third_party/webrtc': - Var('webrtc_git') + '/src.git' + '@' + 'c087d0cce50d2fa75f55e0aeb3f8f0763a80a960', + Var('webrtc_git') + '/src.git' + '@' + '242ca2b5d198d983c756cf49a12df0cd2b366c19', # Wuffs' canonical repository is at github.com/google/wuffs, but we use # Skia's mirror of Wuffs, the same as in upstream Skia's DEPS file. @@ -1975,7 +1951,7 @@ Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'), 'src-internal': { - 'url': Var('chrome_git') + '/chrome/src-internal.git@3146ac33668eafeb7543f352648247a9f259a4a0', + 'url': Var('chrome_git') + '/chrome/src-internal.git@726354df5b77533ca4391ab983468febb0982a9b', 'condition': 'checkout_src_internal', }, @@ -4205,16 +4181,6 @@ '--package=clang-tidy'], }, { - # Grab the libraries and header files of the clang compiler that will be - # used to build Chromium. These can be used to build clang tooling for - # static analysis or codegen. - 'name': 'clang_libs', - 'pattern': '.', - 'condition': 'checkout_clang_libs', - 'action': ['python3', 'src/tools/clang/scripts/update.py', - '--package=clang-libs'], - }, - { # This is also supposed to support the same set of platforms as 'clang' # above. LLVM ToT support isn't provided at the moment. 'name': 'clangd', @@ -4224,17 +4190,6 @@ '--package=clangd'], }, { - # Build experimental in-tree Rust toolchain. Must run after clang_libs or - # clang_tot hook. This should only be run on bots. Syncing clang-libs above - # and passing `--use-final-llvm-build-dir` links rustc against the LLVM libs - # in clang-libs - 'name': 'build_rust', - 'pattern': '.', - 'condition': 'build_chromium_rust_toolchain', - 'action': ['python3', 'src/tools/rust/build_rust.py', - '--use-final-llvm-build-dir'], - }, - { # Should run after the clang hook. Used on mac, as well as for orderfile # generation and size tooling on Android. Used by # dump-static-initializers.py on linux.
diff --git a/WATCHLISTS b/WATCHLISTS index 7343f7c..69064e854 100644 --- a/WATCHLISTS +++ b/WATCHLISTS
@@ -2588,7 +2588,7 @@ 'chrome-os-gardeners+watch@google.com'], 'chromeos_timezone': ['alemate+watch@chromium.org'], 'chromeos_webui': ['alemate+watch@chromium.org'], - 'chromeos_wifi_sync': ['danlee+watch@google.com', + 'chromeos_wifi_sync': ['ajayramamurthy+watch@google.com', 'jonmann+watch@chromium.org', 'stevenjb+watch@chromium.org'], 'chrometto_proto_extensions': ['ddrone+watch@google.com'], @@ -2839,7 +2839,7 @@ 'multi_apps': ['samicolon+watch@google.com', 'isandrk+watch@chromium.org', 'phweiss+watch@chromium.org'], - 'multidevice': ['danlee+watch-multidevice@google.com', + 'multidevice': ['ajayramamurthy+watch-multidevice@google.com', 'hansberry+watch-multidevice@chromium.org', 'joeantonetti+watch-multidevice@google.com', 'jonmann+watch-multidevice@chromium.org'], @@ -2855,7 +2855,7 @@ 'navigation-cc+reviews@chromium.org'], 'nearby': ['cclem+watch-nearby@google.com', 'crisrael+watch-nearby@google.com', - 'danlee+watch-nearby@google.com', + 'ajayramamurthy+watch-nearby@google.com', 'hais+watch-nearby@google.com', 'hansberry+watch-nearby@chromium.org', 'hansenmichael+watch-nearby@google.com', @@ -2929,6 +2929,7 @@ 'iclelland+watch@chromium.org', 'jmedley+watch@chromium.org'], 'phonehub': ['crisrael+watch-phonehub@google.com', + 'ajayramamurthy+watch-phonehub@google.com', 'hansberry+watch-phonehub@chromium.org', 'jonmann+watch-phonehub@chromium.org', 'joeantonetti+watch-phonehub@google.com', @@ -3012,7 +3013,7 @@ 'creis+watch@chromium.org'], 'smartlock': ['bhartmire+watch-smartlock@google.com', 'cclem+watch-smartlock@google.com', - 'danlee+watch-smartlock@google.com', + 'ajayramamurthy+watch-smartlock@google.com', 'hansberry+watch-smartlock@chromium.org', 'jasonrhee+watch-smartlock@google.com'], 'smb': ['cros-enterprise-lax+smbwatch@chromium.org'], @@ -3067,7 +3068,7 @@ 'tests': [], 'tether': ['bhartmire+watch-tether@google.com', 'cclem+watch-tether@google.com', - 'danlee+watch-tether@google.com', + 'ajayramamurthy+watch-tether@google.com', 'hansberry+watch-tether@chromium.org', 'jasonrhee+watch-tether@google.com'], 'text_to_speech': ['dtseng+watch@chromium.org'],
diff --git a/ash/app_list/views/continue_task_view.cc b/ash/app_list/views/continue_task_view.cc index fa80d37244..d95efb9a 100644 --- a/ash/app_list/views/continue_task_view.cc +++ b/ash/app_list/views/continue_task_view.cc
@@ -327,6 +327,7 @@ } ui::SimpleMenuModel* ContinueTaskView::BuildMenuModel() { + DCHECK(result_); context_menu_model_ = std::make_unique<ui::SimpleMenuModel>(this); context_menu_model_->AddItemWithIcon( ContinueTaskCommandId::kOpenResult, @@ -335,12 +336,17 @@ ui::ImageModel::FromVectorIcon(kLaunchIcon, ui::kColorAshSystemUIMenuIcon)); - context_menu_model_->AddItemWithIcon( - ContinueTaskCommandId::kRemoveResult, - l10n_util::GetStringUTF16( - IDS_ASH_LAUNCHER_CONTINUE_SECTION_CONTEXT_MENU_REMOVE), - ui::ImageModel::FromVectorIcon(kRemoveOutlineIcon, - ui::kColorAshSystemUIMenuIcon)); + // We won't create the `Remove suggestion` option for admin templates. + // Reference: b/273800982. + if (result_->result_type() != AppListSearchResultType::kDesksAdminTemplate) { + context_menu_model_->AddItemWithIcon( + ContinueTaskCommandId::kRemoveResult, + l10n_util::GetStringUTF16( + IDS_ASH_LAUNCHER_CONTINUE_SECTION_CONTEXT_MENU_REMOVE), + ui::ImageModel::FromVectorIcon(kRemoveOutlineIcon, + ui::kColorAshSystemUIMenuIcon)); + } + if (Shell::Get()->IsInTabletMode()) { context_menu_model_->AddSeparator(ui::NORMAL_SEPARATOR); context_menu_model_->AddItemWithIcon(
diff --git a/ash/clipboard/views/clipboard_history_delete_button.cc b/ash/clipboard/views/clipboard_history_delete_button.cc index 4c7f384..6caffcb 100644 --- a/ash/clipboard/views/clipboard_history_delete_button.cc +++ b/ash/clipboard/views/clipboard_history_delete_button.cc
@@ -6,11 +6,11 @@ #include "ash/clipboard/clipboard_history_util.h" #include "ash/clipboard/views/clipboard_history_item_view.h" -#include "ash/style/ash_color_id.h" #include "ash/style/style_util.h" #include "base/functional/bind.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/metadata/metadata_impl_macros.h" +#include "ui/chromeos/styles/cros_tokens_color_mappings.h" #include "ui/compositor/layer.h" #include "ui/strings/grit/ui_strings.h" #include "ui/views/animation/ink_drop.h" @@ -27,8 +27,8 @@ base::Unretained(listener)), CloseButton::Type::kSmall, /*icon=*/nullptr, - kColorAshShieldAndBase80Light, - kColorAshButtonIconColorLight), + cros_tokens::kCrosSysSurface, + cros_tokens::kCrosSysSecondary), listener_(listener) { SetID(clipboard_history_util::kDeleteButtonViewID); SetAccessibleName(
diff --git a/ash/style/ash_color_mixer.cc b/ash/style/ash_color_mixer.cc index 1555c97..733233c 100644 --- a/ash/style/ash_color_mixer.cc +++ b/ash/style/ash_color_mixer.cc
@@ -125,7 +125,7 @@ use_dark_color ? ui::ColorTransform(SkColorSetA(SK_ColorWHITE, 0x24)) : ui::ColorTransform(SkColorSetA(SK_ColorBLACK, 0x24)); mixer[kColorAshTextColorPrimary] = {cros_tokens::kColorPrimary}; - mixer[kColorAshTextColorSecondary] = {cros_tokens::kColorSecondary}; + mixer[kColorAshTextColorSecondary] = {cros_tokens::kTextColorSecondary}; mixer[kColorAshTextColorAlert] = {cros_tokens::kColorAlert}; mixer[kColorAshTextColorWarning] = {cros_tokens::kColorWarning}; mixer[kColorAshTextColorPositive] = {cros_tokens::kColorPositive}; @@ -242,6 +242,13 @@ mixer[cros_tokens::kColorSelection] = { cros_tokens::kCrosSysOnPrimaryContainer}; + mixer[cros_tokens::kTextColorSecondaryLight] = { + cros_tokens::kCrosSysOnSurfaceVariantLight}; + mixer[cros_tokens::kTextColorSecondaryDark] = { + cros_tokens::kCrosSysOnSurfaceVariantDark}; + mixer[cros_tokens::kTextColorSecondary] = { + cros_tokens::kCrosSysOnSurfaceVariant}; + mixer[cros_tokens::kBgColor] = {cros_tokens::kCrosSysAppBase}; mixer[cros_tokens::kBgColorElevation1] = {cros_tokens::kCrosSysBaseElevated}; mixer[cros_tokens::kBgColorElevation2Light] = {
diff --git a/ash/style/pagination_view.cc b/ash/style/pagination_view.cc index e4e0d20..373fb7c9 100644 --- a/ash/style/pagination_view.cc +++ b/ash/style/pagination_view.cc
@@ -28,6 +28,9 @@ namespace { +// The minimum number of pages to show the pagination view. +constexpr int kMinNumPages = 2; + // Attributes of arrow buttons. constexpr int kArrowButtonIconSize = 20; constexpr ui::ColorId kArrowButtonColorId = cros_tokens::kCrosSysSecondary; @@ -43,7 +46,7 @@ // Get the width of the indicator container. int GetIndicatorContainerWidth(int total_pages) { - if (total_pages <= 0) { + if (total_pages < kMinNumPages) { return 0; } @@ -322,11 +325,11 @@ indicator_scroll_view_->SetVerticalScrollBarMode( views::ScrollView::ScrollBarMode::kDisabled); - if (model_->total_pages() > 0) { + if (model_->total_pages() >= kMinNumPages) { TotalPagesChanged(0, model_->total_pages()); } - if (model_->is_valid_page(model_->selected_page())) { + if (ShouldShowSelectorDot()) { CreateSelectorDot(); } } @@ -335,6 +338,10 @@ gfx::Size PaginationView::CalculatePreferredSize() const { const int total_pages = model_->total_pages(); + if (total_pages < kMinNumPages) { + return gfx::Size(); + } + // Initialize container size with indicator container size. int container_size = GetIndicatorContainerWidth(total_pages); if (total_pages > kMaxNumVisibleIndicators) { @@ -456,6 +463,11 @@ } } +bool PaginationView::ShouldShowSelectorDot() const { + return model_->total_pages() >= kMinNumPages && + model_->is_valid_page(model_->selected_page()); +} + void PaginationView::CreateSelectorDot() { if (selector_dot_) { return; @@ -545,7 +557,7 @@ void PaginationView::SelectedPageChanged(int old_selected, int new_selected) { // Update selector dot position and arrow buttons visibility. - if (model_->is_valid_page(new_selected)) { + if (ShouldShowSelectorDot()) { if (!selector_dot_) { CreateSelectorDot(); } else { @@ -565,39 +577,46 @@ void PaginationView::TotalPagesChanged(int previous_page_count, int new_page_count) { - previous_page_count = std::max(0, previous_page_count); - new_page_count = std::max(0, new_page_count); - if (previous_page_count == new_page_count) { + const int current_indicator_num = indicator_container_->children().size(); + new_page_count = new_page_count < kMinNumPages ? 0 : new_page_count; + if (current_indicator_num == new_page_count) { return; } - if (previous_page_count < new_page_count) { + if (current_indicator_num < new_page_count) { // Add more indicators at the end of container. - for (int i = previous_page_count; i < new_page_count; i++) { + for (int i = current_indicator_num; i < new_page_count; i++) { indicator_container_->PushIndicator(model_.get()); } // Add arrow buttons if the number of total pages exceeds the visible // maximum. - if (previous_page_count <= kMaxNumVisibleIndicators && + if (current_indicator_num <= kMaxNumVisibleIndicators && new_page_count > kMaxNumVisibleIndicators) { CreateArrowButtons(); } + + // Create selector dot if the number of total pages exceeds the minimum + // number of pages. + if (new_page_count >= kMinNumPages && !selector_dot_) { + CreateSelectorDot(); + } } else { // Remove indicators from the end of the container. - for (int i = previous_page_count; i > new_page_count; i--) { + for (int i = current_indicator_num; i > new_page_count; i--) { indicator_container_->PopIndicator(); } // Remove arrow buttons if the number of total pages does not exceed the // visible maximum. - if (previous_page_count > kMaxNumVisibleIndicators && + if (current_indicator_num > kMaxNumVisibleIndicators && new_page_count <= kMaxNumVisibleIndicators) { RemoveArrowButtons(); } - // Remove the selector dot if there is no pages. - if (new_page_count == 0) { + // Remove the selector dot if the number of pages is less than the minimum + // number of pages. + if (new_page_count < kMinNumPages && selector_dot_) { RemoveSelectorDot(); } }
diff --git a/ash/style/pagination_view.h b/ash/style/pagination_view.h index 2645ba4..ea9f19d4 100644 --- a/ash/style/pagination_view.h +++ b/ash/style/pagination_view.h
@@ -75,6 +75,7 @@ void OnArrowButtonPressed(bool forward, const ui::Event& event); void MaybeSetUpScroll(); + bool ShouldShowSelectorDot() const; void CreateSelectorDot(); void RemoveSelectorDot(); void UpdateSelectorDot();
diff --git a/ash/style/pill_button.h b/ash/style/pill_button.h index bbb1a71..ba144e8 100644 --- a/ash/style/pill_button.h +++ b/ash/style/pill_button.h
@@ -163,7 +163,7 @@ // InstallRoundRectHighlightPathGenerator for the button only if // `rounded_highlight_path` is true. This is special handlings for buttons // inside the old notifications UI, might can be removed once - // `kNotificationsRefresh` is fully launched. + // `kNotificationsRefresh` is fully launched. See b/257291597 explicit PillButton( PressedCallback callback = PressedCallback(), const std::u16string& text = std::u16string(),
diff --git a/ash/system/message_center/message_center_style.h b/ash/system/message_center/message_center_style.h index c330d91..e656790 100644 --- a/ash/system/message_center/message_center_style.h +++ b/ash/system/message_center/message_center_style.h
@@ -19,9 +19,7 @@ // TODO(crbug.com/1309551): Get the colors from AshColorProvider once // notification supports dark/light mode. -constexpr SkColor kCountLabelColor = gfx::kGoogleGrey900; constexpr SkColor kSeparatorColor = SkColorSetA(SK_ColorBLACK, 0x24); // 14% -constexpr SkColor kNotificationBackgroundColor = SK_ColorWHITE; constexpr SkColor kUnifiedMenuButtonColorActive = SkColorSetRGB(0x25, 0x81, 0xDF); constexpr SkColor kInkRippleColor = SK_ColorBLACK;
diff --git a/ash/system/notification_center/notification_center_view.cc b/ash/system/notification_center/notification_center_view.cc index 363dec6..734ba7f 100644 --- a/ash/system/notification_center/notification_center_view.cc +++ b/ash/system/notification_center/notification_center_view.cc
@@ -163,11 +163,9 @@ return; } - int max_scroller_height = max_height; - if (notification_bar_->GetVisible()) { - max_scroller_height -= notification_bar_->GetPreferredSize().height() + - 2 * kMessageCenterPadding; - } + int max_scroller_height = max_height - + notification_bar_->GetPreferredSize().height() - + 2 * kMessageCenterPadding; scroller_->ClipHeightTo(0, max_scroller_height); } @@ -191,12 +189,6 @@ return; } - // Do not collapse the message center if notification bar is not visible. - // i.e. there is only one notification. - if (!notification_bar_->GetVisible()) { - return; - } - collapsed_ = true; if (animate) { StartCollapseAnimation(); @@ -223,21 +215,12 @@ message_center_bubble_->ExpandMessageCenter(); } -bool NotificationCenterView::IsNotificationBarVisible() const { - return notification_bar_->GetVisible(); -} - bool NotificationCenterView::IsScrollBarVisible() const { return scroll_bar_->GetVisible(); } void NotificationCenterView::OnNotificationSlidOut() { - if (notification_bar_->GetVisible()) { - UpdateNotificationBar(); - if (!notification_bar_->GetVisible()) { - StartHideStackingBarAnimation(); - } - } + UpdateNotificationBar(); if (!notification_list_view_->GetTotalNotificationCount()) { StartCollapseAnimation(); @@ -530,10 +513,8 @@ return notification_list_view_->GetAllNotificationIds(); } - const int notification_bar_height = - IsNotificationBarVisible() ? kStackedNotificationBarHeight : 0; const int y_offset_above = scroller_->GetVisibleRect().y() - scroller_->y() + - notification_bar_height; + kStackedNotificationBarHeight; auto above_id_list = notification_list_view_->GetNotificationIdsAboveY(y_offset_above); const int y_offset_below =
diff --git a/ash/system/notification_center/notification_center_view.h b/ash/system/notification_center/notification_center_view.h index c9a0235..c6ad266 100644 --- a/ash/system/notification_center/notification_center_view.h +++ b/ash/system/notification_center/notification_center_view.h
@@ -139,9 +139,6 @@ // Called when user clicks the see all notifications button. void ExpandMessageCenter(); - // Returns true if the notification bar is visible. - bool IsNotificationBarVisible() const; - // Returns true if the scroll bar is visible. bool IsScrollBarVisible() const;
diff --git a/ash/system/notification_center/stacked_notification_bar.cc b/ash/system/notification_center/stacked_notification_bar.cc index a75e5d3f..056cb80 100644 --- a/ash/system/notification_center/stacked_notification_bar.cc +++ b/ash/system/notification_center/stacked_notification_bar.cc
@@ -23,7 +23,6 @@ #include "ui/compositor/layer_animation_sequence.h" #include "ui/compositor/layer_animator.h" #include "ui/compositor/scoped_layer_animation_settings.h" -#include "ui/gfx/canvas.h" #include "ui/gfx/interpolated_transform.h" #include "ui/message_center/message_center.h" #include "ui/message_center/public/cpp/message_center_constants.h" @@ -44,23 +43,17 @@ StackingBarLabelButton(PressedCallback callback, const std::u16string& text, NotificationCenterView* notification_center_view) - : PillButton( - std::move(callback), - text, - PillButton::Type::kAccentFloatingWithoutIcon, - /*icon=*/nullptr, - kNotificationPillButtonHorizontalSpacing, - /*use_light_colors=*/!features::IsNotificationsRefreshEnabled(), - /*rounded_highlight_path=*/ - features::IsNotificationsRefreshEnabled()), + : PillButton(std::move(callback), + text, + PillButton::Type::kAccentFloatingWithoutIcon, + /*icon=*/nullptr, + kNotificationPillButtonHorizontalSpacing, + /*use_light_colors=*/false, + /*rounded_highlight_path=*/true), notification_center_view_(notification_center_view) { - const SkColor bg_color = - features::IsNotificationsRefreshEnabled() - ? gfx::kPlaceholderColor - : message_center_style::kUnifiedMenuButtonColorActive; StyleUtil::SetUpInkDropForButton(this, gfx::Insets(), /*highlight_on_hover=*/true, - /*highlight_on_focus=*/true, bg_color); + /*highlight_on_focus=*/true); } StackingBarLabelButton(const StackingBarLabelButton&) = delete; @@ -102,8 +95,6 @@ void OnThemeChanged() override { views::ImageView::OnThemeChanged(); - const auto* color_provider = GetColorProvider(); - auto* notification = message_center::MessageCenter::Get()->FindVisibleNotificationById(id_); // The notification icon could be waiting to be cleaned up after the @@ -111,22 +102,11 @@ if (!notification) return; - SkColor accent_color; - gfx::Image masked_small_icon; - if (features::IsNotificationsRefreshEnabled()) { - accent_color = AshColorProvider::Get()->GetContentLayerColor( - AshColorProvider::ContentLayerType::kIconColorPrimary); - masked_small_icon = notification->GenerateMaskedSmallIcon( - kStackedNotificationIconSize, accent_color, SK_ColorTRANSPARENT, - accent_color); - } else { - accent_color = - color_provider->GetColor(ui::kColorNotificationHeaderForeground); - masked_small_icon = notification->GenerateMaskedSmallIcon( - kStackedNotificationIconSize, accent_color, - color_provider->GetColor(ui::kColorNotificationIconBackground), - color_provider->GetColor(ui::kColorNotificationIconForeground)); - } + SkColor accent_color = AshColorProvider::Get()->GetContentLayerColor( + AshColorProvider::ContentLayerType::kIconColorPrimary); + gfx::Image masked_small_icon = notification->GenerateMaskedSmallIcon( + kStackedNotificationIconSize, accent_color, SK_ColorTRANSPARENT, + accent_color); if (masked_small_icon.IsEmpty()) { SetImage(gfx::CreateVectorIcon(message_center::kProductIcon, @@ -261,10 +241,7 @@ notification_center_view))), layout_manager_(SetLayoutManager(std::make_unique<views::BoxLayout>( views::BoxLayout::Orientation::kHorizontal, - features::IsNotificationsRefreshEnabled() ? kNotificationBarPadding - : gfx::Insets()))) { - UpdateVisibility(); - + kNotificationBarPadding))) { layout_manager_->set_cross_axis_alignment( views::BoxLayout::CrossAxisAlignment::kStretch); @@ -276,11 +253,8 @@ message_center::MessageCenter::Get()->AddObserver(this); - SkColor label_color = - features::IsNotificationsRefreshEnabled() - ? AshColorProvider::Get()->GetContentLayerColor( - AshColorProvider::ContentLayerType::kIconColorPrimary) - : message_center_style::kCountLabelColor; + SkColor label_color = AshColorProvider::Get()->GetContentLayerColor( + AshColorProvider::ContentLayerType::kIconColorPrimary); count_label_->SetEnabledColor(label_color); count_label_->SetFontList(views::Label::GetDefaultFontList().Derive( 1, gfx::Font::NORMAL, gfx::Font::Weight::MEDIUM)); @@ -291,9 +265,6 @@ IDS_ASH_MESSAGE_CENTER_CLEAR_ALL_BUTTON_TOOLTIP)); expand_all_button_->SetVisible(false); - - if (!features::IsNotificationsRefreshEnabled()) - SetPaintToLayer(); } StackedNotificationBar::~StackedNotificationBar() { @@ -318,7 +289,6 @@ pinned_notification_count_ = pinned_notification_count; UpdateStackedNotifications(stacked_notifications); - UpdateVisibility(); const int unpinned_count = total_notification_count_ - pinned_notification_count_; @@ -336,21 +306,17 @@ void StackedNotificationBar::SetAnimationState( NotificationCenterAnimationState animation_state) { animation_state_ = animation_state; - UpdateVisibility(); } void StackedNotificationBar::SetCollapsed() { - if (features::IsNotificationsRefreshEnabled()) - layout_manager_->set_inside_border_insets(gfx::Insets()); + layout_manager_->set_inside_border_insets(gfx::Insets()); clear_all_button_->SetVisible(false); expand_all_button_->SetVisible(true); - UpdateVisibility(); } void StackedNotificationBar::SetExpanded() { - if (features::IsNotificationsRefreshEnabled()) - layout_manager_->set_inside_border_insets(kNotificationBarPadding); + layout_manager_->set_inside_border_insets(kNotificationBarPadding); clear_all_button_->SetVisible(true); expand_all_button_->SetVisible(false); @@ -507,72 +473,10 @@ } } -void StackedNotificationBar::OnPaint(gfx::Canvas* canvas) { - // We don't need the custom border below in the new message center UI, since - // the clear all button does not interfere with the border anymore. Also, the - // message center bubble will have a highlight border that covers this view. - if (features::IsNotificationsRefreshEnabled()) - return; - - cc::PaintFlags flags; - flags.setColor(message_center_style::kNotificationBackgroundColor); - flags.setStyle(cc::PaintFlags::kFill_Style); - flags.setAntiAlias(true); - - gfx::Rect bounds = GetLocalBounds(); - canvas->DrawRect(bounds, flags); - - // We draw a border here than use a views::Border so the ink drop highlight - // of the clear all button overlays the border. - if (clear_all_button_->GetVisible()) { - canvas->DrawSharpLine( - gfx::PointF(bounds.bottom_left() - gfx::Vector2d(0, 1)), - gfx::PointF(bounds.bottom_right() - gfx::Vector2d(0, 1)), - message_center_style::kSeparatorColor); - } -} - const char* StackedNotificationBar::GetClassName() const { return "StackedNotificationBar"; } -void StackedNotificationBar::UpdateVisibility() { - // In the refreshed message center view the notification bar is always - // visible. - if (features::IsNotificationsRefreshEnabled()) { - if (!GetVisible()) - SetVisible(true); - return; - } - - int unpinned_count = total_notification_count_ - pinned_notification_count_; - - // In expanded state, clear all button should be visible when (rule is subject - // to change): - // 1. There are more than one notification. - // 2. There is at least one unpinned notification - const bool show_clear_all = - total_notification_count_ > 1 && unpinned_count >= 1; - if (!expand_all_button_->GetVisible()) - clear_all_button_->SetVisible(show_clear_all); - - switch (animation_state_) { - case NotificationCenterAnimationState::IDLE: - SetVisible( - (stacked_notification_count_ && total_notification_count_ > 1) || - show_clear_all || expand_all_button_->GetVisible()); - break; - case NotificationCenterAnimationState::HIDE_STACKING_BAR: - SetVisible(true); - break; - case NotificationCenterAnimationState::COLLAPSE: - SetVisible( - (stacked_notification_count_ && total_notification_count_ > 1) || - show_clear_all || expand_all_button_->GetVisible()); - break; - } -} - void StackedNotificationBar::OnNotificationAdded(const std::string& id) { // Reset the stacked icons bar if a notification is added since we don't // know the position where it may have been added.
diff --git a/ash/system/notification_center/stacked_notification_bar.h b/ash/system/notification_center/stacked_notification_bar.h index 140c511..9cd0394 100644 --- a/ash/system/notification_center/stacked_notification_bar.h +++ b/ash/system/notification_center/stacked_notification_bar.h
@@ -52,7 +52,6 @@ void SetExpanded(); // views::View: - void OnPaint(gfx::Canvas* canvas) override; const char* GetClassName() const override; // message_center::MessageCenterObserver: @@ -77,9 +76,6 @@ // notification id. const StackedNotificationBarIcon* GetIconFromId(const std::string& id) const; - // Set visibility based on number of stacked notifications or animation state. - void UpdateVisibility(); - // Add a stacked notification icon to the front or back of the row. void AddNotificationIcon(message_center::Notification* notification, bool at_front);
diff --git a/ash/system/privacy/privacy_indicators_controller.cc b/ash/system/privacy/privacy_indicators_controller.cc index 97fa23e..a9cdfeba 100644 --- a/ash/system/privacy/privacy_indicators_controller.cc +++ b/ash/system/privacy/privacy_indicators_controller.cc
@@ -19,6 +19,8 @@ #include "ash/system/unified/unified_system_tray.h" #include "base/functional/callback_forward.h" #include "base/metrics/histogram_functions.h" +#include "chromeos/ash/components/audio/cras_audio_handler.h" +#include "media/capture/video/chromeos/camera_hal_dispatcher_impl.h" #include "ui/base/l10n/l10n_util.h" #include "ui/gfx/vector_icon_types.h" #include "ui/message_center/message_center.h" @@ -159,18 +161,44 @@ } } -// Updates the access status of `app_id` for the given `access_set`. -void UpdateAccessStatus(const std::string& app_id, - bool is_accessed, - base::flat_set<std::string>& access_set) { - if (access_set.contains(app_id) == is_accessed) { +// Updates the access status of `app_id` for the given `access_map`. +void UpdateAccessStatus( + const std::string& app_id, + bool is_accessed, + std::map<std::string, ash::PrivacyIndicatorsAppInfo>& access_map, + absl::optional<std::u16string> app_name, + scoped_refptr<ash::PrivacyIndicatorsNotificationDelegate> delegate) { + if (access_map.contains(app_id) == is_accessed) { return; } if (is_accessed) { - access_set.insert(app_id); + ash::PrivacyIndicatorsAppInfo info; + info.app_name = app_name; + info.delegate = delegate; + access_map[app_id] = std::move(info); } else { - access_set.erase(app_id); + access_map.erase(app_id); + } +} + +void UpdatePrivacyIndicatorsVisibility() { + DCHECK(Shell::HasInstance()); + for (auto* root_window_controller : + Shell::Get()->GetAllRootWindowControllers()) { + CHECK(root_window_controller); + auto* status_area_widget = root_window_controller->GetStatusAreaWidget(); + CHECK(status_area_widget); + + auto* privacy_indicators_view = + features::IsQsRevampEnabled() + ? status_area_widget->notification_center_tray() + ->privacy_indicators_view() + : status_area_widget->unified_system_tray() + ->privacy_indicators_view(); + CHECK(privacy_indicators_view); + + privacy_indicators_view->UpdateVisibility(); } } @@ -234,14 +262,26 @@ return kPrivacyIndicatorsNotificationIdPrefix + app_id; } +PrivacyIndicatorsAppInfo::PrivacyIndicatorsAppInfo() = default; + +PrivacyIndicatorsAppInfo::~PrivacyIndicatorsAppInfo() = default; + PrivacyIndicatorsController::PrivacyIndicatorsController() { DCHECK(!g_controller_instance); g_controller_instance = this; + + CrasAudioHandler::Get()->AddAudioObserver(this); + media::CameraHalDispatcherImpl::GetInstance()->AddCameraPrivacySwitchObserver( + this); } PrivacyIndicatorsController::~PrivacyIndicatorsController() { DCHECK_EQ(this, g_controller_instance); g_controller_instance = nullptr; + + CrasAudioHandler::Get()->RemoveAudioObserver(this); + media::CameraHalDispatcherImpl::GetInstance() + ->RemoveCameraPrivacySwitchObserver(this); } // static @@ -262,10 +302,15 @@ const bool was_microphone_in_use = IsMicrophoneUsed(); UpdateAccessStatus(app_id, /*is_accessed=*/is_camera_used, - /*access_set=*/apps_using_camera_); + /*access_map=*/apps_using_camera_, app_name, delegate); UpdateAccessStatus(app_id, /*is_accessed=*/is_microphone_used, - /*access_set=*/apps_using_microphone_); + /*access_map=*/apps_using_microphone_, app_name, delegate); + + is_camera_used = is_camera_used && !camera_muted_by_hardware_switch_ && + !camera_muted_by_software_switch_; + is_microphone_used = + is_microphone_used && !CrasAudioHandler::Get()->IsInputMuted(); ModifyPrivacyIndicatorsNotification(app_id, app_name, is_camera_used, is_microphone_used, delegate); @@ -275,12 +320,68 @@ base::UmaHistogramEnumeration("Ash.PrivacyIndicators.Source", source); } +void PrivacyIndicatorsController::OnCameraHWPrivacySwitchStateChanged( + const std::string& device_id, + cros::mojom::CameraPrivacySwitchState state) { + camera_muted_by_hardware_switch_ = + state == cros::mojom::CameraPrivacySwitchState::ON; + + UpdateForCameraMuteStateChanged(); +} + +void PrivacyIndicatorsController::OnCameraSWPrivacySwitchStateChanged( + cros::mojom::CameraPrivacySwitchState state) { + camera_muted_by_software_switch_ = + state == cros::mojom::CameraPrivacySwitchState::ON; + + UpdateForCameraMuteStateChanged(); +} + +void PrivacyIndicatorsController::OnInputMuteChanged( + bool mute_on, + CrasAudioHandler::InputMuteChangeMethod method) { + // Iterate through all the apps that are tracked as using the microphone, then + // modify the notification according to the mute state of the microphone. + for (const auto& [app_id, app_info] : apps_using_microphone_) { + // Retrieve camera usage state for each individual app to update in the + // notification. + bool is_camera_used = apps_using_camera_.contains(app_id) && + !camera_muted_by_hardware_switch_ && + !camera_muted_by_software_switch_; + ModifyPrivacyIndicatorsNotification( + app_id, app_info.app_name, is_camera_used, + /*is_microphone_used=*/!mute_on, app_info.delegate); + } + + UpdatePrivacyIndicatorsVisibility(); +} + +void PrivacyIndicatorsController::UpdateForCameraMuteStateChanged() { + // Iterate through all the apps that are tracked as using the camera, then + // modify the notification according to the mute state of camera. + for (const auto& [app_id, app_info] : apps_using_camera_) { + // Retrieve microphone usage state for each individual app to update in the + // notification. + bool is_camera_used = + !camera_muted_by_hardware_switch_ && !camera_muted_by_software_switch_; + bool is_microphone_used = apps_using_microphone_.contains(app_id) && + !CrasAudioHandler::Get()->IsInputMuted(); + ModifyPrivacyIndicatorsNotification(app_id, app_info.app_name, + is_camera_used, is_microphone_used, + app_info.delegate); + } + + UpdatePrivacyIndicatorsVisibility(); +} + bool PrivacyIndicatorsController::IsCameraUsed() const { - return !apps_using_camera_.empty(); + return !apps_using_camera_.empty() && !camera_muted_by_hardware_switch_ && + !camera_muted_by_software_switch_; } bool PrivacyIndicatorsController::IsMicrophoneUsed() const { - return !apps_using_microphone_.empty(); + return !apps_using_microphone_.empty() && + !CrasAudioHandler::Get()->IsInputMuted(); } void UpdatePrivacyIndicatorsScreenShareStatus(bool is_screen_sharing) {
diff --git a/ash/system/privacy/privacy_indicators_controller.h b/ash/system/privacy/privacy_indicators_controller.h index 92efa4f..ee47f2c 100644 --- a/ash/system/privacy/privacy_indicators_controller.h +++ b/ash/system/privacy/privacy_indicators_controller.h
@@ -8,8 +8,9 @@ #include <string> #include "ash/ash_export.h" -#include "base/containers/flat_set.h" #include "base/functional/callback_forward.h" +#include "chromeos/ash/components/audio/cras_audio_handler.h" +#include "media/capture/video/chromeos/camera_hal_dispatcher_impl.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/message_center/public/cpp/notification_delegate.h" @@ -84,10 +85,24 @@ std::string ASH_EXPORT GetPrivacyIndicatorsNotificationId(const std::string& app_id); +// Struct that stores info of an app that is being tracked by privacy +// indicators. +struct PrivacyIndicatorsAppInfo { + PrivacyIndicatorsAppInfo(); + PrivacyIndicatorsAppInfo(PrivacyIndicatorsAppInfo&&); + PrivacyIndicatorsAppInfo& operator=(PrivacyIndicatorsAppInfo&&) = default; + ~PrivacyIndicatorsAppInfo(); + + absl::optional<std::u16string> app_name; + scoped_refptr<PrivacyIndicatorsNotificationDelegate> delegate; +}; + // A controller that manages the logic of modifying the tray item privacy // indicator dot and the privacy indicators notification when camera/microphone // access state changes. -class ASH_EXPORT PrivacyIndicatorsController { +class ASH_EXPORT PrivacyIndicatorsController + : public CrasAudioHandler::AudioObserver, + public media::CameraPrivacySwitchObserver { public: PrivacyIndicatorsController(); @@ -95,7 +110,7 @@ PrivacyIndicatorsController& operator=(const PrivacyIndicatorsController&) = delete; - ~PrivacyIndicatorsController(); + ~PrivacyIndicatorsController() override; // Returns the singleton instance. static PrivacyIndicatorsController* Get(); @@ -117,22 +132,48 @@ scoped_refptr<PrivacyIndicatorsNotificationDelegate> delegate, PrivacyIndicatorsSource source); + // media::CameraPrivacySwitchObserver: + void OnCameraHWPrivacySwitchStateChanged( + const std::string& device_id, + cros::mojom::CameraPrivacySwitchState state) override; + void OnCameraSWPrivacySwitchStateChanged( + cros::mojom::CameraPrivacySwitchState state) override; + + // CrasAudioHandler::AudioObserver: + void OnInputMuteChanged( + bool mute_on, + CrasAudioHandler::InputMuteChangeMethod method) override; + // Specifies whether camera/microphone is in use by at least one app. bool IsCameraUsed() const; bool IsMicrophoneUsed() const; - base::flat_set<std::string> apps_using_camera() const { + const std::map<std::string, PrivacyIndicatorsAppInfo>& apps_using_camera() + const { return apps_using_camera_; } - base::flat_set<std::string> apps_using_microphone() const { + const std::map<std::string, PrivacyIndicatorsAppInfo>& apps_using_microphone() + const { return apps_using_microphone_; } private: - // Stores the app_id(s) that are currently accessing camera/microphone. - base::flat_set<std::string> apps_using_camera_; - base::flat_set<std::string> apps_using_microphone_; + // Updates privacy indicators after camera mute state changed. + void UpdateForCameraMuteStateChanged(); + + // Stores the app(s) info that are currently accessing camera/microphone. The + // key represents the app id. + std::map<std::string, PrivacyIndicatorsAppInfo> apps_using_camera_; + std::map<std::string, PrivacyIndicatorsAppInfo> apps_using_microphone_; + + // This keeps track of the current Camera Privacy Switch state. + // Updated via `OnCameraHWPrivacySwitchStateChanged()` and + // `OnCameraSWPrivacySwitchStateChanged()` We use these variables since + // fetching this directly through `media::CameraHalDispatcherImpl` would + // otherwise need an asynchronous call. + bool camera_muted_by_hardware_switch_ = false; + bool camera_muted_by_software_switch_ = false; }; // Update `PrivacyIndicatorsTrayItemView` screen share status across all status
diff --git a/ash/system/privacy/privacy_indicators_controller_unittest.cc b/ash/system/privacy/privacy_indicators_controller_unittest.cc index efa6f12..15a71e4 100644 --- a/ash/system/privacy/privacy_indicators_controller_unittest.cc +++ b/ash/system/privacy/privacy_indicators_controller_unittest.cc
@@ -27,6 +27,7 @@ #include "base/memory/weak_ptr.h" #include "base/test/metrics/histogram_tester.h" #include "base/test/scoped_feature_list.h" +#include "chromeos/ash/components/audio/cras_audio_handler.h" #include "ui/base/l10n/l10n_util.h" #include "ui/compositor/scoped_animation_duration_scale_mode.h" #include "ui/events/test/event_generator.h" @@ -387,6 +388,280 @@ PrivacyIndicatorsSource::kLinuxVm, 1); } +TEST_F(PrivacyIndicatorsControllerTest, CameraDisabledWithOneApp) { + auto* controller = PrivacyIndicatorsController::Get(); + + std::string app_id = "test_app_id"; + scoped_refptr<TestDelegate> delegate = base::MakeRefCounted<TestDelegate>(); + controller->UpdatePrivacyIndicators(app_id, u"test_app_name", + /*is_camera_used=*/true, + /*is_microphone_used=*/false, delegate, + PrivacyIndicatorsSource::kApps); + + std::string notification_id = GetPrivacyIndicatorsNotificationId(app_id); + ASSERT_TRUE(message_center::MessageCenter::Get()->FindNotificationById( + notification_id)); + ASSERT_TRUE(GetPrimaryDisplayPrivacyIndicatorsView()->GetVisible()); + + // Camera is in use, but if the camera is being hardware muted, the + // notification and indicator view should not show. + controller->OnCameraHWPrivacySwitchStateChanged( + "test_device_id", cros::mojom::CameraPrivacySwitchState::ON); + EXPECT_FALSE(message_center::MessageCenter::Get()->FindNotificationById( + notification_id)); + EXPECT_FALSE(GetPrimaryDisplayPrivacyIndicatorsView()->GetVisible()); + + // Flip back the switch. Indicators should show again. + controller->OnCameraHWPrivacySwitchStateChanged( + "test_device_id", cros::mojom::CameraPrivacySwitchState::OFF); + EXPECT_TRUE(message_center::MessageCenter::Get()->FindNotificationById( + notification_id)); + EXPECT_TRUE(GetPrimaryDisplayPrivacyIndicatorsView()->GetVisible()); + + // Camera is in use, but if the camera is being software muted, the + // notification and indicator view should not show. + controller->OnCameraSWPrivacySwitchStateChanged( + cros::mojom::CameraPrivacySwitchState::ON); + EXPECT_FALSE(message_center::MessageCenter::Get()->FindNotificationById( + notification_id)); + EXPECT_FALSE(GetPrimaryDisplayPrivacyIndicatorsView()->GetVisible()); + // Flip back the switch. Indicators should show again. + controller->OnCameraSWPrivacySwitchStateChanged( + cros::mojom::CameraPrivacySwitchState::OFF); + EXPECT_TRUE(message_center::MessageCenter::Get()->FindNotificationById( + notification_id)); + EXPECT_TRUE(GetPrimaryDisplayPrivacyIndicatorsView()->GetVisible()); + + // If both camera and microphone is in use, but the camera is muted. The + // notification content (i.e. the title) should reflect that only mic is being + // in used. + controller->UpdatePrivacyIndicators(app_id, u"test_app_name", + /*is_camera_used=*/true, + /*is_microphone_used=*/true, delegate, + PrivacyIndicatorsSource::kApps); + controller->OnCameraSWPrivacySwitchStateChanged( + cros::mojom::CameraPrivacySwitchState::ON); + auto* notification = + message_center::MessageCenter::Get()->FindNotificationById( + notification_id); + EXPECT_TRUE(notification); + EXPECT_EQ(l10n_util::GetStringUTF16(IDS_PRIVACY_NOTIFICATION_TITLE_MIC), + notification->title()); + + // Flip back. + controller->OnCameraSWPrivacySwitchStateChanged( + cros::mojom::CameraPrivacySwitchState::OFF); + notification = message_center::MessageCenter::Get()->FindNotificationById( + notification_id); + EXPECT_TRUE(notification); + EXPECT_EQ( + l10n_util::GetStringUTF16(IDS_PRIVACY_NOTIFICATION_TITLE_CAMERA_AND_MIC), + notification->title()); +} + +TEST_F(PrivacyIndicatorsControllerTest, MicrophoneDisabledWithOneApp) { + auto* controller = PrivacyIndicatorsController::Get(); + + std::string app_id = "test_app_id"; + scoped_refptr<TestDelegate> delegate = base::MakeRefCounted<TestDelegate>(); + controller->UpdatePrivacyIndicators(app_id, u"test_app_name", + /*is_camera_used=*/false, + /*is_microphone_used=*/true, delegate, + PrivacyIndicatorsSource::kApps); + + std::string notification_id = GetPrivacyIndicatorsNotificationId(app_id); + ASSERT_TRUE(message_center::MessageCenter::Get()->FindNotificationById( + notification_id)); + ASSERT_TRUE(GetPrimaryDisplayPrivacyIndicatorsView()->GetVisible()); + + // Microphone is in use, but if the microphone is being muted, the + // notification and indicator view should not show. + CrasAudioHandler::Get()->SetInputMute( + /*mute_on=*/true, + CrasAudioHandler::InputMuteChangeMethod::kKeyboardButton); + EXPECT_FALSE(message_center::MessageCenter::Get()->FindNotificationById( + notification_id)); + EXPECT_FALSE(GetPrimaryDisplayPrivacyIndicatorsView()->GetVisible()); + + // Flip back the switch. Indicators should show again. + CrasAudioHandler::Get()->SetInputMute( + /*mute_on=*/false, + CrasAudioHandler::InputMuteChangeMethod::kKeyboardButton); + EXPECT_TRUE(message_center::MessageCenter::Get()->FindNotificationById( + notification_id)); + EXPECT_TRUE(GetPrimaryDisplayPrivacyIndicatorsView()->GetVisible()); + + // If both camera and microphone is in use, but the camera is muted. The + // notification content (i.e. the title) should reflect that only mic is being + // in used. + controller->UpdatePrivacyIndicators(app_id, u"test_app_name", + /*is_camera_used=*/true, + /*is_microphone_used=*/true, delegate, + PrivacyIndicatorsSource::kApps); + CrasAudioHandler::Get()->SetInputMute( + /*mute_on=*/true, + CrasAudioHandler::InputMuteChangeMethod::kKeyboardButton); + auto* notification = + message_center::MessageCenter::Get()->FindNotificationById( + notification_id); + EXPECT_TRUE(notification); + EXPECT_EQ(l10n_util::GetStringUTF16(IDS_PRIVACY_NOTIFICATION_TITLE_CAMERA), + notification->title()); + + // Flip back. + CrasAudioHandler::Get()->SetInputMute( + /*mute_on=*/false, + CrasAudioHandler::InputMuteChangeMethod::kKeyboardButton); + notification = message_center::MessageCenter::Get()->FindNotificationById( + notification_id); + EXPECT_TRUE(notification); + EXPECT_EQ( + l10n_util::GetStringUTF16(IDS_PRIVACY_NOTIFICATION_TITLE_CAMERA_AND_MIC), + notification->title()); +} + +// When both microphone and camera is disabled, no privacy indicators should +// show for camera/microphone usage. +TEST_F(PrivacyIndicatorsControllerTest, CameraAndMicrophoneDisabledWithOneApp) { + auto* controller = PrivacyIndicatorsController::Get(); + + std::string app_id = "test_app_id"; + scoped_refptr<TestDelegate> delegate = base::MakeRefCounted<TestDelegate>(); + controller->UpdatePrivacyIndicators(app_id, u"test_app_name", + /*is_camera_used=*/true, + /*is_microphone_used=*/true, delegate, + PrivacyIndicatorsSource::kApps); + + std::string notification_id = GetPrivacyIndicatorsNotificationId(app_id); + ASSERT_TRUE(message_center::MessageCenter::Get()->FindNotificationById( + notification_id)); + ASSERT_TRUE(GetPrimaryDisplayPrivacyIndicatorsView()->GetVisible()); + + CrasAudioHandler::Get()->SetInputMute( + /*mute_on=*/true, + CrasAudioHandler::InputMuteChangeMethod::kKeyboardButton); + controller->OnCameraSWPrivacySwitchStateChanged( + cros::mojom::CameraPrivacySwitchState::ON); + + EXPECT_FALSE(message_center::MessageCenter::Get()->FindNotificationById( + notification_id)); + EXPECT_FALSE(GetPrimaryDisplayPrivacyIndicatorsView()->GetVisible()); + + CrasAudioHandler::Get()->SetInputMute( + /*mute_on=*/true, + CrasAudioHandler::InputMuteChangeMethod::kKeyboardButton); + controller->OnCameraHWPrivacySwitchStateChanged( + "test_device_id", cros::mojom::CameraPrivacySwitchState::ON); + + EXPECT_FALSE(message_center::MessageCenter::Get()->FindNotificationById( + notification_id)); + EXPECT_FALSE(GetPrimaryDisplayPrivacyIndicatorsView()->GetVisible()); +} + +TEST_F(PrivacyIndicatorsControllerTest, CameraDisabledWithMultipleApps) { + auto* controller = PrivacyIndicatorsController::Get(); + + std::string app_id1 = "test_app_id1"; + std::string app_id2 = "test_app_id2"; + std::string app_id3 = "test_app_id3"; + scoped_refptr<TestDelegate> delegate = base::MakeRefCounted<TestDelegate>(); + controller->UpdatePrivacyIndicators(app_id1, u"test_app_name", + /*is_camera_used=*/true, + /*is_microphone_used=*/false, delegate, + PrivacyIndicatorsSource::kApps); + controller->UpdatePrivacyIndicators(app_id2, u"test_app_name", + /*is_camera_used=*/true, + /*is_microphone_used=*/false, delegate, + PrivacyIndicatorsSource::kApps); + controller->UpdatePrivacyIndicators(app_id3, u"test_app_name", + /*is_camera_used=*/false, + /*is_microphone_used=*/true, delegate, + PrivacyIndicatorsSource::kApps); + + std::string notification_id1 = GetPrivacyIndicatorsNotificationId(app_id1); + std::string notification_id2 = GetPrivacyIndicatorsNotificationId(app_id2); + std::string notification_id3 = GetPrivacyIndicatorsNotificationId(app_id3); + ASSERT_TRUE(message_center::MessageCenter::Get()->FindNotificationById( + notification_id1)); + ASSERT_TRUE(message_center::MessageCenter::Get()->FindNotificationById( + notification_id2)); + ASSERT_TRUE(message_center::MessageCenter::Get()->FindNotificationById( + notification_id3)); + + controller->OnCameraSWPrivacySwitchStateChanged( + cros::mojom::CameraPrivacySwitchState::ON); + EXPECT_FALSE(message_center::MessageCenter::Get()->FindNotificationById( + notification_id1)); + EXPECT_FALSE(message_center::MessageCenter::Get()->FindNotificationById( + notification_id2)); + + // The app that uses microphone should not be affected. + EXPECT_TRUE(message_center::MessageCenter::Get()->FindNotificationById( + notification_id3)); + + // When flip back, all old notification should be re-created. + controller->OnCameraSWPrivacySwitchStateChanged( + cros::mojom::CameraPrivacySwitchState::OFF); + + EXPECT_TRUE(message_center::MessageCenter::Get()->FindNotificationById( + notification_id1)); + EXPECT_TRUE(message_center::MessageCenter::Get()->FindNotificationById( + notification_id2)); +} + +TEST_F(PrivacyIndicatorsControllerTest, MicrophoneDisabledWithMultipleApps) { + auto* controller = PrivacyIndicatorsController::Get(); + + std::string app_id1 = "test_app_id1"; + std::string app_id2 = "test_app_id2"; + std::string app_id3 = "test_app_id3"; + scoped_refptr<TestDelegate> delegate = base::MakeRefCounted<TestDelegate>(); + controller->UpdatePrivacyIndicators(app_id1, u"test_app_name", + /*is_camera_used=*/false, + /*is_microphone_used=*/true, delegate, + PrivacyIndicatorsSource::kApps); + controller->UpdatePrivacyIndicators(app_id2, u"test_app_name", + /*is_camera_used=*/false, + /*is_microphone_used=*/true, delegate, + PrivacyIndicatorsSource::kApps); + controller->UpdatePrivacyIndicators(app_id3, u"test_app_name", + /*is_camera_used=*/true, + /*is_microphone_used=*/false, delegate, + PrivacyIndicatorsSource::kApps); + + std::string notification_id1 = GetPrivacyIndicatorsNotificationId(app_id1); + std::string notification_id2 = GetPrivacyIndicatorsNotificationId(app_id2); + std::string notification_id3 = GetPrivacyIndicatorsNotificationId(app_id3); + ASSERT_TRUE(message_center::MessageCenter::Get()->FindNotificationById( + notification_id1)); + ASSERT_TRUE(message_center::MessageCenter::Get()->FindNotificationById( + notification_id2)); + ASSERT_TRUE(message_center::MessageCenter::Get()->FindNotificationById( + notification_id3)); + + CrasAudioHandler::Get()->SetInputMute( + /*mute_on=*/true, + CrasAudioHandler::InputMuteChangeMethod::kKeyboardButton); + EXPECT_FALSE(message_center::MessageCenter::Get()->FindNotificationById( + notification_id1)); + EXPECT_FALSE(message_center::MessageCenter::Get()->FindNotificationById( + notification_id2)); + + // The app that uses camera should not be affected. + EXPECT_TRUE(message_center::MessageCenter::Get()->FindNotificationById( + notification_id3)); + + // When flip back, all old notification should be re-created. + CrasAudioHandler::Get()->SetInputMute( + /*mute_on=*/false, + CrasAudioHandler::InputMuteChangeMethod::kKeyboardButton); + + EXPECT_TRUE(message_center::MessageCenter::Get()->FindNotificationById( + notification_id1)); + EXPECT_TRUE(message_center::MessageCenter::Get()->FindNotificationById( + notification_id2)); +} + // Tests enabling both `kPrivacyIndicators` and `kVideoConference`, // parameterized with `kQsRevamp` enabled and disabled. class PrivacyIndicatorsControllerVideoConferenceTest
diff --git a/ash/system/privacy/privacy_indicators_tray_item_view.cc b/ash/system/privacy/privacy_indicators_tray_item_view.cc index d1acc80..aeeeb25 100644 --- a/ash/system/privacy/privacy_indicators_tray_item_view.cc +++ b/ash/system/privacy/privacy_indicators_tray_item_view.cc
@@ -291,6 +291,32 @@ {cam_and_mic_status, screen_share_status}, /*offsets=*/nullptr); } + +void PrivacyIndicatorsTrayItemView::UpdateVisibility() { + // We only hide the view when nothing is in use. + const bool visible = PrivacyIndicatorsController::Get()->IsCameraUsed() || + PrivacyIndicatorsController::Get()->IsMicrophoneUsed() || + is_screen_sharing_; + + if (GetVisible() == visible) { + return; + } + + SetVisible(visible); + + if (!visible) { + return; + } + + ++count_visible_per_session_; + + // Keep incrementing the count to track the number of times the view flickers. + // When the delay of `kRepeatedShowTimerInterval` has reached, record that + // count. + ++count_repeated_shows_; + repeated_shows_timer_.Reset(); +} + void PrivacyIndicatorsTrayItemView::PerformVisibilityAnimation(bool visible) { // This view will not perform `TrayItemView`'s visibility animation since it // has its own animation. We need to create our own function to trigger the @@ -522,31 +548,6 @@ : kPrivacyIndicatorsViewExpandedLongerSideSize; } -void PrivacyIndicatorsTrayItemView::UpdateVisibility() { - // We only hide the view when nothing is in use. - const bool visible = PrivacyIndicatorsController::Get()->IsCameraUsed() || - PrivacyIndicatorsController::Get()->IsMicrophoneUsed() || - is_screen_sharing_; - - if (GetVisible() == visible) { - return; - } - - SetVisible(visible); - - if (!visible) { - return; - } - - ++count_visible_per_session_; - - // Keeps increment the count to track the number of times the view flickers. - // When the delay of `kRepeatedShowTimerInterval` has reached, record that - // count. - ++count_repeated_shows_; - repeated_shows_timer_.Reset(); -} - void PrivacyIndicatorsTrayItemView::EndAllAnimations() { shorter_side_shrink_animation_->End(); longer_side_shrink_animation_->End();
diff --git a/ash/system/privacy/privacy_indicators_tray_item_view.h b/ash/system/privacy/privacy_indicators_tray_item_view.h index 587cb6d..73965259 100644 --- a/ash/system/privacy/privacy_indicators_tray_item_view.h +++ b/ash/system/privacy/privacy_indicators_tray_item_view.h
@@ -96,6 +96,10 @@ // TrayItemView: std::u16string GetTooltipText(const gfx::Point& point) const override; + // Update the view's visibility based on camera/mic access and screen sharing + // state. + void UpdateVisibility(); + private: friend class PrivacyIndicatorsTrayItemViewTest; friend class CaptureModePrivacyIndicatorsTest; @@ -133,10 +137,6 @@ // Calculate the length of the longer size, based on `is_screen_sharing_`. int GetLongerSideLengthInExpandedMode() const; - // Update the view's visibility based on camera/mic access and screen sharing - // state. - void UpdateVisibility(); - // End all 3 animations contained in this class. void EndAllAnimations();
diff --git a/ash/webui/common/resources/navigation_view_panel.html b/ash/webui/common/resources/navigation_view_panel.html index 60b1599..ac887ef 100644 --- a/ash/webui/common/resources/navigation_view_panel.html +++ b/ash/webui/common/resources/navigation_view_panel.html
@@ -15,6 +15,7 @@ } :host { + --navigation-view-panel-bg-color: var(--cros-bg-color); --navigation-view-panel-toolbar-height: 56px; } @@ -61,6 +62,7 @@ cr-drawer { --cr-separator-line: none; + --cr-drawer-background-color: var(--navigation-view-panel-bg-color); --cr-drawer-header-color: var(--cros-text-color-secondary); --cr-drawer-header-font-weight: 500; --cr-drawer-header-padding: 20px;
diff --git a/ash/webui/common/resources/page_toolbar.html b/ash/webui/common/resources/page_toolbar.html index 5458f3d..be8993f 100644 --- a/ash/webui/common/resources/page_toolbar.html +++ b/ash/webui/common/resources/page_toolbar.html
@@ -1,7 +1,7 @@ <style include="cr-shared-style"> :host { align-items: center; - background: var(--cros-bg-color); + background: var(--navigation-view-panel-bg-color); display: flex; height: var(--navigation-view-panel-toolbar-height, 56px); width: 100%;
diff --git a/ash/webui/diagnostics_ui/resources/diagnostics_app.html b/ash/webui/diagnostics_ui/resources/diagnostics_app.html index af2d4f6..28aeb0e 100644 --- a/ash/webui/diagnostics_ui/resources/diagnostics_app.html +++ b/ash/webui/diagnostics_ui/resources/diagnostics_app.html
@@ -5,6 +5,10 @@ height: 100%; } + :host-context(body.jelly-enabled) navigation-view-panel { + --navigation-view-panel-bg-color: var(--cros-sys-app_base_shaded); + } + page-toolbar { min-height: 56px; position: sticky;
diff --git a/ash/webui/diagnostics_ui/resources/diagnostics_shared.css b/ash/webui/diagnostics_ui/resources/diagnostics_shared.css index acb9b12..66d0ad77 100644 --- a/ash/webui/diagnostics_ui/resources/diagnostics_shared.css +++ b/ash/webui/diagnostics_ui/resources/diagnostics_shared.css
@@ -8,7 +8,7 @@ * #import=chrome://resources/cr_elements/chromeos/cros_color_overrides.css.js * #import=chrome://resources/cr_elements/cr_shared_style.css.js * #import=chrome://resources/cr_elements/cr_shared_vars.css.js - * #include=cr-shared-style + * #include=cr-shared-style cros-color-overrides * #css_wrapper_metadata_end */ :host {
diff --git a/ash/webui/diagnostics_ui/resources/keyboard_tester.html b/ash/webui/diagnostics_ui/resources/keyboard_tester.html index ef95544..8a19ffdf 100644 --- a/ash/webui/diagnostics_ui/resources/keyboard_tester.html +++ b/ash/webui/diagnostics_ui/resources/keyboard_tester.html
@@ -27,6 +27,10 @@ --cr-dialog-body-padding-horizontal: 24px; } + :host-context(body.jelly-enabled) #help { + color: var( --cros-text-color-primary); + } + [slot='title'] { font-family: var(--diagnostics-google-sans-font-family); font-size: 16px;
diff --git a/ash/webui/firmware_update_ui/resources/firmware_shared_css.html b/ash/webui/firmware_update_ui/resources/firmware_shared_css.html index f97e555..703af23 100644 --- a/ash/webui/firmware_update_ui/resources/firmware_shared_css.html +++ b/ash/webui/firmware_update_ui/resources/firmware_shared_css.html
@@ -1,5 +1,5 @@ <template> - <style include="cr-shared-style"> + <style include="cr-shared-style cros-color-overrides"> @media (prefers-color-scheme: dark) { cr-dialog::part(dialog) { background-color: var(--cros-bg-color-elevation-3);
diff --git a/ash/webui/firmware_update_ui/resources/firmware_shared_css.js b/ash/webui/firmware_update_ui/resources/firmware_shared_css.js index 91288f2c..4815544e 100644 --- a/ash/webui/firmware_update_ui/resources/firmware_shared_css.js +++ b/ash/webui/firmware_update_ui/resources/firmware_shared_css.js
@@ -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 '//resources/cr_elements/chromeos/cros_color_overrides.css.js'; import 'chrome://resources/cr_elements/cr_shared_style.css.js'; import 'chrome://resources/cr_elements/cr_shared_vars.css.js'; import 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
diff --git a/ash/webui/firmware_update_ui/resources/firmware_update_app.js b/ash/webui/firmware_update_ui/resources/firmware_update_app.js index 9304627..3abd99b3 100644 --- a/ash/webui/firmware_update_ui/resources/firmware_update_app.js +++ b/ash/webui/firmware_update_ui/resources/firmware_update_app.js
@@ -46,6 +46,7 @@ // `cros_styles.css` with `theme/colors.css` directly in `index.html`. document.querySelector('link[href*=\'cros_styles.css\']') ?.setAttribute('href', 'chrome://theme/colors.css?sets=legacy,sys'); + document.body.classList.add('jelly-enabled'); startColorChangeUpdater(); } }
diff --git a/ash/webui/shortcut_customization_ui/backend/accelerator_configuration_provider.cc b/ash/webui/shortcut_customization_ui/backend/accelerator_configuration_provider.cc index f107fb8..ff01820a 100644 --- a/ash/webui/shortcut_customization_ui/backend/accelerator_configuration_provider.cc +++ b/ash/webui/shortcut_customization_ui/backend/accelerator_configuration_provider.cc
@@ -441,60 +441,15 @@ return; } - // Check if `accelerator` conflicts with non-configurable accelerators. - // This includes: browser, accessbility, and ambient accelerators. - const uint32_t* non_configurable_conflict_id = - non_configurable_accelerator_to_id_.Find(accelerator); - // If there was a conflict with a non-configurable accelerator - if (non_configurable_conflict_id) { - pending_accelerator_.reset(); - result_data->result = AcceleratorConfigResult::kConflict; - // Get the shortcut name and add it to the return struct. - result_data->shortcut_name = l10n_util::GetStringUTF16( - accelerator_layout_lookup_[GetUuid(mojom::AcceleratorSource::kAmbient, - *non_configurable_conflict_id)] - .description_string_id); - std::move(callback).Run(std::move(result_data)); + absl::optional<AcceleratorResultDataPtr> result_data_ptr = + PreprocessAddAccelerator(source, action_id, accelerator); + // Check if there was an error during processing the accelerator, if so return + // early with the error. + if (result_data_ptr.has_value()) { + std::move(callback).Run(std::move(*result_data_ptr)); return; } - // Check if the accelerator conflicts with an existing ash accelerator. - const AcceleratorAction* found_ash_action = - ash_accelerator_configuration_->FindAcceleratorAction(accelerator); - if (found_ash_action && - !ash_accelerator_configuration_->IsDeprecated(accelerator)) { - // Accelerator already exists, check if it belongs to a locked action. - const auto& layout_iter = accelerator_layout_lookup_.find( - GetUuid(mojom::AcceleratorSource::kAsh, *found_ash_action)); - CHECK(layout_iter != accelerator_layout_lookup_.end()); - const AcceleratorLayoutDetails& layout_details = layout_iter->second; - const std::u16string& shortcut_name = - l10n_util::GetStringUTF16(layout_details.description_string_id); - if (layout_details.locked) { - pending_accelerator_.reset(); - result_data->result = AcceleratorConfigResult::kActionLocked; - result_data->shortcut_name = shortcut_name; - std::move(callback).Run(std::move(result_data)); - return; - } - - // If not locked, then check if the user has already pressed the accelerator - // for this action. If not, store it and return the error. If this is a - // different accelerator then store it. - if (!pending_accelerator_ || pending_accelerator_->action != action_id || - pending_accelerator_->source != source || - pending_accelerator_->accelerator != accelerator) { - result_data->result = - mojom::AcceleratorConfigResult::kConflictCanOverride; - pending_accelerator_.reset(); - pending_accelerator_ = - std::make_unique<PendingAccelerator>(accelerator, source, action_id); - result_data->shortcut_name = shortcut_name; - std::move(callback).Run(std::move(result_data)); - return; - } - } - // Continue with adding the accelerator. pending_accelerator_.reset(); result_data->result = ash_accelerator_configuration_->AddUserAccelerator( @@ -525,6 +480,51 @@ std::move(callback).Run(std::move(result_data)); } +void AcceleratorConfigurationProvider::ReplaceAccelerator( + mojom::AcceleratorSource source, + uint32_t action_id, + const ui::Accelerator& old_accelerator, + const ui::Accelerator& new_accelerator, + ReplaceAcceleratorCallback callback) { + CHECK(::features::IsShortcutCustomizationEnabled()); + + AcceleratorResultDataPtr result_data = AcceleratorResultData::New(); + + absl::optional<AcceleratorConfigResult> validated_source_action_result = + ValidateSourceAndAction(source, action_id, + ash_accelerator_configuration_); + + if (validated_source_action_result.has_value()) { + result_data->result = *validated_source_action_result; + std::move(callback).Run(std::move(result_data)); + return; + } + + // Verify old accelerator exists. + const AcceleratorAction* old_accelerator_id = + ash_accelerator_configuration_->FindAcceleratorAction(old_accelerator); + if (!old_accelerator_id || *old_accelerator_id != action_id) { + result_data->result = AcceleratorConfigResult::kNotFound; + std::move(callback).Run(std::move(result_data)); + return; + } + + // Check if there was an error during processing the accelerator, if so return + // early with the error. + absl::optional<AcceleratorResultDataPtr> result_data_ptr = + PreprocessAddAccelerator(source, action_id, new_accelerator); + if (result_data_ptr.has_value()) { + std::move(callback).Run(std::move(*result_data_ptr)); + return; + } + + // Continue with replacing the accelerator. + pending_accelerator_.reset(); + result_data->result = ash_accelerator_configuration_->ReplaceAccelerator( + action_id, old_accelerator, new_accelerator); + std::move(callback).Run(std::move(result_data)); +} + void AcceleratorConfigurationProvider::RestoreDefault( mojom::AcceleratorSource source, uint32_t action_id, @@ -639,6 +639,66 @@ } } +absl::optional<AcceleratorResultDataPtr> +AcceleratorConfigurationProvider::PreprocessAddAccelerator( + mojom::AcceleratorSource source, + AcceleratorActionId action_id, + const ui::Accelerator& accelerator) { + AcceleratorResultDataPtr result_data = AcceleratorResultData::New(); + + // Check if `accelerator` conflicts with non-configurable accelerators. + // This includes: browser, accessbility, and ambient accelerators. + const uint32_t* non_configurable_conflict_id = + non_configurable_accelerator_to_id_.Find(accelerator); + // If there was a conflict with a non-configurable accelerator + if (non_configurable_conflict_id) { + pending_accelerator_.reset(); + result_data->result = AcceleratorConfigResult::kConflict; + // Get the shortcut name and add it to the return struct. + result_data->shortcut_name = l10n_util::GetStringUTF16( + accelerator_layout_lookup_[GetUuid(mojom::AcceleratorSource::kAmbient, + *non_configurable_conflict_id)] + .description_string_id); + return result_data; + } + + // Check if the accelerator conflicts with an existing ash accelerator. + const AcceleratorAction* found_ash_action = + ash_accelerator_configuration_->FindAcceleratorAction(accelerator); + if (found_ash_action && + !ash_accelerator_configuration_->IsDeprecated(accelerator)) { + // Accelerator already exists, check if it belongs to a locked action. + const auto& layout_iter = accelerator_layout_lookup_.find( + GetUuid(mojom::AcceleratorSource::kAsh, *found_ash_action)); + CHECK(layout_iter != accelerator_layout_lookup_.end()); + const AcceleratorLayoutDetails& layout_details = layout_iter->second; + const std::u16string& shortcut_name = + l10n_util::GetStringUTF16(layout_details.description_string_id); + if (layout_details.locked) { + pending_accelerator_.reset(); + result_data->result = AcceleratorConfigResult::kActionLocked; + result_data->shortcut_name = shortcut_name; + return result_data; + } + + // If not locked, then check if the user has already pressed the accelerator + // for this action. If not, store it and return the error. If this is a + // different accelerator then store it. + if (!pending_accelerator_ || pending_accelerator_->action != action_id || + pending_accelerator_->source != source || + pending_accelerator_->accelerator != accelerator) { + result_data->result = + mojom::AcceleratorConfigResult::kConflictCanOverride; + pending_accelerator_.reset(); + pending_accelerator_ = + std::make_unique<PendingAccelerator>(accelerator, source, action_id); + result_data->shortcut_name = shortcut_name; + return result_data; + } + } + return absl::nullopt; +} + void AcceleratorConfigurationProvider::SetLayoutDetailsMapForTesting( const std::vector<AcceleratorLayoutDetails>& layouts) { accelerator_layout_lookup_.clear();
diff --git a/ash/webui/shortcut_customization_ui/backend/accelerator_configuration_provider.h b/ash/webui/shortcut_customization_ui/backend/accelerator_configuration_provider.h index 103ba8e0..7318301 100644 --- a/ash/webui/shortcut_customization_ui/backend/accelerator_configuration_provider.h +++ b/ash/webui/shortcut_customization_ui/backend/accelerator_configuration_provider.h
@@ -85,6 +85,11 @@ uint32_t action_id, const ui::Accelerator& accelerator, RemoveAcceleratorCallback callback) override; + void ReplaceAccelerator(mojom::AcceleratorSource source, + uint32_t action_id, + const ui::Accelerator& old_accelerator, + const ui::Accelerator& new_accelerator, + ReplaceAcceleratorCallback callback) override; void RestoreDefault(mojom::AcceleratorSource source, uint32_t action_id, RestoreDefaultCallback callback) override; @@ -164,6 +169,13 @@ mojom::AcceleratorState state, std::vector<mojom::AcceleratorInfoPtr>& output); + // Returns a non-null value if there was an error with pre-processing the + // accelerator to be added. + absl::optional<shortcut_customization::mojom::AcceleratorResultDataPtr> + PreprocessAddAccelerator(mojom::AcceleratorSource source, + AcceleratorActionId action_id, + const ui::Accelerator& accelerator); + void SetLayoutDetailsMapForTesting( const std::vector<AcceleratorLayoutDetails>& layouts);
diff --git a/ash/webui/shortcut_customization_ui/backend/accelerator_configuration_provider_unittest.cc b/ash/webui/shortcut_customization_ui/backend/accelerator_configuration_provider_unittest.cc index 7604066..f27b8e7 100644 --- a/ash/webui/shortcut_customization_ui/backend/accelerator_configuration_provider_unittest.cc +++ b/ash/webui/shortcut_customization_ui/backend/accelerator_configuration_provider_unittest.cc
@@ -20,6 +20,7 @@ #include "ash/public/mojom/accelerator_info.mojom.h" #include "ash/session/session_controller_impl.h" #include "ash/shell.h" +#include "ash/strings/grit/ash_strings.h" #include "ash/test/ash_test_base.h" #include "ash/webui/shortcut_customization_ui/backend/accelerator_layout_table.h" #include "ash/webui/shortcut_customization_ui/mojom/shortcut_customization.mojom-forward.h" @@ -1560,6 +1561,40 @@ updated_test_data, actual_config); } +TEST_F(AcceleratorConfigurationProviderTest, ReplaceBadSourceOrAction) { + FakeAcceleratorsUpdatedMojoObserver observer; + SetUpObserver(&observer); + + // Initialize default accelerators. + const AcceleratorData test_data[] = { + {/*trigger_on_press=*/true, ui::VKEY_SPACE, ui::EF_CONTROL_DOWN, + TOGGLE_MIRROR_MODE}, + }; + + AshAcceleratorConfiguration* config = + Shell::Get()->ash_accelerator_configuration(); + config->Initialize(test_data); + base::RunLoop().RunUntilIdle(); + + AcceleratorResultDataPtr result; + const ui::Accelerator old_accelerator(ui::VKEY_SPACE, ui::EF_CONTROL_DOWN); + const ui::Accelerator new_accelerator(ui::VKEY_M, ui::EF_ALT_DOWN); + // Browser is a locked source. + ash::shortcut_customization::mojom:: + AcceleratorConfigurationProviderAsyncWaiter(provider_.get()) + .ReplaceAccelerator(mojom::AcceleratorSource::kBrowser, + TOGGLE_MIRROR_MODE, old_accelerator, + new_accelerator, &result); + EXPECT_EQ(mojom::AcceleratorConfigResult::kActionLocked, result->result); + + // TOGGLE_CALENDAR does not exist. + ash::shortcut_customization::mojom:: + AcceleratorConfigurationProviderAsyncWaiter(provider_.get()) + .ReplaceAccelerator(mojom::AcceleratorSource::kAsh, TOGGLE_CALENDAR, + old_accelerator, new_accelerator, &result); + EXPECT_EQ(mojom::AcceleratorConfigResult::kNotFound, result->result); +} + TEST_F(AcceleratorConfigurationProviderTest, AddAcceleratorConflictThenGood) { FakeAcceleratorsUpdatedMojoObserver observer; SetUpObserver(&observer); @@ -1639,6 +1674,210 @@ ->ShouldPreventProcessingAccelerators()); } +TEST_F(AcceleratorConfigurationProviderTest, ReplaceDefaultAccelerator) { + FakeAcceleratorsUpdatedMojoObserver observer; + SetUpObserver(&observer); + + // Initialize default accelerators. + const AcceleratorData test_data[] = { + {/*trigger_on_press=*/true, ui::VKEY_SPACE, ui::EF_CONTROL_DOWN, + TOGGLE_MIRROR_MODE}, + }; + + AshAcceleratorConfiguration* config = + Shell::Get()->ash_accelerator_configuration(); + config->Initialize(test_data); + base::RunLoop().RunUntilIdle(); + + AcceleratorResultDataPtr result; + const ui::Accelerator old_accelerator(ui::VKEY_SPACE, ui::EF_CONTROL_DOWN); + const ui::Accelerator new_accelerator(ui::VKEY_M, ui::EF_ALT_DOWN); + ash::shortcut_customization::mojom:: + AcceleratorConfigurationProviderAsyncWaiter(provider_.get()) + .ReplaceAccelerator(mojom::AcceleratorSource::kAsh, + TOGGLE_MIRROR_MODE, old_accelerator, + new_accelerator, &result); + EXPECT_EQ(mojom::AcceleratorConfigResult::kSuccess, result->result); + + base::RunLoop().RunUntilIdle(); + + const AcceleratorData updated_test_data[] = { + {/*trigger_on_press=*/true, ui::VKEY_SPACE, ui::EF_CONTROL_DOWN, + TOGGLE_MIRROR_MODE}, + {/*trigger_on_press=*/true, ui::VKEY_M, ui::EF_ALT_DOWN, + TOGGLE_MIRROR_MODE}, + }; + + // Replacing a default will result in disabling the default and then adding + // the new accelerator. + AcceleratorConfigurationProvider::AcceleratorConfigurationMap actual_config = + observer.config(); + ExpectMojomAcceleratorsEqual(mojom::AcceleratorSource::kAsh, + updated_test_data, mojo::Clone(actual_config)); + + std::vector<mojom::AcceleratorInfoPtr> actual_infos(mojo::Clone( + actual_config[mojom::AcceleratorSource::kAsh][TOGGLE_MIRROR_MODE])); + EXPECT_EQ(2u, actual_infos.size()); + // A disabled default accelerator should be marked as `kDisabledByUser`. + EXPECT_EQ(mojom::AcceleratorState::kDisabledByUser, actual_infos[0]->state); + EXPECT_EQ(mojom::AcceleratorType::kDefault, actual_infos[0]->type); +} + +TEST_F(AcceleratorConfigurationProviderTest, ReplaceAcceleratorDoesNotExist) { + FakeAcceleratorsUpdatedMojoObserver observer; + SetUpObserver(&observer); + + // Initialize default accelerators. + const AcceleratorData test_data[] = { + {/*trigger_on_press=*/true, ui::VKEY_SPACE, ui::EF_CONTROL_DOWN, + TOGGLE_MIRROR_MODE}, + }; + + AshAcceleratorConfiguration* config = + Shell::Get()->ash_accelerator_configuration(); + config->Initialize(test_data); + base::RunLoop().RunUntilIdle(); + + AcceleratorResultDataPtr result; + const ui::Accelerator old_accelerator(ui::VKEY_J, ui::EF_CONTROL_DOWN); + const ui::Accelerator new_accelerator(ui::VKEY_M, ui::EF_ALT_DOWN); + ash::shortcut_customization::mojom:: + AcceleratorConfigurationProviderAsyncWaiter(provider_.get()) + .ReplaceAccelerator(mojom::AcceleratorSource::kAsh, + TOGGLE_MIRROR_MODE, old_accelerator, + new_accelerator, &result); + EXPECT_EQ(mojom::AcceleratorConfigResult::kNotFound, result->result); +} + +TEST_F(AcceleratorConfigurationProviderTest, AddThenReplaceAccelerator) { + FakeAcceleratorsUpdatedMojoObserver observer; + SetUpObserver(&observer); + + // Initialize default accelerators. + const AcceleratorData test_data[] = { + {/*trigger_on_press=*/true, ui::VKEY_SPACE, ui::EF_CONTROL_DOWN, + TOGGLE_MIRROR_MODE}, + }; + + AshAcceleratorConfiguration* config = + Shell::Get()->ash_accelerator_configuration(); + config->Initialize(test_data); + base::RunLoop().RunUntilIdle(); + + AcceleratorResultDataPtr result; + const ui::Accelerator accelerator(ui::VKEY_M, ui::EF_ALT_DOWN); + ash::shortcut_customization::mojom:: + AcceleratorConfigurationProviderAsyncWaiter(provider_.get()) + .AddAccelerator(mojom::AcceleratorSource::kAsh, TOGGLE_MIRROR_MODE, + accelerator, &result); + EXPECT_EQ(mojom::AcceleratorConfigResult::kSuccess, result->result); + + const AcceleratorData updated_test_data[] = { + {/*trigger_on_press=*/true, ui::VKEY_SPACE, ui::EF_CONTROL_DOWN, + TOGGLE_MIRROR_MODE}, + {/*trigger_on_press=*/true, ui::VKEY_M, ui::EF_ALT_DOWN, + TOGGLE_MIRROR_MODE}, + }; + + AcceleratorConfigurationProvider::AcceleratorConfigurationMap actual_config = + observer.config(); + ExpectMojomAcceleratorsEqual(mojom::AcceleratorSource::kAsh, + updated_test_data, mojo::Clone(actual_config)); + + // Now replace the newly added accelerator. + const ui::Accelerator new_accelerator(ui::VKEY_C, ui::EF_COMMAND_DOWN); + ash::shortcut_customization::mojom:: + AcceleratorConfigurationProviderAsyncWaiter(provider_.get()) + .ReplaceAccelerator(mojom::AcceleratorSource::kAsh, + TOGGLE_MIRROR_MODE, accelerator, new_accelerator, + &result); + EXPECT_EQ(mojom::AcceleratorConfigResult::kSuccess, result->result); + + const AcceleratorData updated_test_data2[] = { + {/*trigger_on_press=*/true, ui::VKEY_SPACE, ui::EF_CONTROL_DOWN, + TOGGLE_MIRROR_MODE}, + {/*trigger_on_press=*/true, ui::VKEY_C, ui::EF_COMMAND_DOWN, + TOGGLE_MIRROR_MODE}, + }; + + actual_config = observer.config(); + ExpectMojomAcceleratorsEqual(mojom::AcceleratorSource::kAsh, + updated_test_data2, mojo::Clone(actual_config)); +} + +TEST_F(AcceleratorConfigurationProviderTest, + ReplaceOtherDefaultAcceleratorAction) { + FakeAcceleratorsUpdatedMojoObserver observer; + SetUpObserver(&observer); + + // Initialize default accelerators. + const AcceleratorData test_data[] = { + {/*trigger_on_press=*/true, ui::VKEY_SPACE, ui::EF_CONTROL_DOWN, + TOGGLE_MIRROR_MODE}, + {/*trigger_on_press=*/true, ui::VKEY_D, ui::EF_ALT_DOWN, TOGGLE_CALENDAR}, + }; + + AshAcceleratorConfiguration* config = + Shell::Get()->ash_accelerator_configuration(); + config->Initialize(test_data); + base::RunLoop().RunUntilIdle(); + + // Replace the default of `TOGGLE_CALENDAR` with that of the default of + // `TOGGLE_MIRROR_MODE`. This results in `TOGGLE_MIRROR_MODE` to have only the + // disabled default accelerator, `TOGGLE_CALENDAR` will also have disabled + // default accelerator but also a new accelerator added. + AcceleratorResultDataPtr result; + const ui::Accelerator old_accelerator(ui::VKEY_D, ui::EF_ALT_DOWN); + const ui::Accelerator new_accelerator(ui::VKEY_SPACE, ui::EF_CONTROL_DOWN); + ash::shortcut_customization::mojom:: + AcceleratorConfigurationProviderAsyncWaiter(provider_.get()) + .ReplaceAccelerator(mojom::AcceleratorSource::kAsh, TOGGLE_CALENDAR, + old_accelerator, new_accelerator, &result); + // Overridable accelerator, but will need to re-call `ReplaceAccelerator` to + // confirm the override. + EXPECT_EQ(mojom::AcceleratorConfigResult::kConflictCanOverride, + result->result); + EXPECT_EQ(l10n_util::GetStringUTF16( + IDS_ASH_ACCELERATOR_DESCRIPTION_TOGGLE_MIRROR_MODE), + result->shortcut_name); + + ash::shortcut_customization::mojom:: + AcceleratorConfigurationProviderAsyncWaiter(provider_.get()) + .ReplaceAccelerator(mojom::AcceleratorSource::kAsh, TOGGLE_CALENDAR, + old_accelerator, new_accelerator, &result); + + EXPECT_EQ(mojom::AcceleratorConfigResult::kSuccess, result->result); + + base::RunLoop().RunUntilIdle(); + + const AcceleratorData updated_test_data[] = { + {/*trigger_on_press=*/true, ui::VKEY_SPACE, ui::EF_CONTROL_DOWN, + TOGGLE_MIRROR_MODE}, + {/*trigger_on_press=*/true, ui::VKEY_D, ui::EF_ALT_DOWN, TOGGLE_CALENDAR}, + {/*trigger_on_press=*/true, ui::VKEY_SPACE, ui::EF_CONTROL_DOWN, + TOGGLE_CALENDAR}, + }; + + AcceleratorConfigurationProvider::AcceleratorConfigurationMap actual_config = + observer.config(); + ExpectMojomAcceleratorsEqual(mojom::AcceleratorSource::kAsh, + updated_test_data, mojo::Clone(actual_config)); + + std::vector<mojom::AcceleratorInfoPtr> actual_infos(mojo::Clone( + actual_config[mojom::AcceleratorSource::kAsh][TOGGLE_MIRROR_MODE])); + EXPECT_EQ(1u, actual_infos.size()); + EXPECT_EQ(mojom::AcceleratorState::kDisabledByUser, actual_infos[0]->state); + EXPECT_EQ(mojom::AcceleratorType::kDefault, actual_infos[0]->type); + + std::vector<mojom::AcceleratorInfoPtr> actual_infos2(mojo::Clone( + actual_config[mojom::AcceleratorSource::kAsh][TOGGLE_CALENDAR])); + EXPECT_EQ(2u, actual_infos2.size()); + EXPECT_EQ(mojom::AcceleratorState::kDisabledByUser, actual_infos2[0]->state); + EXPECT_EQ(mojom::AcceleratorType::kDefault, actual_infos2[0]->type); + EXPECT_EQ(mojom::AcceleratorState::kEnabled, actual_infos2[1]->state); + EXPECT_EQ(mojom::AcceleratorType::kDefault, actual_infos2[1]->type); +} + using FlagsKeyboardCodesVariant = std::variant<ui::EventFlags, ui::KeyboardCode, TextAcceleratorDelimiter>; using FlagsKeyboardCodeStringVariant = std::variant<ui::EventFlags,
diff --git a/ash/webui/shortcut_customization_ui/backend/accelerator_layout_table.cc b/ash/webui/shortcut_customization_ui/backend/accelerator_layout_table.cc index 93459ad..f7f99e8 100644 --- a/ash/webui/shortcut_customization_ui/backend/accelerator_layout_table.cc +++ b/ash/webui/shortcut_customization_ui/backend/accelerator_layout_table.cc
@@ -189,16 +189,16 @@ {NonConfigurableActions::kAmbientHighlightNextItemOnShelf, NonConfigurableAcceleratorDetails( IDS_AMBIENT_ACCELERATOR_HIGHLIGHT_NEXT_ITEM_ON_SHELF, - {TextAcceleratorPart(ui::EF_SHIFT_DOWN), - TextAcceleratorPart(ui::EF_ALT_DOWN), + {TextAcceleratorPart(ui::EF_ALT_DOWN), + TextAcceleratorPart(ui::EF_SHIFT_DOWN), TextAcceleratorPart(ui::KeyboardCode::VKEY_I), TextAcceleratorPart(ui::KeyboardCode::VKEY_TAB), TextAcceleratorPart(ui::KeyboardCode::VKEY_RIGHT)})}, {NonConfigurableActions::kAmbientHighlightPreviousItemOnShelf, NonConfigurableAcceleratorDetails( IDS_AMBIENT_ACCELERATOR_HIGHTLIGHT_PREVIOUS_ITEM_ON_SHELF, - {TextAcceleratorPart(ui::EF_SHIFT_DOWN), - TextAcceleratorPart(ui::EF_ALT_DOWN), + {TextAcceleratorPart(ui::EF_ALT_DOWN), + TextAcceleratorPart(ui::EF_SHIFT_DOWN), TextAcceleratorPart(ui::KeyboardCode::VKEY_I), TextAcceleratorPart(ui::EF_SHIFT_DOWN), TextAcceleratorPart(ui::KeyboardCode::VKEY_TAB), @@ -206,16 +206,16 @@ {NonConfigurableActions::kAmbientOpenHighlightedItemOnShelf, NonConfigurableAcceleratorDetails( IDS_AMBIENT_ACCELERATOR_OPEN_HIGHLIGHTED_ITEM_ON_SHELF, - {TextAcceleratorPart(ui::EF_SHIFT_DOWN), - TextAcceleratorPart(ui::EF_ALT_DOWN), + {TextAcceleratorPart(ui::EF_ALT_DOWN), + TextAcceleratorPart(ui::EF_SHIFT_DOWN), TextAcceleratorPart(ui::KeyboardCode::VKEY_I), TextAcceleratorPart(ui::KeyboardCode::VKEY_SPACE), TextAcceleratorPart(ui::KeyboardCode::VKEY_RETURN)})}, {NonConfigurableActions::kAmbientRemoveHighlightOnShelf, NonConfigurableAcceleratorDetails( IDS_AMBIENT_ACCELERATOR_REMOVE_HIGHLIGHT_ON_SHELF, - {TextAcceleratorPart(ui::EF_SHIFT_DOWN), - TextAcceleratorPart(ui::EF_ALT_DOWN), + {TextAcceleratorPart(ui::EF_ALT_DOWN), + TextAcceleratorPart(ui::EF_SHIFT_DOWN), TextAcceleratorPart(ui::KeyboardCode::VKEY_I), TextAcceleratorPart(ui::KeyboardCode::VKEY_ESCAPE)})}, {NonConfigurableActions::kAmbientSwitchFocus, @@ -254,8 +254,8 @@ {NonConfigurableActions::kAmbientActivateIndexedDesk, NonConfigurableAcceleratorDetails( IDS_AMBIENT_ACCELERATOR_ACTIVATE_INDEXED_DESK, - {TextAcceleratorPart(ui::EF_SHIFT_DOWN), - TextAcceleratorPart(ui::EF_COMMAND_DOWN), + {TextAcceleratorPart(ui::EF_COMMAND_DOWN), + TextAcceleratorPart(ui::EF_SHIFT_DOWN), TextAcceleratorPart(TextAcceleratorDelimiter::kPlusSign), TextAcceleratorPart(ui::KeyboardCode::VKEY_1), TextAcceleratorPart(ui::KeyboardCode::VKEY_8)})},
diff --git a/ash/webui/shortcut_customization_ui/mojom/shortcut_customization.mojom b/ash/webui/shortcut_customization_ui/mojom/shortcut_customization.mojom index 196d3248..adcfb48 100644 --- a/ash/webui/shortcut_customization_ui/mojom/shortcut_customization.mojom +++ b/ash/webui/shortcut_customization_ui/mojom/shortcut_customization.mojom
@@ -101,6 +101,14 @@ SimpleAccelerator accelerator) => (AcceleratorResultData result); + // Atomic version of `RemoveAccelerator(old_accelerator)` then + // `AddAccelerator(new_accelerator)`. This follows behaviors detailed by both + // respective sub-actions. + ReplaceAccelerator(ash.mojom.AcceleratorSource source, uint32 action_id, + SimpleAccelerator old_accelerator, + SimpleAccelerator new_accelerator) + => (AcceleratorResultData result); + // Resets the accelerators of `action_id` to the system defaults. This will // remove any user added accelerators. If a default accelerator is used by // another accelerator, it will be disable for `action_id`.
diff --git a/ash/webui/shortcut_customization_ui/resources/js/accelerator_view.ts b/ash/webui/shortcut_customization_ui/resources/js/accelerator_view.ts index 3f1e400c..515d00a3 100644 --- a/ash/webui/shortcut_customization_ui/resources/js/accelerator_view.ts +++ b/ash/webui/shortcut_customization_ui/resources/js/accelerator_view.ts
@@ -414,9 +414,9 @@ .replaceAccelerator( this.source, this.action, (getAccelerator(this.acceleratorInfo)), (getAccelerator(newAcceleratorInfo))) - .then((result: AcceleratorConfigResult) => { + .then(({result}) => { // TODO(jimmyxgong): Handle other error cases. - if (result === AcceleratorConfigResult.kSuccess) { + if (result.result === AcceleratorConfigResult.kSuccess) { this.lookupManager.replaceAccelerator( this.source, this.action, this.acceleratorInfo.layoutProperties.standardAccelerator
diff --git a/ash/webui/shortcut_customization_ui/resources/js/fake_shortcut_provider.ts b/ash/webui/shortcut_customization_ui/resources/js/fake_shortcut_provider.ts index 8f22414..ff70c131 100644 --- a/ash/webui/shortcut_customization_ui/resources/js/fake_shortcut_provider.ts +++ b/ash/webui/shortcut_customization_ui/resources/js/fake_shortcut_provider.ts
@@ -106,10 +106,14 @@ return this.methods.resolveMethod('addAccelerator'); } - replaceAccelerator(): Promise<AcceleratorConfigResult> { + replaceAccelerator( + _source: AcceleratorSource, _actionId: number, + _old_accelerator: Accelerator, + _new_accelerator: Accelerator): Promise<{result: AcceleratorResultData}> { // Always return kSuccess in this fake. - this.methods.setResult( - 'replaceAccelerator', AcceleratorConfigResult.kSuccess); + const result = new AcceleratorResultData(); + result.result = AcceleratorConfigResult.kSuccess; + this.methods.setResult('replaceAccelerator', {result}); return this.methods.resolveMethod('replaceAccelerator'); }
diff --git a/ash/webui/shortcut_customization_ui/resources/js/mojo_interface_provider.ts b/ash/webui/shortcut_customization_ui/resources/js/mojo_interface_provider.ts index 6a69107e..89aa32b 100644 --- a/ash/webui/shortcut_customization_ui/resources/js/mojo_interface_provider.ts +++ b/ash/webui/shortcut_customization_ui/resources/js/mojo_interface_provider.ts
@@ -8,7 +8,7 @@ import {fakeAcceleratorConfig, fakeLayoutInfo} from './fake_data.js'; import {FakeShortcutProvider} from './fake_shortcut_provider.js'; -import {Accelerator, AcceleratorConfigResult, AcceleratorSource, MojoAcceleratorConfig, MojoLayoutInfo, ShortcutProviderInterface} from './shortcut_types.js'; +import {Accelerator, AcceleratorSource, MojoAcceleratorConfig, MojoLayoutInfo, ShortcutProviderInterface} from './shortcut_types.js'; @@ -100,7 +100,7 @@ replaceAccelerator( source: AcceleratorSource, action: number, oldAccelerator: Accelerator, - newAccelerator: Accelerator): Promise<AcceleratorConfigResult> { + newAccelerator: Accelerator): Promise<{result: AcceleratorResultData}> { // TODO(cambickel) Replace with real mojo method. return this.fakeProvider.replaceAccelerator( source, action, oldAccelerator, newAccelerator);
diff --git a/ash/webui/shortcut_customization_ui/resources/js/shortcut_types.ts b/ash/webui/shortcut_customization_ui/resources/js/shortcut_types.ts index b234ac7..a212a1a 100644 --- a/ash/webui/shortcut_customization_ui/resources/js/shortcut_types.ts +++ b/ash/webui/shortcut_customization_ui/resources/js/shortcut_types.ts
@@ -208,7 +208,7 @@ accelerator: Accelerator): Promise<{result: AcceleratorResultData}>; replaceAccelerator( source: AcceleratorSource, action: number, oldAccelerator: Accelerator, - newAccelerator: Accelerator): Promise<AcceleratorConfigResult>; + newAccelerator: Accelerator): Promise<{result: AcceleratorResultData}>; addObserver(observer: AcceleratorsUpdatedObserverRemote): void; restoreDefault(source: AcceleratorSource, actionId: number): Promise<{result: AcceleratorResultData}>;
diff --git a/ash/wm/desks/desks_controller.cc b/ash/wm/desks/desks_controller.cc index 077047f7..ae4c5820 100644 --- a/ash/wm/desks/desks_controller.cc +++ b/ash/wm/desks/desks_controller.cc
@@ -12,7 +12,6 @@ #include "ash/app_list/app_list_controller_impl.h" #include "ash/constants/ash_features.h" #include "ash/constants/notifier_catalogs.h" -#include "ash/public/cpp/app_types_util.h" #include "ash/public/cpp/desk_template.h" #include "ash/public/cpp/shelf_model.h" #include "ash/public/cpp/shelf_types.h" @@ -2055,11 +2054,7 @@ // logic. However, the desk controller has waited for the app window to // close cleanly before this. if (widget) { - // TODO(b/276351837): Remove this ARC check once we have a better way of - // closing ARC++ windows. - if (!IsArcWindow(window)) { - widget->CloseNow(); - } + widget->CloseNow(); } else { // If the window does not have a widget, we add it to the // `widgetless_windows` tracker to check back on later.
diff --git a/ash/wm/overview/overview_grid.cc b/ash/wm/overview/overview_grid.cc index 931d395e..09cea56b 100644 --- a/ash/wm/overview/overview_grid.cc +++ b/ash/wm/overview/overview_grid.cc
@@ -832,6 +832,8 @@ drop_target_widget_ = CreateDropTargetWidget(root_window_, dragged_item->GetWindow()); const size_t position = GetOverviewItemIndex(dragged_item) + 1u; + // TODO(b/277979324): Consider avoid creating overview item for drop target + // widget. overview_session_->AddItem(drop_target_widget_->GetNativeWindow(), /*reposition=*/true, /*animate=*/false, /*ignored_items=*/{dragged_item}, position); @@ -850,6 +852,8 @@ drop_target_widget_->SetOpacity(1.f); } const size_t position = FindInsertionIndex(dragged_window); + // TODO(b/277979324): Consider avoid creating overview item for drop target + // widget. overview_session_->AddItem(drop_target_window, /*reposition=*/true, animate, /*ignored_items=*/{}, position); }
diff --git a/ash/wm/overview/overview_item.cc b/ash/wm/overview/overview_item.cc index 86d023b0..e9fd0c0 100644 --- a/ash/wm/overview/overview_item.cc +++ b/ash/wm/overview/overview_item.cc
@@ -437,8 +437,9 @@ // will be squashed to fit the given bounds. To get around this, stretch out // the contents so that it matches `unclipped_size_`, then clip the layer to // match `target_bounds`. This is what is done on non-minimized windows. - ui::Layer* preview_layer = overview_item_view_->preview_view()->layer(); - DCHECK(preview_layer); + auto* preview_view = overview_item_view_->preview_view(); + CHECK(preview_view); + ui::Layer* preview_layer = preview_view->layer(); if (unclipped_size_) { gfx::SizeF target_size(*unclipped_size_); gfx::SizeF preview_size = GetWindowTargetBoundsWithInsets().size(); @@ -774,10 +775,13 @@ 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)); + bounds_in_item.ClampToCenteredSize( gfx::ToRoundedSize(bounds_in_screen->size())); shadow_->SetContentBounds(bounds_in_item); + if (chromeos::features::IsJellyrollEnabled()) { + shadow_->SetRoundedCornerRadius(kOverviewItemCornerRadius); + } } void OverviewItem::UpdateRoundedCornersAndShadow() { @@ -808,13 +812,15 @@ ->GetAnimator() ->is_animating(); if (should_show_shadow) { - // The shadow should always match the size of the item minus the border and - // header instead of the transformed window or preview view, since for the - // window which has `kPillarBoxed` or `kLetterBoxed` dimension types, it - // doesn't occupy the whole remaining area of the overview item widget minus - // the header view in which case, the shadow looks weird if it matches the - // size of the transformed window or preview view. - SetShadowBounds(absl::make_optional(GetWindowTargetBoundsWithInsets())); + // The shadow should always match the size of the item minus the border + // instead of the transformed window or preview view, since for the window + // which has `kPillarBoxed` or `kLetterBoxed` dimension types, it doesn't + // occupy the whole remaining area of the overview item widget minus the + // header view in which case, the shadow looks weird if it matches the size + // of the transformed window or preview view. + gfx::RectF shadow_bounds = target_bounds_; + shadow_bounds.Inset(gfx::InsetsF(kWindowMargin)); + SetShadowBounds(absl::make_optional(shadow_bounds)); } else { SetShadowBounds(absl::nullopt); } @@ -1053,10 +1059,10 @@ } void OverviewItem::OnWindowDestroying(aura::Window* window) { - DCHECK_EQ(GetWindow(), window); + CHECK_EQ(GetWindow(), window); if (is_being_dragged_) { - DCHECK_EQ(this, overview_session_->window_drag_controller()->item()); + CHECK_EQ(this, overview_session_->window_drag_controller()->item()); overview_session_->window_drag_controller()->ResetGesture(); } @@ -1257,9 +1263,7 @@ // transform. if (transform_window_.type() == OverviewGridWindowFillMode::kNormal && overview_item_bounds.width() != transformed_bounds.width()) { - overview_item_bounds.set_x( - overview_item_bounds.x() + - 0.5f * (overview_item_bounds.width() - transformed_bounds.width())); + overview_item_bounds.set_x(transformed_bounds.x()); overview_item_bounds.set_width(transformed_bounds.width()); } }
diff --git a/ash/wm/overview/overview_item_view.cc b/ash/wm/overview/overview_item_view.cc index 157c781..423b9fa4 100644 --- a/ash/wm/overview/overview_item_view.cc +++ b/ash/wm/overview/overview_item_view.cc
@@ -100,9 +100,9 @@ // elements existing. SetShowPreview(show_preview); // Do not show header if the current overview item is the drop target widget. - if (show_preview || overview_item_->overview_grid()->IsDropTargetWindow( - overview_item_->GetWindow())) { - header_view()->layer()->SetOpacity(0.f); + if (overview_item_->overview_grid()->IsDropTargetWindow( + overview_item_->GetWindow())) { + header_view()->SetVisible(false); current_header_visibility_ = HeaderVisibility::kInvisible; }
diff --git a/ash/wm/overview/overview_session_unittest.cc b/ash/wm/overview/overview_session_unittest.cc index 9969722..c1ef05cf 100644 --- a/ash/wm/overview/overview_session_unittest.cc +++ b/ash/wm/overview/overview_session_unittest.cc
@@ -103,6 +103,7 @@ #include "ui/events/event_utils.h" #include "ui/events/gesture_detection/gesture_configuration.h" #include "ui/events/test/event_generator.h" +#include "ui/gfx/geometry/insets_f.h" #include "ui/gfx/geometry/point_conversions.h" #include "ui/gfx/geometry/transform.h" #include "ui/gfx/geometry/transform_util.h" @@ -484,6 +485,24 @@ EXPECT_EQ(window2.get(), window_util::GetFocusedWindow()); } +// Tests that calling `views::Widget::CloseNow` on a minimized window that is +// currently being dragged does not cause a crash. Regression test for +// b/268413746. +TEST_P(OverviewSessionTest, CloseNowDraggedMinimizedWindow) { + std::unique_ptr<aura::Window> window = CreateAppWindow(); + WindowState::Get(window.get())->Minimize(); + + // Start dragging the window. + ToggleOverview(); + GetEventGenerator()->set_current_screen_location( + GetTransformedTargetBounds(window.get()).CenterPoint()); + GetEventGenerator()->PressLeftButton(); + + // Call `views::Widget::CloseNow` on the window mid drag and verify no crash. + // This could happen in production when an exo window shuts down. + views::Widget::GetWidgetForNativeView(window.release())->CloseNow(); +} + // Tests that the user action WindowSelector_ActiveWindowChanged is // recorded when the mouse/touchscreen/keyboard are used to select a window // in overview mode which is different from the previously-active window. @@ -2583,7 +2602,8 @@ // Helper function which returns the ratio of the item width and height minus // the header and window margin. auto item_ratio = [](OverviewItem* item) { - gfx::RectF boundsf = item->GetWindowTargetBoundsWithInsets(); + gfx::RectF boundsf = item->target_bounds(); + boundsf.Inset(gfx::InsetsF(kWindowMargin)); return boundsf.width() / boundsf.height(); }; @@ -2626,7 +2646,7 @@ // the header of window margin. EXPECT_NEAR(shadow_ratio(wide_item), item_ratio(wide_item), 0.01f); EXPECT_NEAR(shadow_ratio(tall_item), item_ratio(tall_item), 0.01f); - EXPECT_NEAR(shadow_ratio(normal_item), 1.f, 0.01f); + EXPECT_NEAR(shadow_ratio(normal_item), item_ratio(normal_item), 0.01f); // Verify all the shadows are within the bounds of their respective item // widgets when the overview windows are positioned with animations. @@ -2639,7 +2659,7 @@ EXPECT_NEAR(shadow_ratio(wide_item), item_ratio(wide_item), 0.01f); EXPECT_NEAR(shadow_ratio(tall_item), item_ratio(tall_item), 0.01f); - EXPECT_NEAR(shadow_ratio(normal_item), 1.f, 0.01f); + EXPECT_NEAR(shadow_ratio(normal_item), item_ratio(normal_item), 0.01f); // Test that leaving overview mode cleans up properly. ToggleOverview();
diff --git a/ash/wm/overview/overview_window_drag_controller.cc b/ash/wm/overview/overview_window_drag_controller.cc index 904844d..556495a 100644 --- a/ash/wm/overview/overview_window_drag_controller.cc +++ b/ash/wm/overview/overview_window_drag_controller.cc
@@ -347,10 +347,11 @@ // Expand desks bar when normal drag starts and desks bar is in zero state for // feature Jellyroll. - if (chromeos::features::IsJellyrollEnabled() && - overview_grid->desks_bar_view()->IsZeroState()) { - overview_grid->desks_bar_view()->UpdateNewMiniViews( - /*initializing_bar_view=*/false, /*expanding_bar_view=*/true); + auto* desks_bar_view = overview_grid->desks_bar_view(); + if (desks_bar_view && desks_bar_view->IsZeroState() && + chromeos::features::IsJellyrollEnabled()) { + desks_bar_view->UpdateNewMiniViews(/*initializing_bar_view=*/false, + /*expanding_bar_view=*/true); } item_->UpdateShadowTypeForDrag(/*is_dragging=*/true); @@ -478,7 +479,13 @@ item_->UpdateCannotSnapWarningVisibility(/*animate=*/true); } } - overview_session_->PositionWindows(/*animate=*/true); + + // No need to position windows that are being destroyed. + base::flat_set<OverviewItem*> ignored_items; + if (item_->GetWindow()->is_destroying()) { + ignored_items.insert(item_); + } + overview_session_->PositionWindows(/*animate=*/true, ignored_items); overview_session_->float_container_stacker()->OnDragFinished( item_->GetWindow()); // This function gets called after a long press release, which bypasses @@ -669,8 +676,9 @@ bounds.set_y(centerpoint.y() - bounds.height() / 2.f); item_->SetBounds(bounds, OVERVIEW_ANIMATION_NONE); - if (chromeos::features::IsJellyrollEnabled()) { - auto* new_desk_button = overview_grid->desks_bar_view()->new_desk_button(); + auto* desks_bar_view = overview_grid->desks_bar_view(); + if (desks_bar_view && chromeos::features::IsJellyrollEnabled()) { + auto* new_desk_button = desks_bar_view->new_desk_button(); // When `Jellyroll` is enabled, the header of window is shown during // dragging. Overview item should be hovered on the new desk button with @@ -770,6 +778,7 @@ } } + auto* desks_bar_view = current_grid->desks_bar_view(); // Snap a window if appropriate. if (should_allow_split_view_ && snap_position_ != SplitViewController::SnapPosition::kNone) { @@ -780,8 +789,7 @@ // ended. Thus we need to check whether `overview_session_` is being // shutting down or not here before triggering `MaybeShrinkDesksBarView`. if (!overview_session_->is_shutting_down()) { - if (chromeos::features::IsJellyrollEnabled()) { - auto* desks_bar_view = current_grid->desks_bar_view(); + if (desks_bar_view && chromeos::features::IsJellyrollEnabled()) { desks_bar_view->UpdateDeskIconButtonState( desks_bar_view->new_desk_button(), CrOSNextDeskIconButton::State::kExpanded); @@ -827,8 +835,7 @@ } else { item_->set_should_restack_on_animation_end(true); overview_session_->PositionWindows(/*animate=*/true); - if (chromeos::features::IsJellyrollEnabled()) { - auto* desks_bar_view = current_grid->desks_bar_view(); + if (desks_bar_view && chromeos::features::IsJellyrollEnabled()) { desks_bar_view->UpdateDeskIconButtonState( desks_bar_view->new_desk_button(), CrOSNextDeskIconButton::State::kExpanded);
diff --git a/ash/wm/overview/overview_window_drag_controller.h b/ash/wm/overview/overview_window_drag_controller.h index 5b55090f..ab7ad50 100644 --- a/ash/wm/overview/overview_window_drag_controller.h +++ b/ash/wm/overview/overview_window_drag_controller.h
@@ -108,6 +108,9 @@ float velocity_x, float velocity_y); void ActivateDraggedWindow(); + + // Called when a gesture event is reset or when the dragged window is being + // destroyed. void ResetGesture(); // Resets |overview_session_| to nullptr. It's needed since we defer the
diff --git a/ash/wm/overview/scoped_overview_transform_window.cc b/ash/wm/overview/scoped_overview_transform_window.cc index e150a48c..160a4425 100644 --- a/ash/wm/overview/scoped_overview_transform_window.cc +++ b/ash/wm/overview/scoped_overview_transform_window.cc
@@ -584,10 +584,6 @@ kOverviewItemCornerRadius / scale); } - if (auto* shadow = overview_item_->shadow()) { - shadow->SetRoundedCornerRadius(kOverviewItemCornerRadius); - } - layer->SetRoundedCornerRadius(radii); }
diff --git a/ash/wm/window_mini_view.cc b/ash/wm/window_mini_view.cc index 85adef0..c5e7e74 100644 --- a/ash/wm/window_mini_view.cc +++ b/ash/wm/window_mini_view.cc
@@ -100,8 +100,7 @@ } if (!show) { - RemoveChildView(preview_view_); - delete preview_view_; + RemoveChildViewT(preview_view_); preview_view_ = nullptr; return; }
diff --git a/base/debug/alias.h b/base/debug/alias.h index 8195bfa..77b02f0 100644 --- a/base/debug/alias.h +++ b/base/debug/alias.h
@@ -72,15 +72,16 @@ } // namespace debug -// The canonical definitions/declarations for `strlcpy()` and `u16cstrlcpy()` -// are in //base/strings/string_util.{cc,h}. These prototypes are forward -// declared here to avoid having to include string_utils.h and its transitive -// tree of headers in an otherwise small header (which is itself included in -// some very popular headers). +// The canonical definitions/declarations for `strlcpy()`, `u16cstrlcpy()`, +// and `wcslcpy()` are in //base/strings/string_util.{cc,h}. These prototypes +// are forward declared here to avoid having to include string_utils.h and its +// transitive tree of headers in an otherwise small header (which is itself +// included in some very popular headers). BASE_EXPORT size_t strlcpy(char* dst, const char* src, size_t dst_size); BASE_EXPORT size_t u16cstrlcpy(char16_t* dst, const char16_t* src, size_t dst_size); +BASE_EXPORT size_t wcslcpy(wchar_t* dst, const wchar_t* src, size_t dst_size); } // namespace base @@ -97,6 +98,11 @@ ::base::u16cstrlcpy(var_name, (c_str), std::size(var_name)); \ ::base::debug::Alias(var_name) +#define DEBUG_ALIAS_FOR_WCHARCSTR(var_name, c_str, char_count) \ + wchar_t var_name[char_count]; \ + ::base::wcslcpy(var_name, (c_str), std::size(var_name)); \ + ::base::debug::Alias(var_name) + // Code folding is a linker optimization whereby the linker identifies functions // that are bit-identical and overlays them. This saves space but it leads to // confusing call stacks because multiple symbols are at the same address and
diff --git a/base/process/launch_win.cc b/base/process/launch_win.cc index 3e1516cf..503d60e 100644 --- a/base/process/launch_win.cc +++ b/base/process/launch_win.cc
@@ -17,6 +17,7 @@ #include <ios> #include <limits> +#include "base/debug/alias.h" #include "base/debug/stack_trace.h" #include "base/functional/bind.h" #include "base/functional/callback_helpers.h" @@ -241,6 +242,10 @@ Process LaunchProcess(const CommandLine::StringType& cmdline, const LaunchOptions& options) { + // Retain the command line on the stack for investigating shutdown hangs + // tracked in https://crbug.com/1431378 + DEBUG_ALIAS_FOR_WCHARCSTR(cmdline_for_debugging, cmdline.c_str(), 200); + if (options.elevated) { return LaunchElevatedProcess(base::CommandLine::FromString(cmdline), options.start_hidden, options.wait);
diff --git a/build/fuchsia/linux_internal.sdk.sha1 b/build/fuchsia/linux_internal.sdk.sha1 index c89eb9f..fe91bdc4 100644 --- a/build/fuchsia/linux_internal.sdk.sha1 +++ b/build/fuchsia/linux_internal.sdk.sha1
@@ -1 +1 @@ -12.20230413.1.1 +12.20230413.3.1
diff --git a/cc/BUILD.gn b/cc/BUILD.gn index 05e11fe..d59e047 100644 --- a/cc/BUILD.gn +++ b/cc/BUILD.gn
@@ -366,6 +366,8 @@ "trees/latency_info_swap_promise.h", "trees/latency_info_swap_promise_monitor.cc", "trees/latency_info_swap_promise_monitor.h", + "trees/layer_context.h", + "trees/layer_context_client.h", "trees/layer_tree_frame_sink.cc", "trees/layer_tree_frame_sink.h", "trees/layer_tree_frame_sink_client.h", @@ -381,6 +383,8 @@ "trees/layer_tree_mutator.h", "trees/layer_tree_settings.cc", "trees/layer_tree_settings.h", + "trees/local_layer_context.cc", + "trees/local_layer_context.h", "trees/managed_memory_policy.cc", "trees/managed_memory_policy.h", "trees/mobile_optimized_viewport_util.cc",
diff --git a/cc/animation/animation_host.cc b/cc/animation/animation_host.cc index 91b23dc..9e46a63 100644 --- a/cc/animation/animation_host.cc +++ b/cc/animation/animation_host.cc
@@ -533,16 +533,22 @@ TRACE_EVENT_INSTANT0("cc", "NeedsTickAnimations", TRACE_EVENT_SCOPE_THREAD); bool animated = false; + std::vector<AnimationTimeline*> scroll_timelines; for (auto& kv : id_to_timeline_map_.Read(*this)) { AnimationTimeline* timeline = kv.second.get(); if (timeline->IsScrollTimeline()) { - animated |= timeline->TickScrollLinkedAnimations( - ticking_animations_.Read(*this), scroll_tree, is_active_tree); + scroll_timelines.push_back(timeline); } else { animated |= timeline->TickTimeLinkedAnimations( ticking_animations_.Read(*this), monotonic_time); } } + // Tick the scroll-linked animations last, since a smooth scroll (time-linked) + // might update the scroll offset. + for (auto* timeline : scroll_timelines) { + animated |= timeline->TickScrollLinkedAnimations( + ticking_animations_.Read(*this), scroll_tree, is_active_tree); + } // TODO(majidvp): At the moment we call this for both active and pending // trees similar to other animations. However our final goal is to only call
diff --git a/cc/animation/animation_host_unittest.cc b/cc/animation/animation_host_unittest.cc index a7778f03..06f7d77 100644 --- a/cc/animation/animation_host_unittest.cc +++ b/cc/animation/animation_host_unittest.cc
@@ -416,6 +416,56 @@ host_impl_->TickAnimations(base::TimeTicks(), scroll_tree, false)); } +TEST_F(AnimationHostTest, TickScrollLinkedAnimationSmooth) { + ElementId element_id = element_id_; + const int linked_animation_id = 11; + const int scroll_animation_id = 12; + + client_.RegisterElementId(element_id, ElementListType::ACTIVE); + client_impl_.RegisterElementId(element_id, ElementListType::PENDING); + client_impl_.RegisterElementId(element_id, ElementListType::ACTIVE); + host_impl_->AddAnimationTimeline(timeline_); + + PropertyTrees property_trees(*host_impl_); + property_trees.set_is_main_thread(false); + property_trees.set_is_active(true); + CreateScrollingNodeForElement(element_id, &property_trees); + const auto& scroll_tree = property_trees.scroll_tree(); + + ScrollTimeline::ScrollOffsets scroll_offsets(0, 100); + auto scroll_timeline = ScrollTimeline::Create( + element_id, ScrollTimeline::ScrollDown, scroll_offsets); + + scoped_refptr<Animation> animation = Animation::Create(linked_animation_id); + host_impl_->AddAnimationTimeline(scroll_timeline); + scroll_timeline->AttachAnimation(animation); + animation->AttachElement(element_id); + + AddOpacityTransitionToAnimation(animation.get(), 40, .7f, .3f, true); + auto* keyframe_model = animation->GetKeyframeModel(TargetProperty::OPACITY); + keyframe_model->set_needs_synchronized_start_time(false); + + host_impl_->TickAnimations(base::TimeTicks(), scroll_tree, false); + TickAnimationsTransferEvents(base::TimeTicks(), 1u); + + scoped_refptr<MockAnimation> mock_scroll_animation( + new MockAnimation(scroll_animation_id)); + EXPECT_CALL(*mock_scroll_animation, Tick(_)) + .WillOnce(InvokeWithoutArgs([&]() { + SetScrollOffset(&property_trees, element_id, gfx::PointF(0, 20)); + })); + timeline_->AttachAnimation(mock_scroll_animation); + host_impl_->AddToTicking(mock_scroll_animation); + + // This should tick the scroll animation first, and then the opacity animation + // that depends on the scroll position. + host_impl_->TickAnimations(base::TimeTicks(), scroll_tree, false); + + const float expected_opacity = 0.5; + client_impl_.ExpectOpacityPropertyMutated(element_id, ElementListType::ACTIVE, + expected_opacity); +} + TEST_F(AnimationHostTest, PushPropertiesToImpl) { TestHostClient host_client(ThreadInstance::MAIN); AnimationHost* host = host_client.host();
diff --git a/cc/metrics/average_lag_tracking_manager_unittest.cc b/cc/metrics/average_lag_tracking_manager_unittest.cc index 7548c0f9..c374d8ce 100644 --- a/cc/metrics/average_lag_tracking_manager_unittest.cc +++ b/cc/metrics/average_lag_tracking_manager_unittest.cc
@@ -97,7 +97,7 @@ ui::ET_GESTURE_SCROLL_UPDATE, ui::ScrollInputType::kTouchscreen, kScrollIsNotInertial, scroll_update_type, delta, event_time, arrived_in_browser_main_timestamp, - base::IdType64<class ui::LatencyInfo>(trace_id), base::TimeTicks()); + base::IdType64<class ui::LatencyInfo>(trace_id)); } AverageLagTrackingManager average_lag_tracking_manager_;
diff --git a/cc/metrics/compositor_frame_reporter_unittest.cc b/cc/metrics/compositor_frame_reporter_unittest.cc index 0d8d6a1..7a3c45d 100644 --- a/cc/metrics/compositor_frame_reporter_unittest.cc +++ b/cc/metrics/compositor_frame_reporter_unittest.cc
@@ -103,7 +103,7 @@ if (stage_durations[i] >= 0) { AdvanceNowByUs(stage_durations[i]); metrics->SetDispatchStageTimestamp( - EventMetrics::DispatchStage(i + 2)); + EventMetrics::DispatchStage(i + 1)); } } } @@ -112,11 +112,9 @@ std::unique_ptr<EventMetrics> CreateEventMetrics(ui::EventType type) { const base::TimeTicks event_time = AdvanceNowByUs(3); - const base::TimeTicks arrived_in_browser_main_timestamp = AdvanceNowByUs(2); AdvanceNowByUs(3); - return SetupEventMetrics(EventMetrics::CreateForTesting( - type, event_time, arrived_in_browser_main_timestamp, - &test_tick_clock_)); + return SetupEventMetrics( + EventMetrics::CreateForTesting(type, event_time, &test_tick_clock_)); } // Creates EventMetrics with elements in stage_durations representing each @@ -1586,15 +1584,13 @@ // Test with no previous stage predictions. std::vector<base::TimeDelta> expected_predictions1(kNumDispatchStages, base::Microseconds(-1)); - IntToTimeDeltaVector( - expected_predictions1, - std::vector<int>{/*kScrollsBlockingTouchDispatchedToRenderer=*/-1, - /*kArrivedInBrowserMain=*/300, - /*kArrivedInRendererCompositor=*/300, - /*kRendererCompositorStarted=*/300, - /*kRendererCompositorFinished=*/300, - /*kRendererMainStarted=*/300, - /*kRendererMainFinished=*/300}); + IntToTimeDeltaVector(expected_predictions1, + std::vector<int>{/*kArrivedInBrowserMain=*/300, + /*kArrivedInRendererCompositor=*/300, + /*kRendererCompositorStarted=*/300, + /*kRendererCompositorFinished=*/300, + /*kRendererMainStarted=*/300, + /*kRendererMainFinished=*/300}); base::TimeDelta expected_transition1 = base::Microseconds(300); base::TimeDelta expected_total1 = base::Microseconds(2400); CompositorFrameReporter::EventLatencyInfo actual_predictions1 = @@ -1607,14 +1603,14 @@ std::vector<base::TimeDelta> expected_predictions2(kNumDispatchStages, base::Microseconds(-1)); IntToTimeDeltaVector(expected_predictions2, - std::vector<int>{300, 262, 262, 300, 412, 225, 450}); + std::vector<int>{262, 262, 300, 412, 225, 450}); base::TimeDelta expected_transition2 = base::Microseconds(390); - base::TimeDelta expected_total2 = base::Microseconds(2901); + base::TimeDelta expected_total2 = base::Microseconds(2601); CompositorFrameReporter::EventLatencyInfo actual_predictions2 = CompositorFrameReporter::EventLatencyInfo(kNumDispatchStages, kNumOfCompositorStages); IntToTimeDeltaVector(actual_predictions2.dispatch_durations, - std::vector<int>{300, 250, 250, 300, 450, 200, 500}); + std::vector<int>{250, 250, 300, 450, 200, 500}); actual_predictions2.transition_duration = base::Microseconds(420); pipeline_reporter_->CalculateEventLatencyPrediction( actual_predictions2, kLatencyPredictionDeviationThreshold); @@ -1623,14 +1619,14 @@ std::vector<base::TimeDelta> expected_predictions3(kNumDispatchStages, base::Microseconds(-1)); IntToTimeDeltaVector(expected_predictions3, - std::vector<int>{300, 300, 375, 450, 300, 300, 300}); + std::vector<int>{300, 375, 450, 300, 300, 300}); base::TimeDelta expected_transition3 = base::Microseconds(270); - base::TimeDelta expected_total3 = base::Microseconds(2895); + base::TimeDelta expected_total3 = base::Microseconds(2595); CompositorFrameReporter::EventLatencyInfo actual_predictions3 = CompositorFrameReporter::EventLatencyInfo(kNumDispatchStages, kNumOfCompositorStages); IntToTimeDeltaVector(actual_predictions3.dispatch_durations, - std::vector<int>{300, -1, 400, 500, 300, -1, -1}); + std::vector<int>{-1, 400, 500, 300, -1, -1}); actual_predictions3.transition_duration = base::Microseconds(260); pipeline_reporter_->CalculateEventLatencyPrediction( actual_predictions3, kLatencyPredictionDeviationThreshold); @@ -1692,7 +1688,7 @@ std::vector<base::TimeDelta> expected_predictions1(kNumDispatchStages, base::Microseconds(-1)); IntToTimeDeltaVector(expected_predictions1, - std::vector<int>{-1, 200, 400, 600, 700, -1, -1}); + std::vector<int>{200, 400, 600, 700, -1, -1}); base::TimeDelta expected_transition1 = base::Microseconds(470); base::TimeDelta expected_total1 = base::Microseconds(2670); CompositorFrameReporter::EventLatencyInfo actual_predictions1 = @@ -1705,14 +1701,14 @@ std::vector<base::TimeDelta> expected_predictions2(kNumDispatchStages, base::Microseconds(-1)); IntToTimeDeltaVector(expected_predictions2, - std::vector<int>{100, 125, 250, 375, 475, 200, 500}); + std::vector<int>{125, 250, 375, 475, 200, 500}); base::TimeDelta expected_transition2 = base::Microseconds(402); - base::TimeDelta expected_total2 = base::Microseconds(2727); + base::TimeDelta expected_total2 = base::Microseconds(2627); CompositorFrameReporter::EventLatencyInfo actual_predictions2 = CompositorFrameReporter::EventLatencyInfo(kNumDispatchStages, kNumOfCompositorStages); IntToTimeDeltaVector(actual_predictions2.dispatch_durations, - std::vector<int>{100, 100, 200, 300, 400, 200, 500}); + std::vector<int>{100, 200, 300, 400, 200, 500}); actual_predictions2.transition_duration = base::Microseconds(380); pipeline_reporter_->CalculateEventLatencyPrediction( actual_predictions2, kLatencyPredictionDeviationThreshold); @@ -1721,14 +1717,14 @@ std::vector<base::TimeDelta> expected_predictions3(kNumDispatchStages, base::Microseconds(-1)); IntToTimeDeltaVector(expected_predictions3, - std::vector<int>{125, 143, 400, 525, 745, -1, -1}); + std::vector<int>{143, 400, 525, 745, -1, -1}); base::TimeDelta expected_transition3 = base::Microseconds(492); - base::TimeDelta expected_total3 = base::Microseconds(2730); + base::TimeDelta expected_total3 = base::Microseconds(2605); CompositorFrameReporter::EventLatencyInfo actual_predictions3 = CompositorFrameReporter::EventLatencyInfo(kNumDispatchStages, kNumOfCompositorStages); IntToTimeDeltaVector(actual_predictions3.dispatch_durations, - std::vector<int>{125, 125, 400, 500, 760, -1, -1}); + std::vector<int>{125, 400, 500, 760, -1, -1}); actual_predictions3.transition_duration = base::Microseconds(500); pipeline_reporter_->CalculateEventLatencyPrediction( actual_predictions3, kLatencyPredictionDeviationThreshold); @@ -1800,15 +1796,13 @@ // Test with no previous stage predictions. std::vector<base::TimeDelta> expected_dispatch1(kNumDispatchStages, base::Microseconds(-1)); - IntToTimeDeltaVector( - expected_dispatch1, - std::vector<int>{/*kScrollsBlockingTouchDispatchedToRenderer=*/-1, - /*kArrivedInBrowserMain=*/300, - /*kArrivedInRendererCompositor=*/300, - /*kRendererCompositorStarted=*/300, - /*kRendererCompositorFinished=*/300, - /*kRendererMainStarted=*/300, - /*kRendererMainFinished=*/300}); + IntToTimeDeltaVector(expected_dispatch1, + std::vector<int>{/*kArrivedInBrowserMain=*/300, + /*kArrivedInRendererCompositor=*/300, + /*kRendererCompositorStarted=*/300, + /*kRendererCompositorFinished=*/300, + /*kRendererMainStarted=*/300, + /*kRendererMainFinished=*/300}); base::TimeDelta expected_transition1 = base::Microseconds(300); std::vector<base::TimeDelta> expected_compositor1(kNumOfCompositorStages, base::Microseconds(-1)); @@ -1825,18 +1819,18 @@ std::vector<base::TimeDelta> expected_dispatch2(kNumDispatchStages, base::Microseconds(-1)); IntToTimeDeltaVector(expected_dispatch2, - std::vector<int>{250, 262, 262, 300, 412, 225, 450}); + std::vector<int>{262, 262, 300, 412, 225, 450}); base::TimeDelta expected_transition2 = base::Microseconds(390); std::vector<base::TimeDelta> expected_compositor2(kNumOfCompositorStages, base::Microseconds(-1)); IntToTimeDeltaVector(expected_compositor2, std::vector<int>{465, 500, 90, 720, 410, 742, 390}); - base::TimeDelta expected_total2 = base::Microseconds(5868); + base::TimeDelta expected_total2 = base::Microseconds(5618); CompositorFrameReporter::EventLatencyInfo actual_predictions2 = CompositorFrameReporter::EventLatencyInfo(kNumDispatchStages, kNumOfCompositorStages); IntToTimeDeltaVector(actual_predictions2.dispatch_durations, - std::vector<int>{250, 250, 250, 300, 450, 200, 500}); + std::vector<int>{250, 250, 300, 450, 200, 500}); actual_predictions2.transition_duration = base::Microseconds(420); IntToTimeDeltaVector(actual_predictions2.compositor_durations, std::vector<int>{520, 500, 90, 720, 410, 890, 420}); @@ -1847,18 +1841,18 @@ std::vector<base::TimeDelta> expected_dispatch3(kNumDispatchStages, base::Microseconds(-1)); IntToTimeDeltaVector(expected_dispatch3, - std::vector<int>{400, 375, 375, 450, 300, 300, 300}); + std::vector<int>{375, 375, 450, 300, 300, 300}); base::TimeDelta expected_transition3 = base::Microseconds(270); std::vector<base::TimeDelta> expected_compositor3(kNumOfCompositorStages, base::Microseconds(-1)); IntToTimeDeltaVector(expected_compositor3, std::vector<int>{300, 500, -1, -1, 410, 742, 390}); - base::TimeDelta expected_total3 = base::Microseconds(5112); + base::TimeDelta expected_total3 = base::Microseconds(4712); CompositorFrameReporter::EventLatencyInfo actual_predictions3 = CompositorFrameReporter::EventLatencyInfo(kNumDispatchStages, kNumOfCompositorStages); IntToTimeDeltaVector(actual_predictions3.dispatch_durations, - std::vector<int>{400, 400, 400, 500, 300, -1, -1}); + std::vector<int>{400, 400, 500, 300, -1, -1}); actual_predictions3.transition_duration = base::Microseconds(260); IntToTimeDeltaVector(actual_predictions3.compositor_durations, std::vector<int>{-1, 500, -1, -1, 410, 890, 420}); @@ -1945,23 +1939,21 @@ // Test with no previous stage predictions. std::vector<base::TimeDelta> expected_dispatch1(kNumDispatchStages, base::Microseconds(-1)); - IntToTimeDeltaVector( - expected_dispatch1, - std::vector<int>{/*kScrollsBlockingTouchDispatchedToRenderer=*/-1, - /*kArrivedInBrowserMain=*/300, - /*kArrivedInRendererCompositor=*/300, - /*kRendererCompositorStarted=*/300, - /*kRendererCompositorFinished=*/300, - /*kRendererMainStarted=*/300, - /*kRenderePrMainFinished=*/300}); + IntToTimeDeltaVector(expected_dispatch1, + std::vector<int>{/*kArrivedInBrowserMain=*/300, + /*kArrivedInRendererCompositor=*/300, + /*kRendererCompositorStarted=*/300, + /*kRendererCompositorFinished=*/300, + /*kRendererMainStarted=*/300, + /*kRendererMainFinished=*/300}); base::TimeDelta expected_transition1 = - base::Microseconds(302) + kTouchEventTransition; + base::Microseconds(300) + kTouchEventTransition; std::vector<base::TimeDelta> expected_compositor1(kNumOfCompositorStages, base::Microseconds(-1)); IntToTimeDeltaVector(expected_compositor1, std::vector<int>{300, -1, -1, -1, -1, 300, 300}); base::TimeDelta expected_total1 = - base::Microseconds(3002) + kTouchEventTransition; + base::Microseconds(3000) + kTouchEventTransition; CompositorFrameReporter::EventLatencyInfo actual_predictions1 = CompositorFrameReporter::EventLatencyInfo(kNumDispatchStages, kNumOfCompositorStages); @@ -1972,18 +1964,18 @@ std::vector<base::TimeDelta> expected_dispatch2(kNumDispatchStages, base::Microseconds(-1)); IntToTimeDeltaVector(expected_dispatch2, - std::vector<int>{250, 262, 262, 300, 412, 225, 450}); + std::vector<int>{262, 262, 300, 412, 225, 450}); base::TimeDelta expected_transition2 = base::Microseconds(393); std::vector<base::TimeDelta> expected_compositor2(kNumOfCompositorStages, base::Microseconds(-1)); IntToTimeDeltaVector(expected_compositor2, std::vector<int>{465, 500, 90, 720, 410, 742, 390}); - base::TimeDelta expected_total2 = base::Microseconds(5871); + base::TimeDelta expected_total2 = base::Microseconds(5621); CompositorFrameReporter::EventLatencyInfo actual_predictions2 = CompositorFrameReporter::EventLatencyInfo(kNumDispatchStages, kNumOfCompositorStages); IntToTimeDeltaVector(actual_predictions2.dispatch_durations, - std::vector<int>{250, 250, 250, 300, 450, 200, 500}); + std::vector<int>{250, 250, 300, 450, 200, 500}); actual_predictions2.transition_duration = base::Microseconds(420); IntToTimeDeltaVector(actual_predictions2.compositor_durations, std::vector<int>{520, 500, 90, 720, 410, 890, 420}); @@ -2060,7 +2052,7 @@ CompositorFrameReporter::EventLatencyInfo(kNumDispatchStages, kNumOfCompositorStages); IntToTimeDeltaVector(expected_predictions1.dispatch_durations, - std::vector<int>{-1, 300, 300, 300, 300, 50000, 300}); + std::vector<int>{300, 300, 300, 300, 50000, 300}); expected_predictions1.transition_duration = base::Microseconds(300); IntToTimeDeltaVector(expected_predictions1.compositor_durations, std::vector<int>{300, -1, -1, -1, -1, 50000, 300}); @@ -2083,17 +2075,17 @@ CompositorFrameReporter::EventLatencyInfo(kNumDispatchStages, kNumOfCompositorStages); IntToTimeDeltaVector(expected_predictions2.dispatch_durations, - std::vector<int>{300, 300, 300, 300, 300, 12725, 300}); + std::vector<int>{300, 300, 300, 300, 12725, 300}); expected_predictions2.transition_duration = base::Microseconds(300); IntToTimeDeltaVector(expected_predictions2.compositor_durations, std::vector<int>{300, -1, -1, -1, -1, 50000, 300}); - expected_predictions2.total_duration = base::Microseconds(65425); + expected_predictions2.total_duration = base::Microseconds(65125); CompositorFrameReporter::EventLatencyInfo actual_predictions2 = CompositorFrameReporter::EventLatencyInfo(kNumDispatchStages, kNumOfCompositorStages); IntToTimeDeltaVector(actual_predictions2.dispatch_durations, - std::vector<int>{300, 300, 300, 300, 300, 300, 300}); + std::vector<int>{300, 300, 300, 300, 300, 300}); actual_predictions2.transition_duration = base::Microseconds(300); IntToTimeDeltaVector(actual_predictions2.compositor_durations, std::vector<int>{300, -1, -1, -1, -1, 50000, 300}); @@ -2111,17 +2103,17 @@ CompositorFrameReporter::EventLatencyInfo(kNumDispatchStages, kNumOfCompositorStages); IntToTimeDeltaVector(expected_predictions3.dispatch_durations, - std::vector<int>{300, 300, 300, 300, 300, 12725, 300}); + std::vector<int>{300, 300, 300, 300, 12725, 300}); expected_predictions3.transition_duration = base::Microseconds(300); IntToTimeDeltaVector(expected_predictions3.compositor_durations, std::vector<int>{300, -1, -1, -1, -1, 12725, 300}); - expected_predictions3.total_duration = base::Microseconds(28150); + expected_predictions3.total_duration = base::Microseconds(27850); CompositorFrameReporter::EventLatencyInfo actual_predictions3 = CompositorFrameReporter::EventLatencyInfo(kNumDispatchStages, kNumOfCompositorStages); IntToTimeDeltaVector(actual_predictions3.dispatch_durations, - std::vector<int>{300, 300, 300, 300, 300, 300, 300}); + std::vector<int>{300, 300, 300, 300, 300, 300}); actual_predictions3.transition_duration = base::Microseconds(300); IntToTimeDeltaVector(actual_predictions3.compositor_durations, std::vector<int>{300, -1, -1, -1, -1, 300, 300}); @@ -2140,16 +2132,21 @@ actual_predictions1.dispatch_durations[i]); EXPECT_EQ(expected_predictions2.dispatch_durations[i], actual_predictions2.dispatch_durations[i]); + ; EXPECT_EQ(expected_predictions3.dispatch_durations[i], actual_predictions3.dispatch_durations[i]); + ; } for (int i = 0; i < kNumOfCompositorStages; i++) { EXPECT_EQ(expected_predictions1.compositor_durations[i], actual_predictions1.compositor_durations[i]); + ; EXPECT_EQ(expected_predictions2.compositor_durations[i], actual_predictions2.compositor_durations[i]); + ; EXPECT_EQ(expected_predictions3.compositor_durations[i], actual_predictions3.compositor_durations[i]); + ; } EXPECT_EQ(expected_predictions1.transition_duration, actual_predictions1.transition_duration); @@ -2220,7 +2217,7 @@ CompositorFrameReporter::EventLatencyInfo(kNumDispatchStages, kNumOfCompositorStages); IntToTimeDeltaVector(expected_predictions1.dispatch_durations, - std::vector<int>{-1, 10300, 262, -1, -1, 262, 42500}); + std::vector<int>{10300, 262, -1, -1, 262, 42500}); expected_predictions1.transition_duration = base::Microseconds(300); IntToTimeDeltaVector(expected_predictions1.compositor_durations, std::vector<int>{300, -1, -1, -1, -1, 15200, 300}); @@ -2230,7 +2227,7 @@ CompositorFrameReporter::EventLatencyInfo(kNumDispatchStages, kNumOfCompositorStages); IntToTimeDeltaVector(actual_predictions1.dispatch_durations, - std::vector<int>{-1, 400, 300, -1, -1, 300, 40000}); + std::vector<int>{400, 300, -1, -1, 300, 40000}); actual_predictions1.transition_duration = base::Microseconds(300); IntToTimeDeltaVector(actual_predictions1.compositor_durations, std::vector<int>{300, -1, -1, -1, -1, 3600, 300}); @@ -2251,18 +2248,18 @@ CompositorFrameReporter::EventLatencyInfo(kNumDispatchStages, kNumOfCompositorStages); IntToTimeDeltaVector(expected_predictions2.dispatch_durations, - std::vector<int>{300, 10225, 262, -1, -1, 262, 12725}); + std::vector<int>{10225, 262, -1, -1, 262, 12725}); expected_predictions2.transition_duration = base::Microseconds(300); IntToTimeDeltaVector(expected_predictions2.compositor_durations, std::vector<int>{300, -1, -1, -1, -1, 12725, 300}); - expected_predictions2.total_duration = base::Microseconds(37399); + expected_predictions2.total_duration = base::Microseconds(37099); CompositorFrameReporter::EventLatencyInfo actual_predictions2 = CompositorFrameReporter::EventLatencyInfo(kNumDispatchStages, kNumOfCompositorStages); IntToTimeDeltaVector(actual_predictions2.dispatch_durations, - std::vector<int>{300, 300, 300, -1, -1, 300, 300}); + std::vector<int>{300, 300, -1, -1, 300, 300}); actual_predictions2.transition_duration = base::Microseconds(300); IntToTimeDeltaVector(actual_predictions2.compositor_durations, std::vector<int>{300, -1, -1, -1, -1, 300, 300});
diff --git a/cc/metrics/compositor_frame_reporting_controller_unittest.cc b/cc/metrics/compositor_frame_reporting_controller_unittest.cc index 142335b..654e1dc 100644 --- a/cc/metrics/compositor_frame_reporting_controller_unittest.cc +++ b/cc/metrics/compositor_frame_reporting_controller_unittest.cc
@@ -253,11 +253,9 @@ std::unique_ptr<EventMetrics> CreateEventMetrics(ui::EventType type) { const base::TimeTicks event_time = AdvanceNowByMs(10); - const base::TimeTicks arrived_in_browser_main_timestamp = AdvanceNowByMs(3); AdvanceNowByMs(10); - return SetupEventMetrics(EventMetrics::CreateForTesting( - type, event_time, arrived_in_browser_main_timestamp, - &test_tick_clock_)); + return SetupEventMetrics( + EventMetrics::CreateForTesting(type, event_time, &test_tick_clock_)); } std::unique_ptr<EventMetrics> CreateScrollBeginEventMetrics(
diff --git a/cc/metrics/event_latency_tracing_recorder.cc b/cc/metrics/event_latency_tracing_recorder.cc index 7d8d11ac0..6877c9d6 100644 --- a/cc/metrics/event_latency_tracing_recorder.cc +++ b/cc/metrics/event_latency_tracing_recorder.cc
@@ -63,26 +63,12 @@ switch (start_stage) { case EventMetrics::DispatchStage::kGenerated: switch (end_stage) { - case EventMetrics::DispatchStage:: - kScrollsBlockingTouchDispatchedToRenderer: case EventMetrics::DispatchStage::kArrivedInBrowserMain: return "GenerationToBrowserMain"; case EventMetrics::DispatchStage::kArrivedInRendererCompositor: return "GenerationToRendererCompositor"; default: - NOTREACHED() << static_cast<int>(end_stage); - return ""; - } - case EventMetrics::DispatchStage::kScrollsBlockingTouchDispatchedToRenderer: - switch (end_stage) { - case EventMetrics::DispatchStage::kArrivedInBrowserMain: - // This stage can only be in a Scroll EventLatency. It means a path of - // a corresponding blocking TouchMove from BrowserMain To Renderer To - // BrowserMain. Look at the corresponding TouchMove EventLatency for - // a more detailed breakdown of this stage. - return "TouchRendererHandlingToBrowserMain"; - default: - NOTREACHED() << static_cast<int>(end_stage); + NOTREACHED(); return ""; } case EventMetrics::DispatchStage::kArrivedInBrowserMain: @@ -96,7 +82,7 @@ case EventMetrics::DispatchStage::kRendererMainStarted: return "RendererCompositorToMain"; default: - NOTREACHED() << static_cast<int>(end_stage); + NOTREACHED(); return ""; } case EventMetrics::DispatchStage::kRendererCompositorStarted:
diff --git a/cc/metrics/event_metrics.cc b/cc/metrics/event_metrics.cc index 882896b..14d56dd6 100644 --- a/cc/metrics/event_metrics.cc +++ b/cc/metrics/event_metrics.cc
@@ -213,14 +213,6 @@ // static std::unique_ptr<EventMetrics> EventMetrics::Create(ui::EventType type, base::TimeTicks timestamp) { - return Create(type, timestamp, base::TimeTicks()); -} - -// static -std::unique_ptr<EventMetrics> EventMetrics::Create( - ui::EventType type, - base::TimeTicks timestamp, - base::TimeTicks arrived_in_browser_main_timestamp) { // TODO(crbug.com/1157090): We expect that `timestamp` is not null, but there // seems to be some tests that are emitting events with null timestamp. We // should investigate and try to fix those cases and add a `DCHECK` here to @@ -229,8 +221,7 @@ DCHECK(!IsGestureScroll(type) && !IsGesturePinch(type)); std::unique_ptr<EventMetrics> metrics = - CreateInternal(type, timestamp, arrived_in_browser_main_timestamp, - base::DefaultTickClock::GetInstance()); + CreateInternal(type, timestamp, base::DefaultTickClock::GetInstance()); if (!metrics) return nullptr; @@ -243,12 +234,11 @@ std::unique_ptr<EventMetrics> EventMetrics::CreateForTesting( ui::EventType type, base::TimeTicks timestamp, - base::TimeTicks arrived_in_browser_main_timestamp, const base::TickClock* tick_clock) { DCHECK(!timestamp.is_null()); std::unique_ptr<EventMetrics> metrics = - CreateInternal(type, timestamp, base::TimeTicks(), tick_clock); + CreateInternal(type, timestamp, tick_clock); if (!metrics) return nullptr; @@ -270,8 +260,8 @@ if (!existing) return nullptr; - std::unique_ptr<EventMetrics> metrics = CreateInternal( - type, base::TimeTicks(), base::TimeTicks(), existing->tick_clock_); + std::unique_ptr<EventMetrics> metrics = + CreateInternal(type, base::TimeTicks(), existing->tick_clock_); if (!metrics) return nullptr; @@ -286,16 +276,14 @@ std::unique_ptr<EventMetrics> EventMetrics::CreateInternal( ui::EventType type, base::TimeTicks timestamp, - base::TimeTicks arrived_in_browser_main_timestamp, const base::TickClock* tick_clock) { absl::optional<EventType> interesting_type = ToInterestingEventType(type, /*scroll_is_inertial=*/absl::nullopt, /*scroll_update_type=*/absl::nullopt); if (!interesting_type) return nullptr; - return base::WrapUnique(new EventMetrics(*interesting_type, timestamp, - arrived_in_browser_main_timestamp, - tick_clock)); + return base::WrapUnique( + new EventMetrics(*interesting_type, timestamp, tick_clock)); } EventMetrics::EventMetrics(EventType type, @@ -355,13 +343,6 @@ tick_clock_->NowTicks(); } -void EventMetrics::SetDispatchStageTimestamp(DispatchStage stage, - base::TimeTicks timestamp) { - DCHECK(dispatch_stage_timestamps_[static_cast<size_t>(stage)].is_null()); - - dispatch_stage_timestamps_[static_cast<size_t>(stage)] = timestamp; -} - base::TimeTicks EventMetrics::GetDispatchStageTimestamp( DispatchStage stage) const { return dispatch_stage_timestamps_[static_cast<size_t>(stage)]; @@ -424,8 +405,7 @@ ui::ScrollInputType input_type, bool is_inertial, base::TimeTicks timestamp, - base::TimeTicks arrived_in_browser_main_timestamp, - base::TimeTicks blocking_touch_dispatched_to_renderer) { + base::TimeTicks arrived_in_browser_main_timestamp) { // TODO(crbug.com/1157090): We expect that `timestamp` is not null, but there // seems to be some tests that are emitting events with null timestamp. We // should investigate and try to fix those cases and add a `DCHECK` here to @@ -441,9 +421,6 @@ metrics->SetDispatchStageTimestamp( DispatchStage::kArrivedInRendererCompositor); - metrics->SetDispatchStageTimestamp( - DispatchStage::kScrollsBlockingTouchDispatchedToRenderer, - blocking_touch_dispatched_to_renderer); return metrics; } @@ -453,9 +430,7 @@ ui::ScrollInputType input_type, bool is_inertial, base::TimeTicks timestamp) { - return Create(type, input_type, is_inertial, timestamp, - /*arrived_in_browser_main_timestamp=*/base::TimeTicks(), - /*blocking_touch_dispatched_to_renderer=*/base::TimeTicks()); + return Create(type, input_type, is_inertial, timestamp, base::TimeTicks()); } // static @@ -569,8 +544,7 @@ float delta, base::TimeTicks timestamp, base::TimeTicks arrived_in_browser_main_timestamp, - TraceId trace_id, - base::TimeTicks blocking_touch_dispatched_to_renderer) { + TraceId trace_id) { // TODO(crbug.com/1157090): We expect that `timestamp` is not null, but there // seems to be some tests that are emitting events with null timestamp. We // should investigate and try to fix those cases and add a `DCHECK` here to @@ -587,9 +561,6 @@ metrics->SetDispatchStageTimestamp( DispatchStage::kArrivedInRendererCompositor); - metrics->SetDispatchStageTimestamp( - DispatchStage::kScrollsBlockingTouchDispatchedToRenderer, - blocking_touch_dispatched_to_renderer); return metrics; } @@ -602,10 +573,8 @@ float delta, base::TimeTicks timestamp, TraceId trace_id) { - return Create( - type, input_type, is_inertial, scroll_update_type, delta, timestamp, - /*arrived_in_browser_main_timestamp=*/base::TimeTicks(), trace_id, - /*blocking_touch_dispatched_to_renderer=*/base::TimeTicks()); + return Create(type, input_type, is_inertial, scroll_update_type, delta, + timestamp, base::TimeTicks(), trace_id); } // static
diff --git a/cc/metrics/event_metrics.h b/cc/metrics/event_metrics.h index 480fe35..1b1d68b 100644 --- a/cc/metrics/event_metrics.h +++ b/cc/metrics/event_metrics.h
@@ -68,11 +68,6 @@ // Stages of event dispatch in different processes/threads. enum class DispatchStage { kGenerated, - // 'kScrollsBlockingTouchDispatchedToRenderer' is used by Scroll events to - // understand when a corresponding TouchMove event arrived in the Browser - // Main. If the related TouchMove wasn't blocking, this stage field is not - // set. - kScrollsBlockingTouchDispatchedToRenderer, kArrivedInBrowserMain, kArrivedInRendererCompositor, kRendererCompositorStarted, @@ -82,22 +77,16 @@ kMaxValue = kRendererMainFinished, }; - static std::unique_ptr<EventMetrics> Create(ui::EventType type, - base::TimeTicks timestamp); - // Returns a new instance if the event is of a type we are interested in. // Otherwise, returns `nullptr`. For scroll and pinch events, use the // appropriate subcalss instead. - static std::unique_ptr<EventMetrics> Create( - ui::EventType type, - base::TimeTicks timestamp, - base::TimeTicks arrived_in_browser_main_timestamp); + static std::unique_ptr<EventMetrics> Create(ui::EventType type, + base::TimeTicks timestamp); // Similar to `Create()` with an extra `base::TickClock` to use in tests. static std::unique_ptr<EventMetrics> CreateForTesting( ui::EventType type, base::TimeTicks timestamp, - base::TimeTicks arrived_in_browser_main_timestamp, const base::TickClock* tick_clock); // Used to create an instance for an event generated based on an existing @@ -193,9 +182,6 @@ void CopyTimestampsFrom(const EventMetrics& other, DispatchStage last_dispatch_stage); - void SetDispatchStageTimestamp(DispatchStage stage, - base::TimeTicks timestamp); - private: friend class ScrollEventMetrics; friend class ScrollUpdateEventMetrics; @@ -203,7 +189,6 @@ static std::unique_ptr<EventMetrics> CreateInternal( ui::EventType type, base::TimeTicks timestamp, - base::TimeTicks arrived_in_browser_main_timestamp, const base::TickClock* tick_clock); EventType type_; @@ -247,8 +232,6 @@ // Returns a new instance if the event is of a type we are interested in. // Otherwise, returns `nullptr`. Should only be used for scroll events other // than scroll-update. - // The |blocking_touch_dispatched_to_renderer| must be not null only for - // scrolls which corresponding TouchMove was blocking. // // TODO(b/224960731): Fix tests and stop supporting the case when // `arrived_in_browser_main_timestamp` is null. @@ -257,13 +240,11 @@ ui::ScrollInputType input_type, bool is_inertial, base::TimeTicks timestamp, - base::TimeTicks arrived_in_browser_main_timestamp, - base::TimeTicks blocking_touch_dispatched_to_renderer); + base::TimeTicks arrived_in_browser_main_timestamp); // Prefer to use `Create()` above. This method is used only by the Browser // process which have own breakdowns. - // Similar to `Create()` above but doesn't set kArrivedInBrowserMain and - // kScrollsBlockingTouchDispatchedToRenderer. + // Similar to `Create()` above but doesn't set kArrivedInBrowserMain. static std::unique_ptr<ScrollEventMetrics> CreateForBrowser( ui::EventType type, ui::ScrollInputType input_type, @@ -338,8 +319,6 @@ // Returns a new instance if the event is of a type we are interested in. // Otherwise, returns `nullptr`. Should only be used for scroll-update events. - // The |blocking_touch_dispatched_to_renderer| must be not null only for - // scrolls which corresponding TouchMove was blocking. // // TODO(b/224960731): Fix tests and stop supporting the case when // `arrived_in_browser_main_timestamp` is null. @@ -351,13 +330,11 @@ float delta, base::TimeTicks timestamp, base::TimeTicks arrived_in_browser_main_timestamp, - TraceId trace_id, - base::TimeTicks blocking_touch_dispatched_to_renderer); + TraceId trace_id); // Prefer to use `Create()` above. This method is used only by the Browser // process which have own breakdowns. - // Similar to `Create()` above but doesn't set kArrivedInBrowserMain and - // kScrollsBlockingTouchDispatchedToRenderer. + // Similar to `Create()` above but doesn't set kArrivedInBrowserMain. static std::unique_ptr<ScrollUpdateEventMetrics> CreateForBrowser( ui::EventType type, ui::ScrollInputType input_type,
diff --git a/cc/metrics/event_metrics_unittest.cc b/cc/metrics/event_metrics_unittest.cc index 81e88c7..758e9c7 100644 --- a/cc/metrics/event_metrics_unittest.cc +++ b/cc/metrics/event_metrics_unittest.cc
@@ -25,7 +25,6 @@ TEST_F(EventMetricsTest, ScrollBeginCreateWithNullBeginRwhTime) { // Arrange base::TimeTicks event_time = base::TimeTicks::Now() - base::Microseconds(100); - base::TimeTicks blocking_touch_dispatched_to_renderer_timestamp; base::TimeTicks arrived_in_browser_main_timestamp; base::TimeTicks now = base::TimeTicks::Now(); @@ -33,8 +32,7 @@ std::unique_ptr<ScrollEventMetrics> scroll_event_metric = ScrollEventMetrics::Create( ui::ET_GESTURE_SCROLL_BEGIN, ui::ScrollInputType::kTouchscreen, - /*is_inertial=*/false, event_time, arrived_in_browser_main_timestamp, - blocking_touch_dispatched_to_renderer_timestamp); + /*is_inertial=*/false, event_time, arrived_in_browser_main_timestamp); // Assert EXPECT_EQ(event_time, scroll_event_metric->GetDispatchStageTimestamp( @@ -45,11 +43,6 @@ // not set EXPECT_TRUE(scroll_event_metric ->GetDispatchStageTimestamp( - EventMetrics::DispatchStage:: - kScrollsBlockingTouchDispatchedToRenderer) - .is_null()); - EXPECT_TRUE(scroll_event_metric - ->GetDispatchStageTimestamp( EventMetrics::DispatchStage::kArrivedInBrowserMain) .is_null()); EXPECT_TRUE(scroll_event_metric @@ -73,8 +66,6 @@ TEST_F(EventMetricsTest, ScrollBeginCreate) { // Arrange base::TimeTicks event_time = base::TimeTicks::Now() - base::Microseconds(100); - base::TimeTicks blocking_touch_dispatched_to_renderer_timestamp = - base::TimeTicks::Now() - base::Microseconds(70); base::TimeTicks arrived_in_browser_main_timestamp = base::TimeTicks::Now() - base::Microseconds(50); base::TimeTicks now = base::TimeTicks::Now(); @@ -83,16 +74,11 @@ std::unique_ptr<ScrollEventMetrics> scroll_event_metric = ScrollEventMetrics::Create( ui::ET_GESTURE_SCROLL_BEGIN, ui::ScrollInputType::kTouchscreen, - /*is_inertial=*/false, event_time, arrived_in_browser_main_timestamp, - blocking_touch_dispatched_to_renderer_timestamp); + /*is_inertial=*/false, event_time, arrived_in_browser_main_timestamp); // Assert EXPECT_EQ(event_time, scroll_event_metric->GetDispatchStageTimestamp( EventMetrics::DispatchStage::kGenerated)); - EXPECT_EQ(blocking_touch_dispatched_to_renderer_timestamp, - scroll_event_metric->GetDispatchStageTimestamp( - EventMetrics::DispatchStage:: - kScrollsBlockingTouchDispatchedToRenderer)); EXPECT_EQ(arrived_in_browser_main_timestamp, scroll_event_metric->GetDispatchStageTimestamp( EventMetrics::DispatchStage::kArrivedInBrowserMain)); @@ -121,15 +107,12 @@ TEST_F(EventMetricsTest, ScrollBeginCreateFromExisting) { // Arrange base::TimeTicks event_time = base::TimeTicks::Now() - base::Microseconds(100); - base::TimeTicks blocking_touch_dispatched_to_renderer_timestamp = - base::TimeTicks::Now() - base::Microseconds(70); base::TimeTicks arrived_in_browser_main_timestamp = base::TimeTicks::Now() - base::Microseconds(50); std::unique_ptr<ScrollEventMetrics> scroll_metric = ScrollEventMetrics::Create( ui::ET_GESTURE_SCROLL_BEGIN, ui::ScrollInputType::kTouchscreen, - /*is_inertial=*/false, event_time, arrived_in_browser_main_timestamp, - blocking_touch_dispatched_to_renderer_timestamp); + /*is_inertial=*/false, event_time, arrived_in_browser_main_timestamp); // Act std::unique_ptr<ScrollEventMetrics> copy_scroll_metric = @@ -145,12 +128,6 @@ copy_scroll_metric->GetDispatchStageTimestamp( EventMetrics::DispatchStage::kGenerated)); EXPECT_EQ(scroll_metric->GetDispatchStageTimestamp( - EventMetrics::DispatchStage:: - kScrollsBlockingTouchDispatchedToRenderer), - copy_scroll_metric->GetDispatchStageTimestamp( - EventMetrics::DispatchStage:: - kScrollsBlockingTouchDispatchedToRenderer)); - EXPECT_EQ(scroll_metric->GetDispatchStageTimestamp( EventMetrics::DispatchStage::kArrivedInBrowserMain), copy_scroll_metric->GetDispatchStageTimestamp( EventMetrics::DispatchStage::kArrivedInBrowserMain)); @@ -184,7 +161,6 @@ TEST_F(EventMetricsTest, ScrollUpdateCreateWithNullBeginRwhTime) { // Arrange base::TimeTicks event_time = base::TimeTicks::Now() - base::Microseconds(100); - base::TimeTicks blocking_touch_dispatched_to_renderer_timestamp; base::TimeTicks arrived_in_browser_main_timestamp; base::TimeTicks now = base::TimeTicks::Now(); TraceId trace_id(123); @@ -195,8 +171,7 @@ ui::ET_GESTURE_SCROLL_UPDATE, ui::ScrollInputType::kTouchscreen, /*is_inertial=*/false, ScrollUpdateEventMetrics::ScrollUpdateType::kContinued, /*delta=*/0.4, - event_time, arrived_in_browser_main_timestamp, trace_id, - blocking_touch_dispatched_to_renderer_timestamp); + event_time, arrived_in_browser_main_timestamp, trace_id); // Assert EXPECT_EQ(trace_id, scroll_event_metric->trace_id()); @@ -208,11 +183,6 @@ // not set EXPECT_TRUE(scroll_event_metric ->GetDispatchStageTimestamp( - EventMetrics::DispatchStage:: - kScrollsBlockingTouchDispatchedToRenderer) - .is_null()); - EXPECT_TRUE(scroll_event_metric - ->GetDispatchStageTimestamp( EventMetrics::DispatchStage::kArrivedInBrowserMain) .is_null()); EXPECT_TRUE(scroll_event_metric @@ -236,8 +206,6 @@ TEST_F(EventMetricsTest, ScrollUpdateCreate) { // Arrange base::TimeTicks event_time = base::TimeTicks::Now() - base::Microseconds(100); - base::TimeTicks blocking_touch_dispatched_to_renderer_timestamp = - base::TimeTicks::Now() - base::Microseconds(70); base::TimeTicks arrived_in_browser_main_timestamp = base::TimeTicks::Now() - base::Microseconds(50); base::TimeTicks now = base::TimeTicks::Now(); @@ -249,17 +217,12 @@ ui::ET_GESTURE_SCROLL_UPDATE, ui::ScrollInputType::kTouchscreen, /*is_inertial=*/false, ScrollUpdateEventMetrics::ScrollUpdateType::kContinued, /*delta=*/0.4, - event_time, arrived_in_browser_main_timestamp, TraceId(trace_id), - blocking_touch_dispatched_to_renderer_timestamp); + event_time, arrived_in_browser_main_timestamp, TraceId(trace_id)); // Assert EXPECT_EQ(trace_id, scroll_event_metric->trace_id()); EXPECT_EQ(event_time, scroll_event_metric->GetDispatchStageTimestamp( EventMetrics::DispatchStage::kGenerated)); - EXPECT_EQ(blocking_touch_dispatched_to_renderer_timestamp, - scroll_event_metric->GetDispatchStageTimestamp( - EventMetrics::DispatchStage:: - kScrollsBlockingTouchDispatchedToRenderer)); EXPECT_EQ(arrived_in_browser_main_timestamp, scroll_event_metric->GetDispatchStageTimestamp( EventMetrics::DispatchStage::kArrivedInBrowserMain)); @@ -288,8 +251,6 @@ TEST_F(EventMetricsTest, ScrollUpdateCreateFromExisting) { // Arrange base::TimeTicks event_time = base::TimeTicks::Now() - base::Microseconds(100); - base::TimeTicks blocking_touch_dispatched_to_renderer_timestamp = - base::TimeTicks::Now() - base::Microseconds(70); base::TimeTicks arrived_in_browser_main_timestamp = base::TimeTicks::Now() - base::Microseconds(50); TraceId trace_id(123); @@ -298,8 +259,7 @@ ui::ET_GESTURE_SCROLL_UPDATE, ui::ScrollInputType::kTouchscreen, /*is_inertial=*/false, ScrollUpdateEventMetrics::ScrollUpdateType::kContinued, /*delta=*/0.4, - event_time, arrived_in_browser_main_timestamp, trace_id, - blocking_touch_dispatched_to_renderer_timestamp); + event_time, arrived_in_browser_main_timestamp, trace_id); // Act std::unique_ptr<ScrollUpdateEventMetrics> copy_scroll_metric = @@ -317,12 +277,6 @@ copy_scroll_metric->GetDispatchStageTimestamp( EventMetrics::DispatchStage::kGenerated)); EXPECT_EQ(scroll_metric->GetDispatchStageTimestamp( - EventMetrics::DispatchStage:: - kScrollsBlockingTouchDispatchedToRenderer), - copy_scroll_metric->GetDispatchStageTimestamp( - EventMetrics::DispatchStage:: - kScrollsBlockingTouchDispatchedToRenderer)); - EXPECT_EQ(scroll_metric->GetDispatchStageTimestamp( EventMetrics::DispatchStage::kArrivedInBrowserMain), copy_scroll_metric->GetDispatchStageTimestamp( EventMetrics::DispatchStage::kArrivedInBrowserMain)); @@ -353,95 +307,5 @@ EventMetrics::DispatchStage::kRendererMainFinished)); } -TEST_F(EventMetricsTest, Create) { - // Arrange - base::TimeTicks event_time = base::TimeTicks::Now() - base::Microseconds(100); - base::TimeTicks arrived_in_browser_main_timestamp = - base::TimeTicks::Now() - base::Microseconds(50); - base::TimeTicks now = base::TimeTicks::Now(); - - // Act - std::unique_ptr<EventMetrics> event_metric = EventMetrics::Create( - ui::ET_TOUCH_MOVED, event_time, arrived_in_browser_main_timestamp); - - // Assert - EXPECT_EQ(event_time, event_metric->GetDispatchStageTimestamp( - EventMetrics::DispatchStage::kGenerated)); - EXPECT_EQ(arrived_in_browser_main_timestamp, - event_metric->GetDispatchStageTimestamp( - EventMetrics::DispatchStage::kArrivedInBrowserMain)); - EXPECT_LE(now, - event_metric->GetDispatchStageTimestamp( - EventMetrics::DispatchStage::kArrivedInRendererCompositor)); - // not set - EXPECT_TRUE(event_metric - ->GetDispatchStageTimestamp( - EventMetrics::DispatchStage::kRendererCompositorStarted) - .is_null()); - EXPECT_TRUE(event_metric - ->GetDispatchStageTimestamp( - EventMetrics::DispatchStage::kRendererCompositorFinished) - .is_null()); - EXPECT_TRUE(event_metric - ->GetDispatchStageTimestamp( - EventMetrics::DispatchStage::kRendererMainStarted) - .is_null()); - EXPECT_TRUE(event_metric - ->GetDispatchStageTimestamp( - EventMetrics::DispatchStage::kRendererMainFinished) - .is_null()); -} - -TEST_F(EventMetricsTest, CreateFromExisting) { - // Arrange - base::TimeTicks event_time = base::TimeTicks::Now() - base::Microseconds(100); - base::TimeTicks arrived_in_browser_main_timestamp = - base::TimeTicks::Now() - base::Microseconds(50); - std::unique_ptr<EventMetrics> event_metric = EventMetrics::Create( - ui::ET_TOUCH_MOVED, event_time, arrived_in_browser_main_timestamp); - - // Act - std::unique_ptr<EventMetrics> copy_event_metric = - EventMetrics::CreateFromExisting( - ui::ET_TOUCH_MOVED, - EventMetrics::DispatchStage::kRendererMainFinished, - event_metric.get()); - - // Assert - EXPECT_EQ(event_metric->GetDispatchStageTimestamp( - EventMetrics::DispatchStage::kGenerated), - copy_event_metric->GetDispatchStageTimestamp( - EventMetrics::DispatchStage::kGenerated)); - EXPECT_EQ(event_metric->GetDispatchStageTimestamp( - EventMetrics::DispatchStage::kArrivedInBrowserMain), - copy_event_metric->GetDispatchStageTimestamp( - EventMetrics::DispatchStage::kArrivedInBrowserMain)); - - EXPECT_EQ(event_metric->GetDispatchStageTimestamp( - EventMetrics::DispatchStage::kArrivedInRendererCompositor), - copy_event_metric->GetDispatchStageTimestamp( - EventMetrics::DispatchStage::kArrivedInRendererCompositor)); - - EXPECT_EQ(event_metric->GetDispatchStageTimestamp( - EventMetrics::DispatchStage::kRendererCompositorStarted), - copy_event_metric->GetDispatchStageTimestamp( - EventMetrics::DispatchStage::kRendererCompositorStarted)); - - EXPECT_EQ(event_metric->GetDispatchStageTimestamp( - EventMetrics::DispatchStage::kRendererCompositorFinished), - copy_event_metric->GetDispatchStageTimestamp( - EventMetrics::DispatchStage::kRendererCompositorFinished)); - - EXPECT_EQ(event_metric->GetDispatchStageTimestamp( - EventMetrics::DispatchStage::kRendererMainStarted), - copy_event_metric->GetDispatchStageTimestamp( - EventMetrics::DispatchStage::kRendererMainStarted)); - - EXPECT_EQ(event_metric->GetDispatchStageTimestamp( - EventMetrics::DispatchStage::kRendererMainFinished), - copy_event_metric->GetDispatchStageTimestamp( - EventMetrics::DispatchStage::kRendererMainFinished)); -} - } // namespace } // namespace cc
diff --git a/cc/metrics/events_metrics_manager_unittest.cc b/cc/metrics/events_metrics_manager_unittest.cc index 713705c..2692020 100644 --- a/cc/metrics/events_metrics_manager_unittest.cc +++ b/cc/metrics/events_metrics_manager_unittest.cc
@@ -54,12 +54,8 @@ std::unique_ptr<EventMetrics> CreateEventMetrics(ui::EventType type) { test_tick_clock_.Advance(base::Microseconds(10)); base::TimeTicks event_time = test_tick_clock_.NowTicks(); - test_tick_clock_.Advance(base::Microseconds(5)); - base::TimeTicks arrived_in_browser_main_timestamp = - test_tick_clock_.NowTicks(); test_tick_clock_.Advance(base::Microseconds(10)); - return EventMetrics::CreateForTesting( - type, event_time, arrived_in_browser_main_timestamp, &test_tick_clock_); + return EventMetrics::CreateForTesting(type, event_time, &test_tick_clock_); } EventsMetricsManager manager_;
diff --git a/cc/mojo_embedder/BUILD.gn b/cc/mojo_embedder/BUILD.gn index 32c65d2..152c647 100644 --- a/cc/mojo_embedder/BUILD.gn +++ b/cc/mojo_embedder/BUILD.gn
@@ -9,6 +9,8 @@ sources = [ "async_layer_tree_frame_sink.cc", "async_layer_tree_frame_sink.h", + "viz_layer_context.cc", + "viz_layer_context.h", ] defines = [ "CC_MOJO_EMBEDDER_IMPLEMENTATION" ]
diff --git a/cc/mojo_embedder/viz_layer_context.cc b/cc/mojo_embedder/viz_layer_context.cc new file mode 100644 index 0000000..8b74d2cab --- /dev/null +++ b/cc/mojo_embedder/viz_layer_context.cc
@@ -0,0 +1,49 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "cc/mojo_embedder/viz_layer_context.h" + +#include <utility> + +#include "base/check.h" +#include "cc/trees/layer_context_client.h" +#include "services/viz/public/mojom/compositing/layer_context.mojom.h" + +namespace cc::mojo_embedder { + +VizLayerContext::VizLayerContext(viz::mojom::CompositorFrameSink& frame_sink, + cc::LayerContextClient* client) + : client_(client) { + CHECK(client_); + auto context = viz::mojom::PendingLayerContext::New(); + context->receiver = service_.BindNewEndpointAndPassReceiver(); + context->client = client_receiver_.BindNewEndpointAndPassRemote(); + frame_sink.BindLayerContext(std::move(context)); +} + +VizLayerContext::~VizLayerContext() = default; + +void VizLayerContext::SetTargetLocalSurfaceId(const viz::LocalSurfaceId& id) { + service_->SetTargetLocalSurfaceId(id); +} + +void VizLayerContext::SetVisible(bool visible) { + service_->SetVisible(visible); +} + +void VizLayerContext::Commit(const CommitState& state) { + // TODO(https://crbug.com/1431762): Push actual commit data. For now we only + // update basic parameters required for any LayerTreeHost drawing. + auto update = viz::mojom::LayerTreeUpdate::New(); + update->device_viewport = state.device_viewport_rect; + update->device_scale_factor = state.device_scale_factor; + update->local_surface_id_from_parent = state.local_surface_id_from_parent; + service_->Commit(std::move(update)); +} + +void VizLayerContext::OnRequestCommitForFrame(const viz::BeginFrameArgs& args) { + client_->OnRequestCommitForFrame(args); +} + +} // namespace cc::mojo_embedder
diff --git a/cc/mojo_embedder/viz_layer_context.h b/cc/mojo_embedder/viz_layer_context.h new file mode 100644 index 0000000..dd246030 --- /dev/null +++ b/cc/mojo_embedder/viz_layer_context.h
@@ -0,0 +1,51 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CC_MOJO_EMBEDDER_VIZ_LAYER_CONTEXT_H_ +#define CC_MOJO_EMBEDDER_VIZ_LAYER_CONTEXT_H_ + +#include "base/memory/raw_ptr.h" +#include "cc/mojo_embedder/mojo_embedder_export.h" +#include "cc/trees/layer_context.h" +#include "mojo/public/cpp/bindings/associated_receiver.h" +#include "mojo/public/cpp/bindings/associated_remote.h" +#include "services/viz/public/mojom/compositing/compositor_frame_sink.mojom.h" +#include "services/viz/public/mojom/compositing/layer_context.mojom.h" + +namespace cc { +class LayerContextClient; +} // namespace cc + +namespace cc::mojo_embedder { + +// A client-side implementation of LayerContext which runs over a Mojo +// connection to a GPU-side LayerContext backend within Viz. +class CC_MOJO_EMBEDDER_EXPORT VizLayerContext + : public LayerContext, + public viz::mojom::LayerContextClient { + public: + // Constructs a VizLayerContext which submits content on behalf of + // `frame_sink`. `client` must outlive this object. + VizLayerContext(viz::mojom::CompositorFrameSink& frame_sink, + cc::LayerContextClient* client); + ~VizLayerContext() override; + + // LayerContext: + void SetTargetLocalSurfaceId(const viz::LocalSurfaceId& id) override; + void SetVisible(bool visible) override; + void Commit(const CommitState& state) override; + + // viz::mojom::LayerContextClient: + void OnRequestCommitForFrame(const viz::BeginFrameArgs& args) override; + + private: + raw_ptr<cc::LayerContextClient> client_; + mojo::AssociatedReceiver<viz::mojom::LayerContextClient> client_receiver_{ + this}; + mojo::AssociatedRemote<viz::mojom::LayerContext> service_; +}; + +} // namespace cc::mojo_embedder + +#endif // CC_MOJO_EMBEDDER_VIZ_LAYER_CONTEXT_H_
diff --git a/cc/slim/test_frame_sink_impl.cc b/cc/slim/test_frame_sink_impl.cc index 84f9e7a7..af27c9d 100644 --- a/cc/slim/test_frame_sink_impl.cc +++ b/cc/slim/test_frame_sink_impl.cc
@@ -17,6 +17,7 @@ #include "mojo/public/cpp/bindings/pending_associated_remote.h" #include "mojo/public/cpp/bindings/pending_receiver.h" #include "services/viz/public/mojom/compositing/compositor_frame_sink.mojom.h" +#include "services/viz/public/mojom/compositing/layer_context.mojom.h" namespace cc::slim { @@ -49,6 +50,7 @@ void DidDeleteSharedBitmap(const gpu::Mailbox& id) override {} void InitializeCompositorFrameSinkType( viz::mojom::CompositorFrameSinkType type) override {} + void BindLayerContext(viz::mojom::PendingLayerContextPtr context) override {} #if BUILDFLAG(IS_ANDROID) void SetThreadIds(const std::vector<int32_t>& thread_ids) override {} #endif
diff --git a/cc/tiles/gpu_image_decode_cache.cc b/cc/tiles/gpu_image_decode_cache.cc index e6d296b..9aef35a 100644 --- a/cc/tiles/gpu_image_decode_cache.cc +++ b/cc/tiles/gpu_image_decode_cache.cc
@@ -693,6 +693,9 @@ const ImageDecodeCache::TracingInfo tracing_info_; }; +//////////////////////////////////////////////////////////////////////////////// +// GpuImageDecodeCache::ImageDataBase + GpuImageDecodeCache::ImageDataBase::ImageDataBase() = default; GpuImageDecodeCache::ImageDataBase::~ImageDataBase() = default; @@ -738,6 +741,90 @@ return state; } +//////////////////////////////////////////////////////////////////////////////// +// GpuImageDecodeCache::DecodedAuxImageData + +GpuImageDecodeCache::DecodedAuxImageData::DecodedAuxImageData() = default; + +GpuImageDecodeCache::DecodedAuxImageData::DecodedAuxImageData( + const SkPixmap& rgba_pixmap, + std::unique_ptr<base::DiscardableMemory> in_data) { + data = std::move(in_data); + auto release_proc = [](const void*, void*) {}; + images[0] = SkImages::RasterFromPixmap(rgba_pixmap, release_proc, nullptr); + pixmaps[0] = rgba_pixmap; + DCHECK(!pixmaps[0].dimensions().isEmpty()); +} + +GpuImageDecodeCache::DecodedAuxImageData::DecodedAuxImageData( + const SkYUVAPixmaps& yuva_pixmaps, + std::unique_ptr<base::DiscardableMemory> in_data) { + data = std::move(in_data); + auto release_proc = [](const void*, void*) {}; + for (int plane = 0; plane < yuva_pixmaps.numPlanes(); ++plane) { + images[plane] = SkImages::RasterFromPixmap(yuva_pixmaps.plane(plane), + release_proc, nullptr); + pixmaps[plane] = yuva_pixmaps.plane(plane); + DCHECK(!pixmaps[plane].dimensions().isEmpty()); + } +} + +GpuImageDecodeCache::DecodedAuxImageData::DecodedAuxImageData( + DecodedAuxImageData&& other) + : data(std::move(other.data)) { + for (int plane = 0; plane < SkYUVAInfo::kMaxPlanes; ++plane) { + images[plane] = std::move(other.images[plane]); + pixmaps[plane] = other.pixmaps[plane]; + } + other.ResetData(); +} + +GpuImageDecodeCache::DecodedAuxImageData& +GpuImageDecodeCache::DecodedAuxImageData::operator=( + DecodedAuxImageData&& other) { + data = std::move(other.data); + for (int plane = 0; plane < SkYUVAInfo::kMaxPlanes; ++plane) { + images[plane] = std::move(other.images[plane]); + pixmaps[plane] = other.pixmaps[plane]; + } + return *this; +} + +GpuImageDecodeCache::DecodedAuxImageData::~DecodedAuxImageData() = default; + +bool GpuImageDecodeCache::DecodedAuxImageData::IsEmpty() const { + if (data) { + DCHECK(images[0]); + DCHECK(pixmaps[0].dimensions().isEmpty()); + return false; + } + // Note that bitmap backed DecodedAuxImageData will have an `images` and + // `pixmaps`, but no data. + for (auto& image : images) { + if (image) { + return false; + } + } + // It is in error for `images` to be empty but for `pixmaps` to not be empty. + for (auto& pixmap : pixmaps) { + DCHECK(pixmap.dimensions().isEmpty()); + } + return true; +} + +void GpuImageDecodeCache::DecodedAuxImageData::ResetData() { + data = nullptr; + for (auto& image : images) { + image = nullptr; + } + for (auto& pixmap : pixmaps) { + pixmap = SkPixmap(); + } +} + +//////////////////////////////////////////////////////////////////////////////// +// GpuImageDecodeCache::DecodedImageData + GpuImageDecodeCache::DecodedImageData::DecodedImageData( bool is_bitmap_backed, bool can_do_hardware_accelerated_decode, @@ -745,61 +832,53 @@ : is_bitmap_backed_(is_bitmap_backed), can_do_hardware_accelerated_decode_(can_do_hardware_accelerated_decode), do_hardware_accelerated_decode_(do_hardware_accelerated_decode) {} + GpuImageDecodeCache::DecodedImageData::~DecodedImageData() { ResetData(); } bool GpuImageDecodeCache::DecodedImageData::Lock() { - if (data_->Lock()) + if (aux_image_data_.data->Lock()) { OnLock(); + } return is_locked_; } void GpuImageDecodeCache::DecodedImageData::Unlock() { - data_->Unlock(); + aux_image_data_.data->Unlock(); OnUnlock(); } void GpuImageDecodeCache::DecodedImageData::SetLockedData( - std::unique_ptr<base::DiscardableMemory> data, - sk_sp<SkImage> images[SkYUVAInfo::kMaxPlanes], + DecodedAuxImageData aux_image_data, bool out_of_raster) { - DCHECK(data); - DCHECK(!data_); - data_ = std::move(data); - for (int i = 0; i < SkYUVAInfo::kMaxPlanes; ++i) { - DCHECK(!images_[i]); - images_[i] = std::move(images[i]); - } - DCHECK(images_[0]); + DCHECK(aux_image_data_.IsEmpty()); + aux_image_data_ = std::move(aux_image_data); + DCHECK(!aux_image_data_.pixmaps[0].dimensions().isEmpty()); OnSetLockedData(out_of_raster); } void GpuImageDecodeCache::DecodedImageData::SetBitmapImage( sk_sp<SkImage> image) { DCHECK(is_bitmap_backed_); - images_[0] = std::move(image); + DCHECK(aux_image_data_.IsEmpty()); + aux_image_data_.images[0] = std::move(image); + aux_image_data_.images[0]->peekPixels(&aux_image_data_.pixmaps[0]); OnLock(); } void GpuImageDecodeCache::DecodedImageData::ResetBitmapImage() { DCHECK(is_bitmap_backed_); // Bitmaps only ever have a single SkImage. - images_[0] = nullptr; - for (auto& image : images_) { - DCHECK(!image); - } + aux_image_data_.ResetData(); OnUnlock(); } void GpuImageDecodeCache::DecodedImageData::ResetData() { - if (data_) { + if (aux_image_data_.data) { ReportUsageStats(); } - for (auto& image : images_) { - image = nullptr; - } - data_ = nullptr; + aux_image_data_.ResetData(); OnResetData(); } @@ -823,6 +902,9 @@ usage_stats_.first_lock_wasted); } +//////////////////////////////////////////////////////////////////////////////// +// GpuImageDecodeCache::UploadedImageData + GpuImageDecodeCache::UploadedImageData::UploadedImageData() = default; GpuImageDecodeCache::UploadedImageData::~UploadedImageData() { DCHECK(!image()); @@ -911,10 +993,34 @@ usage_stats_.first_lock_wasted); } +//////////////////////////////////////////////////////////////////////////////// +// GpuImageDecodeCache::ImageInfo + +GpuImageDecodeCache::ImageInfo::ImageInfo() = default; + +GpuImageDecodeCache::ImageInfo::ImageInfo(const SkImageInfo& rgba) + : rgba(rgba), size(rgba.computeMinByteSize()) { + DCHECK(!SkImageInfo::ByteSizeOverflowed(size)); +} + +GpuImageDecodeCache::ImageInfo::ImageInfo(const SkYUVAPixmapInfo& yuva) + : yuva(yuva), size(yuva.computeTotalBytes()) { + DCHECK(!SkImageInfo::ByteSizeOverflowed(size)); +} + +GpuImageDecodeCache::ImageInfo::ImageInfo(const ImageInfo&) = default; + +GpuImageDecodeCache::ImageInfo& GpuImageDecodeCache::ImageInfo::operator=( + const ImageInfo&) = default; + +GpuImageDecodeCache::ImageInfo::~ImageInfo() = default; + +//////////////////////////////////////////////////////////////////////////////// +// GpuImageDecodeCache::ImageData + GpuImageDecodeCache::ImageData::ImageData( PaintImage::Id paint_image_id, DecodedDataMode mode, - size_t size, const TargetColorParams& target_color_params, PaintFlags::FilterQuality quality, int upload_scale_mip_level, @@ -922,24 +1028,21 @@ bool is_bitmap_backed, bool can_do_hardware_accelerated_decode, bool do_hardware_accelerated_decode, - const SkImageInfo& image_info, - absl::optional<SkYUVAPixmapInfo> yuva_info) + const ImageInfo& info) : paint_image_id(paint_image_id), mode(mode), - size(size), target_color_params(target_color_params), quality(quality), upload_scale_mip_level(upload_scale_mip_level), needs_mips(needs_mips), is_bitmap_backed(is_bitmap_backed), - image_info(image_info), - yuva_pixmap_info(yuva_info), + info(info), decode(is_bitmap_backed, can_do_hardware_accelerated_decode, do_hardware_accelerated_decode) { - if (yuva_pixmap_info.has_value()) { + if (info.yuva.has_value()) { // This is the only plane config supported by non-OOP raster. - DCHECK_EQ(yuva_pixmap_info->yuvaInfo().planeConfig(), + DCHECK_EQ(info.yuva->yuvaInfo().planeConfig(), SkYUVAInfo::PlaneConfig::kY_U_V); } } @@ -967,7 +1070,7 @@ if (upload.image()) { // TODO(915968): Be smarter about being able to re-upload planes // selectively if only some get deleted from under us. - DCHECK(!yuva_pixmap_info.has_value() || upload.has_yuv_planes()); + DCHECK(!info.yuva.has_value() || upload.has_yuv_planes()); return true; } return false; @@ -985,6 +1088,13 @@ DCHECK_GT(upload.ref_count, 0u); } +size_t GpuImageDecodeCache::ImageData::GetSize() const { + return info.size; +} + +//////////////////////////////////////////////////////////////////////////////// +// GpuImageDecodeCache + // static GrGLuint GpuImageDecodeCache::GlIdFromSkImage(const SkImage* image) { DCHECK(image->isTextureBacked()); @@ -1208,7 +1318,7 @@ // Ensure that the image we're about to decode/upload will fit in memory, if // not already budgeted. - if (!image_data->is_budgeted && !EnsureCapacity(image_data->size)) { + if (!image_data->is_budgeted && !EnsureCapacity(image_data->GetSize())) { // Image will not fit, do an at-raster decode. return TaskResult(false /* need_unref */, true /* is_at_raster_decode */, image_data->decode.can_do_hardware_accelerated_decode()); @@ -1462,7 +1572,7 @@ MaybePurgeOldCacheEntries(); WillAddCacheEntry(draw_image); - persistent_cache_memory_size_ += data->size; + persistent_cache_memory_size_ += data->GetSize(); persistent_cache_.Put(draw_image.frame_key(), std::move(data)); } @@ -1494,7 +1604,7 @@ if (entries_it->second.count == 0u) paint_image_entries_.erase(entries_it); - persistent_cache_memory_size_ -= it->second->size; + persistent_cache_memory_size_ -= it->second->GetSize(); return persistent_cache_.Erase(it); } @@ -1554,7 +1664,7 @@ const std::string& dump_base_name, size_t locked_size) const { using base::trace_event::MemoryAllocatorDump; - DCHECK(image_data->yuva_pixmap_info.has_value()); + DCHECK(image_data->info.yuva.has_value()); DCHECK(image_data->upload.has_yuv_planes()); struct PlaneMemoryDumpInfo { @@ -1609,6 +1719,7 @@ for (const auto& image_pair : persistent_cache_) { const ImageData* image_data = image_pair.second.get(); int image_id = static_cast<int>(image_pair.first.hash()); + const auto& info = image_data->info; // If we have discardable decoded data, dump this here. if (image_data->decode.data()) { @@ -1621,7 +1732,7 @@ // This lets us see the amount of discardable which is contributing to // memory pressure. size_t locked_size = - image_data->decode.is_locked() ? image_data->size : 0u; + image_data->decode.is_locked() ? image_data->GetSize() : 0u; dump->AddScalar("locked_size", MemoryAllocatorDump::kUnitsBytes, locked_size); } @@ -1631,11 +1742,11 @@ if (image_data->HasUploadedData()) { switch (image_data->mode) { case DecodedDataMode::kGpu: { - size_t discardable_size = image_data->size; + size_t discardable_size = info.size; auto* context_support = context_->ContextSupport(); // If the discardable system has deleted this out from under us, log a // size of 0 to match software discardable. - if (image_data->yuva_pixmap_info.has_value() && + if (info.yuva.has_value() && context_support->ThreadsafeDiscardableTextureIsDeletedForTracing( image_data->upload.gl_y_id()) && context_support->ThreadsafeDiscardableTextureIsDeletedForTracing( @@ -1653,7 +1764,7 @@ "%s/gpu/image_%d", dump_name.c_str(), image_id); size_t locked_size = image_data->upload.is_locked() ? discardable_size : 0u; - if (image_data->yuva_pixmap_info.has_value()) { + if (info.yuva.has_value()) { MemoryDumpYUVImage(pmd, image_data, gpu_dump_base_name, locked_size); } else { @@ -1664,14 +1775,13 @@ case DecodedDataMode::kTransferCache: { // TODO(lizeb): Include the right ID to link it with the GPU-side // resource. - size_t size = image_data->size; std::string uploaded_dump_name = base::StringPrintf( "%s/gpu/image_%d", dump_name.c_str(), image_data->upload.transfer_cache_id().value()); MemoryAllocatorDump* dump = pmd->CreateAllocatorDump(uploaded_dump_name); dump->AddScalar(MemoryAllocatorDump::kNameSize, - MemoryAllocatorDump::kUnitsBytes, size); + MemoryAllocatorDump::kUnitsBytes, info.size); } break; case DecodedDataMode::kCpu: @@ -1917,9 +2027,9 @@ image_data->upload.ref_count > 0 || image_data->decode.ref_count > 0; // If we have no image refs on an image, we should unbudget it. if (!has_any_refs && image_data->is_budgeted) { - DCHECK_GE(working_set_bytes_, image_data->size); + DCHECK_GE(working_set_bytes_, image_data->GetSize()); DCHECK_GE(working_set_items_, 1u); - working_set_bytes_ -= image_data->size; + working_set_bytes_ -= image_data->GetSize(); working_set_items_ -= 1; image_data->is_budgeted = false; } @@ -1966,8 +2076,8 @@ // If we have image that could be budgeted, but isn't, budget it now. if (has_any_refs && !image_data->is_budgeted && - CanFitInWorkingSet(image_data->size)) { - working_set_bytes_ += image_data->size; + CanFitInWorkingSet(image_data->GetSize())) { + working_set_bytes_ += image_data->GetSize(); working_set_items_ += 1; image_data->is_budgeted = true; } @@ -2087,8 +2197,9 @@ DCHECK(dark_mode_filter_); // TODO(prashant.n): RSDM - Add support for YUV decoded data. - if (image_data->yuva_pixmap_info.has_value()) + if (image_data->info.yuva.has_value()) { return false; + } // Dark mode filter is already generated and cached. if (image_data->decode.dark_mode_color_filter_cache.find( @@ -2139,7 +2250,7 @@ if (image_data->is_bitmap_backed) { DCHECK(!draw_image.paint_image().IsLazyGenerated()); - if (image_data->yuva_pixmap_info.has_value()) { + if (image_data->info.yuva.has_value()) { DLOG(ERROR) << "YUV + Bitmap is unknown and unimplemented!"; NOTREACHED(); } else { @@ -2159,66 +2270,62 @@ image_data->decode.ResetData(); - // Decode the image into `images`, backed by `backing_memory`. Do the decode - // while the lock is not held. - std::unique_ptr<base::DiscardableMemory> backing_memory; - sk_sp<SkImage> images[SkYUVAInfo::kMaxPlanes]; + // Decode the image into `aux_image_data` while the lock is not held. + DecodedAuxImageData aux_image_data; { - // Allocate the backing memory for the decode. base::AutoUnlock unlock(lock_); + + // Allocate the backing memory for the decode. + std::unique_ptr<base::DiscardableMemory> backing_memory; if (base::FeatureList::IsEnabled( features::kNoDiscardableMemoryForGpuDecodePath)) { backing_memory = - std::make_unique<HeapDiscardableMemory>(image_data->size); + std::make_unique<HeapDiscardableMemory>(image_data->info.size); } else { auto* allocator = base::DiscardableMemoryAllocator::GetInstance(); backing_memory = allocator->AllocateLockedDiscardableMemoryWithRetryOrDie( - image_data->size, base::BindOnce(&GpuImageDecodeCache::ClearCache, - base::Unretained(this))); + image_data->info.size, + base::BindOnce(&GpuImageDecodeCache::ClearCache, + base::Unretained(this))); } // Do the decode. - bool decode_succeeded = false; - auto release_proc = [](const void*, void*) {}; - if (image_data->yuva_pixmap_info.has_value()) { + if (image_data->info.yuva.has_value()) { // Decode as YUV. DVLOG(3) << "GpuImageDecodeCache wants to do YUV decoding/rendering"; SkYUVAPixmaps yuva_pixmaps = SkYUVAPixmaps::FromExternalMemory( - image_data->yuva_pixmap_info.value(), backing_memory->data()); + image_data->info.yuva.value(), backing_memory->data()); if (DrawAndScaleImageYUV(draw_image, AuxImage::kDefault, generator_client_id_, yuva_supported_data_types_, yuva_pixmaps)) { - decode_succeeded = true; - for (int i = 0; i < yuva_pixmaps.numPlanes(); ++i) { - images[i] = SkImages::RasterFromPixmap(yuva_pixmaps.plane(i), - release_proc, nullptr); - } + aux_image_data = + DecodedAuxImageData(yuva_pixmaps, std::move(backing_memory)); + } else { + DLOG(ERROR) << "DrawAndScaleImageYUV failed."; + backing_memory->Unlock(); + backing_memory.reset(); } } else { // Decode as RGB. - SkImageInfo image_info = image_data->image_info.makeColorSpace( + SkImageInfo image_info = image_data->info.rgba->makeColorSpace( ColorSpaceForImageDecode(draw_image, image_data->mode)); SkPixmap pixmap(image_info, backing_memory->data(), image_info.minRowBytes()); if (DrawAndScaleImageRGB(draw_image, AuxImage::kDefault, pixmap, generator_client_id_)) { - decode_succeeded = true; - images[0] = SkImages::RasterFromPixmap(pixmap, release_proc, nullptr); + aux_image_data = DecodedAuxImageData(pixmap, std::move(backing_memory)); + } else { + DLOG(ERROR) << "DrawAndScaleImageRGB failed."; + backing_memory->Unlock(); + backing_memory.reset(); } } - - // If the decode failed, release the backing memory. - if (!decode_succeeded) { - DLOG(ERROR) << "DrawAndScaleImage failed."; - backing_memory->Unlock(); - backing_memory.reset(); - } } if (image_data->decode.data()) { // An at-raster task decoded this before us. Ignore our decode. - if (image_data->yuva_pixmap_info.has_value()) { - for (int i = 0; i < image_data->yuva_pixmap_info->numPlanes(); ++i) { + if (image_data->info.yuva.has_value()) { + for (int i = 0; i < image_data->info.yuva->numPlanes(); ++i) { DCHECK(image_data->decode.image(i)); } } else { @@ -2227,16 +2334,13 @@ return; } - // If `backing_memory` was not populated, we had a non-decodable image. - if (!backing_memory) { - for (const auto& image : images) { - DCHECK(!image); - } + // If `aux_image_data`'s data was not populated, we had a non-decodable image. + if (!aux_image_data.data) { image_data->decode.decode_failure = true; return; } - image_data->decode.SetLockedData(std::move(backing_memory), images, + image_data->decode.SetLockedData(std::move(aux_image_data), task_type == TaskType::kOutOfRaster); } @@ -2256,8 +2360,7 @@ if (image_data->decode.decode_failure) return; - SkPixmap pixmap; - image_data->decode.image(0)->peekPixels(&pixmap); + const SkPixmap& pixmap = image_data->decode.pixmaps()[0]; image_data->decode.dark_mode_color_filter_cache[draw_image.src_rect()] = dark_mode_filter_->ApplyToImage(pixmap, draw_image.src_rect()); } @@ -2336,7 +2439,7 @@ } else { // Do not color convert YUVA images unless the the color conversion also // performs tone mapping. - if (image_data->yuva_pixmap_info.has_value()) { + if (image_data->info.yuva.has_value()) { if (!decoded_target_colorspace || !gfx::ColorSpace(*decoded_target_colorspace) .IsToneMappedByDefault()) { @@ -2354,7 +2457,7 @@ GrMipMapped image_needs_mips = image_data->needs_mips ? GrMipMapped::kYes : GrMipMapped::kNo; - if (image_data->yuva_pixmap_info.has_value()) { + if (image_data->info.yuva.has_value()) { UploadImageIfNecessary_GpuCpu_YUVA( draw_image, image_data, uploaded_image, image_needs_mips, decoded_target_colorspace, target_color_space); @@ -2419,25 +2522,17 @@ DCHECK(!image_data->decode.do_hardware_accelerated_decode()); ClientImageTransferCacheEntry::Image image; - SkPixmap image_pixmaps[SkYUVAInfo::kMaxPlanes]; - if (image_data->yuva_pixmap_info.has_value()) { - for (int i = 0; i < image_data->yuva_pixmap_info->numPlanes(); ++i) { - if (!image_data->decode.image(i)->peekPixels(&image_pixmaps[i])) { - DLOG(ERROR) << "Failed to peek decoded YUV image pixels."; - return; - } - } + if (image_data->info.yuva.has_value()) { + DCHECK(!image_data->info.rgba.has_value()); image = ClientImageTransferCacheEntry::Image( - image_pixmaps, image_data->yuva_pixmap_info->yuvaInfo().planeConfig(), - image_data->yuva_pixmap_info->yuvaInfo().subsampling(), + image_data->decode.pixmaps(), + image_data->info.yuva->yuvaInfo().planeConfig(), + image_data->info.yuva->yuvaInfo().subsampling(), decoded_target_colorspace.get(), - image_data->yuva_pixmap_info->yuvaInfo().yuvColorSpace()); + image_data->info.yuva->yuvaInfo().yuvColorSpace()); } else { - if (!image_data->decode.image()->peekPixels(&image_pixmaps[0])) { - DLOG(ERROR) << "Failed to peek decoded RGB image pixels."; - return; - } - image = ClientImageTransferCacheEntry::Image(&image_pixmaps[0]); + DCHECK(image_data->info.rgba.has_value()); + image = ClientImageTransferCacheEntry::Image(image_data->decode.pixmaps()); } ClientImageTransferCacheEntry image_entry(image, image_data->needs_mips, @@ -2455,12 +2550,12 @@ sk_sp<SkColorSpace> decoded_target_colorspace, sk_sp<SkColorSpace> color_space) { DCHECK(!use_transfer_cache_); - DCHECK(image_data->yuva_pixmap_info.has_value()); + DCHECK(image_data->info.yuva.has_value()); // Grab a reference to our decoded image. For the kCpu path, we will use // this directly as our "uploaded" data. This path only supports tri-planar // YUV with no alpha. - DCHECK_EQ(image_data->yuva_pixmap_info->yuvaInfo().planeConfig(), + DCHECK_EQ(image_data->info.yuva->yuvaInfo().planeConfig(), SkYUVAInfo::PlaneConfig::kY_U_V); sk_sp<SkImage> uploaded_y_image = image_data->decode.image(0); sk_sp<SkImage> uploaded_u_image = image_data->decode.image(1); @@ -2486,9 +2581,9 @@ uploaded_image = CreateImageFromYUVATexturesInternal( uploaded_y_image.get(), uploaded_u_image.get(), uploaded_v_image.get(), image_width, image_height, - image_data->yuva_pixmap_info->yuvaInfo().planeConfig(), - image_data->yuva_pixmap_info->yuvaInfo().subsampling(), - image_data->yuva_pixmap_info->yuvaInfo().yuvColorSpace(), color_space, + image_data->info.yuva->yuvaInfo().planeConfig(), + image_data->info.yuva->yuvaInfo().subsampling(), + image_data->info.yuva->yuvaInfo().yuvColorSpace(), color_space, decoded_target_colorspace); } @@ -2525,7 +2620,7 @@ std::move(uploaded_v_image)); image_data->upload.SetImage(std::move(uploaded_image), - image_data->yuva_pixmap_info.has_value()); + image_data->info.yuva.has_value()); image_data->upload.SetYuvImage(std::move(uploaded_y_image), std::move(uploaded_u_image), std::move(uploaded_v_image)); @@ -2551,7 +2646,7 @@ GrMipMapped image_needs_mips, sk_sp<SkColorSpace> color_space) { DCHECK(!use_transfer_cache_); - DCHECK(!image_data->yuva_pixmap_info.has_value()); + DCHECK(!image_data->info.yuva.has_value()); // RGBX decoding is below. // For kGpu, we upload and color convert (if necessary). @@ -2673,35 +2768,29 @@ } } - absl::optional<SkYUVAPixmapInfo> yuva_pixmap_info; + // Populate the ImageInfo for the base and gainmap images. + ImageInfo info(image_info); if (!do_hardware_accelerated_decode && mode != DecodedDataMode::kCpu && !image_larger_than_max_texture) { - yuva_pixmap_info = + info.yuva = GetYUVADecodeInfo(draw_image, AuxImage::kDefault, image_info.dimensions(), yuva_supported_data_types_); - } - - // Compute the size needed to decode the images. - size_t data_size = 0; - { - if (do_hardware_accelerated_decode) { - data_size = EstimateHardwareDecodedDataSize(image_metadata); - } else { - if (yuva_pixmap_info) { - data_size = yuva_pixmap_info->computeTotalBytes(); - } else { - data_size = image_info.computeMinByteSize(); - } - DCHECK(!SkImageInfo::ByteSizeOverflowed(data_size)); + if (info.yuva.has_value()) { + info = ImageInfo(info.yuva.value()); } } + // Override the estimated size if we are doing hardware decode. + if (do_hardware_accelerated_decode) { + info.size = EstimateHardwareDecodedDataSize(image_metadata); + } + return base::WrapRefCounted(new ImageData( - draw_image.paint_image().stable_id(), mode, data_size, + draw_image.paint_image().stable_id(), mode, draw_image.target_color_params(), CalculateDesiredFilterQuality(draw_image), upload_scale_mip_level, needs_mips, is_bitmap_backed, can_do_hardware_accelerated_decode, - do_hardware_accelerated_decode, image_info, yuva_pixmap_info)); + do_hardware_accelerated_decode, info)); } void GpuImageDecodeCache::WillAddCacheEntry(const DrawImage& draw_image) { @@ -2758,7 +2847,7 @@ if (image_data->HasUploadedData()) { DCHECK(!image_data->upload.is_locked()); if (image_data->mode == DecodedDataMode::kGpu) { - if (image_data->yuva_pixmap_info.has_value()) { + if (image_data->info.yuva.has_value()) { images_pending_deletion_.push_back(image_data->upload.y_image()); images_pending_deletion_.push_back(image_data->upload.u_image()); images_pending_deletion_.push_back(image_data->upload.v_image()); @@ -2776,7 +2865,7 @@ void GpuImageDecodeCache::UnlockImage(ImageData* image_data) { DCHECK(image_data->HasUploadedData()); if (image_data->mode == DecodedDataMode::kGpu) { - if (image_data->yuva_pixmap_info.has_value()) { + if (image_data->info.yuva.has_value()) { images_pending_unlock_.push_back(image_data->upload.y_image().get()); images_pending_unlock_.push_back(image_data->upload.u_image().get()); images_pending_unlock_.push_back(image_data->upload.v_image().get()); @@ -2794,7 +2883,7 @@ // it is guaranteed to have no-refs. auto unmipped_image = image_data->upload.take_unmipped_image(); if (unmipped_image) { - if (image_data->yuva_pixmap_info.has_value()) { + if (image_data->info.yuva.has_value()) { auto unmipped_y_image = image_data->upload.take_unmipped_y_image(); auto unmipped_u_image = image_data->upload.take_unmipped_u_image(); auto unmipped_v_image = image_data->upload.take_unmipped_v_image(); @@ -2943,7 +3032,7 @@ // If |have_context_lock|, we can immediately lock the image and send // the lock command to the GPU process. // TODO(crbug.com/914622): Add Chrome GL extension to upload texture array. - if (data->yuva_pixmap_info.has_value() && + if (data->info.yuva.has_value() && ri->LockDiscardableTextureCHROMIUM(data->upload.gl_y_id()) && ri->LockDiscardableTextureCHROMIUM(data->upload.gl_u_id()) && ri->LockDiscardableTextureCHROMIUM(data->upload.gl_v_id())) { @@ -2951,7 +3040,7 @@ DCHECK(data->mode == DecodedDataMode::kGpu); data->upload.OnLock(); return true; - } else if (!data->yuva_pixmap_info.has_value() && + } else if (!data->info.yuva.has_value() && ri->LockDiscardableTextureCHROMIUM(data->upload.gl_id())) { DCHECK(!use_transfer_cache_); DCHECK(data->mode == DecodedDataMode::kGpu); @@ -2969,7 +3058,7 @@ // UploadImageIfNecessary, which is guaranteed to run before the texture // is used. auto* context_support = context_->ContextSupport(); - if (data->yuva_pixmap_info.has_value() && + if (data->info.yuva.has_value() && context_support->ThreadSafeShallowLockDiscardableTexture( data->upload.gl_y_id()) && context_support->ThreadSafeShallowLockDiscardableTexture( @@ -2983,7 +3072,7 @@ images_pending_complete_lock_.push_back(data->upload.u_image().get()); images_pending_complete_lock_.push_back(data->upload.v_image().get()); return true; - } else if (!data->yuva_pixmap_info.has_value() && + } else if (!data->info.yuva.has_value() && context_support->ThreadSafeShallowLockDiscardableTexture( data->upload.gl_id())) { DCHECK(!use_transfer_cache_); @@ -3061,7 +3150,7 @@ base::AutoLock lock(lock_); scoped_refptr<ImageData> data = CreateImageData(image, false /* allow_hardware_decode */); - return data->size; + return data->GetSize(); } void GpuImageDecodeCache::SetImageDecodingFailedForTesting( @@ -3102,7 +3191,7 @@ auto found = persistent_cache_.Peek(image.frame_key()); DCHECK(found != persistent_cache_.end()); ImageData* image_data = found->second.get(); - DCHECK(!image_data->yuva_pixmap_info.has_value()); + DCHECK(!image_data->info.yuva.has_value()); return image_data->decode.ImageForTesting(); } @@ -3115,8 +3204,9 @@ base::AutoLock lock(lock_); ImageData* image_data = GetImageDataForDrawImage( draw_image, InUseCacheKeyFromDrawImage(draw_image)); - if (!image_data->yuva_pixmap_info.has_value()) + if (!image_data->info.yuva.has_value()) { return nullptr; + } switch (index) { case YUVIndex::kY: return image_data->upload.y_image(); @@ -3248,7 +3338,7 @@ image_data->mode != DecodedDataMode::kGpu) return; - if (image_data->yuva_pixmap_info.has_value()) { + if (image_data->info.yuva.has_value()) { // Need to generate mips. Take a reference on the planes we're about to // delete, delaying deletion. // TODO(crbug.com/910276): Change after alpha support. @@ -3309,10 +3399,10 @@ CreateImageFromYUVATexturesInternal( image_y_with_mips_owned.get(), image_u_with_mips_owned.get(), image_v_with_mips_owned.get(), width, height, - image_data->yuva_pixmap_info->yuvaInfo().planeConfig(), - image_data->yuva_pixmap_info->yuvaInfo().subsampling(), - image_data->yuva_pixmap_info->yuvaInfo().yuvColorSpace(), - color_space, upload_color_space); + image_data->info.yuva->yuvaInfo().planeConfig(), + image_data->info.yuva->yuvaInfo().subsampling(), + image_data->info.yuva->yuvaInfo().yuvColorSpace(), color_space, + upload_color_space); // In case of lost context if (!yuv_image_with_mips_owned) { DLOG(WARNING) << "TODO(crbug.com/740737): Context was lost. Early out.";
diff --git a/cc/tiles/gpu_image_decode_cache.h b/cc/tiles/gpu_image_decode_cache.h index 4e68790..999b04e7 100644 --- a/cc/tiles/gpu_image_decode_cache.h +++ b/cc/tiles/gpu_image_decode_cache.h
@@ -272,6 +272,33 @@ UsageStats usage_stats_; }; + // Stores the CPU-side decoded bits and SkImage representation of a single + // image (either the default or gainmap image). + struct DecodedAuxImageData { + // Initialize `data` and make `images` point to `rgba_pixmap` or + // `yuva_pixmaps`, which must be backed by `data`. + DecodedAuxImageData(); + DecodedAuxImageData(const SkPixmap& rgba_pixmap, + std::unique_ptr<base::DiscardableMemory> data); + DecodedAuxImageData(const SkYUVAPixmaps& yuva_pixmaps, + std::unique_ptr<base::DiscardableMemory> data); + DecodedAuxImageData(const DecodedAuxImageData&) = delete; + DecodedAuxImageData(DecodedAuxImageData&&); + DecodedAuxImageData& operator=(const DecodedAuxImageData&) = delete; + DecodedAuxImageData& operator=(DecodedAuxImageData&&); + ~DecodedAuxImageData(); + + // Return true if all members are reset. + bool IsEmpty() const; + + // Release `data` and all entries in `images` and `pixmaps`. + void ResetData(); + + std::unique_ptr<base::DiscardableMemory> data; + sk_sp<SkImage> images[SkYUVAInfo::kMaxPlanes]; + SkPixmap pixmaps[SkYUVAInfo::kMaxPlanes]; + }; + // Stores the CPU-side decoded bits of an image and supporting fields. struct DecodedImageData : public ImageDataBase { explicit DecodedImageData(bool is_bitmap_backed, @@ -282,19 +309,22 @@ bool Lock(); void Unlock(); - void SetLockedData(std::unique_ptr<base::DiscardableMemory> data, - sk_sp<SkImage> images[SkYUVAInfo::kMaxPlanes], - bool out_of_raster); + void SetLockedData(DecodedAuxImageData aux_image_data, bool out_of_raster); void ResetData(); - base::DiscardableMemory* data() const { return data_.get(); } + base::DiscardableMemory* data() const { return aux_image_data_.data.get(); } void SetBitmapImage(sk_sp<SkImage> image); void ResetBitmapImage(); - sk_sp<SkImage> image(int i = 0) const { + sk_sp<SkImage> image(int plane = 0) const { DCHECK(is_locked() || is_bitmap_backed_); - DCHECK_LT(i, SkYUVAInfo::kMaxPlanes); - return images_[i]; + DCHECK_LT(plane, SkYUVAInfo::kMaxPlanes); + return aux_image_data_.images[plane]; + } + + const SkPixmap* pixmaps() const { + DCHECK(is_locked() || is_bitmap_backed_); + return aux_image_data_.pixmaps; } bool can_do_hardware_accelerated_decode() const { @@ -306,7 +336,7 @@ } // Test-only functions. - sk_sp<SkImage> ImageForTesting() const { return images_[0]; } + sk_sp<SkImage> ImageForTesting() const { return aux_image_data_.images[0]; } bool decode_failure = false; // Similar to |task|, but only is generated if there is no associated upload @@ -328,8 +358,7 @@ void ReportUsageStats() const; const bool is_bitmap_backed_; - std::unique_ptr<base::DiscardableMemory> data_; - sk_sp<SkImage> images_[SkYUVAInfo::kMaxPlanes]; + DecodedAuxImageData aux_image_data_; // Keeps tracks of images that could go through hardware decode acceleration // though they're possibly prevented from doing so because of a disabled @@ -498,10 +527,27 @@ absl::optional<YUVSkImages> unmipped_yuv_images_; }; + // A structure to represent either an RGBA or a YUVA image info. + struct ImageInfo { + // Initialize `rgba` or `yuva`, and compute `size`. + ImageInfo(); + explicit ImageInfo(const SkImageInfo& rgba); + explicit ImageInfo(const SkYUVAPixmapInfo& yuva); + ImageInfo(const ImageInfo&); + ImageInfo& operator=(const ImageInfo&); + ~ImageInfo(); + + // At most one of `rgba` or `yuva` may be valid. + absl::optional<SkImageInfo> rgba; + absl::optional<SkYUVAPixmapInfo> yuva; + + // The number of bytes used by this image. + size_t size = 0; + }; + struct ImageData : public base::RefCountedThreadSafe<ImageData> { ImageData(PaintImage::Id paint_image_id, DecodedDataMode mode, - size_t size, const TargetColorParams& target_color_params, PaintFlags::FilterQuality quality, int upload_scale_mip_level, @@ -509,16 +555,20 @@ bool is_bitmap_backed, bool can_do_hardware_accelerated_decode, bool do_hardware_accelerated_decode, - const SkImageInfo& image_info, - absl::optional<SkYUVAPixmapInfo> yuva_pixmap_info); + const ImageInfo& info); bool IsGpuOrTransferCache() const; bool HasUploadedData() const; void ValidateBudgeted() const; + // Return the memory that is used by this image when decoded. This should + // also equal the memory that is used on the GPU when this is uploaded. + // In some circumstances the GPU memory usage is slightly different (e.g, + // when a gainmap or HDR tonemapping is applied). + size_t GetSize() const; + const PaintImage::Id paint_image_id; const DecodedDataMode mode; - const size_t size; TargetColorParams target_color_params; PaintFlags::FilterQuality quality; int upload_scale_mip_level; @@ -527,14 +577,9 @@ bool is_budgeted = false; base::TimeTicks last_use; - // The RGBA image info for the decoded image. The dimensions may be smaller - // than the original size if the image needs to be downscaled. - SkImageInfo image_info; - - // The YUVA image info for the image, if the image is to be decoded to YUVA. - // The dimensions may be smaller than the original size if the image needs - // to be downscaled. - absl::optional<SkYUVAPixmapInfo> yuva_pixmap_info; + // The RGBA or YUVA image info for the decoded image. The dimensions may be + // smaller than the original size if the image needs to be downscaled. + const ImageInfo info; // If true, this image is no longer in our |persistent_cache_| and will be // deleted as soon as its ref count reaches zero.
diff --git a/cc/trees/layer_context.h b/cc/trees/layer_context.h new file mode 100644 index 0000000..95726a1 --- /dev/null +++ b/cc/trees/layer_context.h
@@ -0,0 +1,35 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CC_TREES_LAYER_CONTEXT_H_ +#define CC_TREES_LAYER_CONTEXT_H_ + +#include "cc/cc_export.h" +#include "cc/trees/commit_state.h" +#include "components/viz/common/surfaces/local_surface_id.h" + +namespace cc { + +// LayerContext provides an opaque interface through which a LayerTreeHost can +// control a backing LayerTreeHostImpl, potentially on another thread or in +// another process. +class CC_EXPORT LayerContext { + public: + virtual ~LayerContext() = default; + + // Indicates that a new LocalSurfaceId has been set for the frame sink hosting + // this tree. + virtual void SetTargetLocalSurfaceId(const viz::LocalSurfaceId& id) = 0; + + // Globally controls the visibility of layers within the tree. + virtual void SetVisible(bool visible) = 0; + + // Flushes pending updates to the backing LayerTreeHostImpl. `state` + // represents the pending CommitState for the client-side LayerTreeHost. + virtual void Commit(const CommitState& state) = 0; +}; + +} // namespace cc + +#endif // CC_TREES_LAYER_CONTEXT_H_
diff --git a/cc/trees/layer_context_client.h b/cc/trees/layer_context_client.h new file mode 100644 index 0000000..2514c245 --- /dev/null +++ b/cc/trees/layer_context_client.h
@@ -0,0 +1,27 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CC_TREES_LAYER_CONTEXT_CLIENT_H_ +#define CC_TREES_LAYER_CONTEXT_CLIENT_H_ + +#include "cc/cc_export.h" +#include "components/viz/common/frame_sinks/begin_frame_args.h" + +namespace cc { + +// Interface used by LayerContext to push requests to its corresponding +// client-side LayerTreeHost. +class CC_EXPORT LayerContextClient { + public: + virtual ~LayerContextClient() = default; + + // Indicates that the compositor will produce a new display frame soon and + // that the client should commit a new layer tree ASAP. `args` correspond to + // the impending display frame that the compositor wants to produce. + virtual void OnRequestCommitForFrame(const viz::BeginFrameArgs& args) = 0; +}; + +} // namespace cc + +#endif // CC_TREES_LAYER_CONTEXT_CLIENT_H_
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc index 1c4fb260..4b3b837 100644 --- a/cc/trees/layer_tree_host_impl_unittest.cc +++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -14370,8 +14370,7 @@ : ScrollUpdateEventMetrics::ScrollUpdateType::kContinued, /*delta=*/10.0f, base::TimeTicks::Now(), base::TimeTicks::Now() + base::Milliseconds(1), - /*trace_id*/ base::IdType64<class ui::LatencyInfo>(123), - base::TimeTicks())); + /*trace_id*/ base::IdType64<class ui::LatencyInfo>(123))); host_impl_->active_tree()->AppendEventsMetricsFromMainThread( std::move(events_metrics));
diff --git a/cc/trees/local_layer_context.cc b/cc/trees/local_layer_context.cc new file mode 100644 index 0000000..0238c079 --- /dev/null +++ b/cc/trees/local_layer_context.cc
@@ -0,0 +1,151 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "cc/trees/local_layer_context.h" + +#include <memory> + +#include "base/task/single_thread_task_runner.h" +#include "cc/raster/categorized_worker_pool.h" +#include "cc/trees/commit_state.h" +#include "cc/trees/layer_tree_host.h" +#include "cc/trees/layer_tree_settings.h" + +namespace cc { + +namespace { + +LayerListSettings CreateSettings() { + LayerListSettings settings; + settings.commit_to_active_tree = true; + return settings; +} + +LayerTreeHost::InitParams CreateInitParams(LocalLayerContext& context, + const LayerListSettings& settings, + MutatorHost* mutator_host) { + LayerTreeHost::InitParams params; + params.client = &context; + params.settings = &settings; + params.task_graph_runner = CategorizedWorkerPool::GetOrCreate(); + params.main_task_runner = base::SingleThreadTaskRunner::GetCurrentDefault(); + params.mutator_host = mutator_host; + return params; +} + +} // namespace + +LocalLayerContext::LocalLayerContext(MutatorHost* mutator_host) + : mutator_host_(mutator_host), + layer_list_settings_(CreateSettings()), + host_(LayerTreeHost::CreateSingleThreaded( + this, + CreateInitParams(*this, layer_list_settings_, mutator_host_))) {} + +LocalLayerContext::~LocalLayerContext() = default; + +void LocalLayerContext::SetTargetLocalSurfaceId(const viz::LocalSurfaceId& id) { + host_->SetTargetLocalSurfaceId(id); +} + +void LocalLayerContext::SetVisible(bool visible) { + host_->SetVisible(visible); +} + +void LocalLayerContext::Commit(const CommitState& state) { + // TODO(https://crbug.com/1431762): Actually update the tree contents. + host_->SetViewportRectAndScale(state.device_viewport_rect, + state.device_scale_factor, + state.local_surface_id_from_parent); +} + +void LocalLayerContext::WillBeginMainFrame() {} + +void LocalLayerContext::DidBeginMainFrame() {} + +void LocalLayerContext::WillUpdateLayers() {} + +void LocalLayerContext::DidUpdateLayers() {} + +void LocalLayerContext::BeginMainFrame(const viz::BeginFrameArgs& args) {} + +void LocalLayerContext::OnDeferMainFrameUpdatesChanged(bool) {} + +void LocalLayerContext::OnDeferCommitsChanged( + bool defer_status, + PaintHoldingReason reason, + absl::optional<PaintHoldingCommitTrigger> trigger) {} + +void LocalLayerContext::OnCommitRequested() {} + +void LocalLayerContext::BeginMainFrameNotExpectedSoon() {} + +void LocalLayerContext::BeginMainFrameNotExpectedUntil(base::TimeTicks time) {} + +void LocalLayerContext::UpdateLayerTreeHost() {} + +void LocalLayerContext::ApplyViewportChanges( + const ApplyViewportChangesArgs& args) {} + +void LocalLayerContext::UpdateCompositorScrollState( + const CompositorCommitData& commit_data) {} + +void LocalLayerContext::RequestNewLayerTreeFrameSink() {} + +void LocalLayerContext::DidInitializeLayerTreeFrameSink() {} + +void LocalLayerContext::DidFailToInitializeLayerTreeFrameSink() {} + +void LocalLayerContext::WillCommit(const CommitState&) {} + +void LocalLayerContext::DidCommit(base::TimeTicks commit_start_time, + base::TimeTicks commit_finish_time) {} + +void LocalLayerContext::DidCommitAndDrawFrame() {} + +void LocalLayerContext::DidReceiveCompositorFrameAck() {} + +void LocalLayerContext::DidCompletePageScaleAnimation() {} + +void LocalLayerContext::DidPresentCompositorFrame( + uint32_t frame_token, + const gfx::PresentationFeedback& feedback) {} + +void LocalLayerContext::RecordStartOfFrameMetrics() {} + +void LocalLayerContext::RecordEndOfFrameMetrics( + base::TimeTicks frame_begin_time, + ActiveFrameSequenceTrackers trackers) {} + +std::unique_ptr<BeginMainFrameMetrics> +LocalLayerContext::GetBeginMainFrameMetrics() { + return nullptr; +} + +std::unique_ptr<WebVitalMetrics> LocalLayerContext::GetWebVitalMetrics() { + return nullptr; +} + +void LocalLayerContext::NotifyThroughputTrackerResults( + CustomTrackerResults results) {} + +void LocalLayerContext::DidObserveFirstScrollDelay( + base::TimeDelta first_scroll_delay, + base::TimeTicks first_scroll_timestamp) {} + +void LocalLayerContext::RunPaintBenchmark(int repeat_count, + PaintBenchmarkResult& result) {} + +void LocalLayerContext::ScheduleAnimationForWebTests() {} + +void LocalLayerContext::FrameIntervalUpdated(base::TimeDelta interval) {} + +void LocalLayerContext::DidSubmitCompositorFrame() {} + +void LocalLayerContext::DidLoseLayerTreeFrameSink() {} + +void LocalLayerContext::FrameSinksToThrottleUpdated( + const base::flat_set<viz::FrameSinkId>& ids) {} + +} // namespace cc
diff --git a/cc/trees/local_layer_context.h b/cc/trees/local_layer_context.h new file mode 100644 index 0000000..106a711 --- /dev/null +++ b/cc/trees/local_layer_context.h
@@ -0,0 +1,98 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CC_TREES_LOCAL_LAYER_CONTEXT_H_ +#define CC_TREES_LOCAL_LAYER_CONTEXT_H_ + +#include <memory> + +#include "base/memory/raw_ptr.h" +#include "cc/cc_export.h" +#include "cc/trees/layer_context.h" +#include "cc/trees/layer_tree_host_client.h" +#include "cc/trees/layer_tree_host_single_thread_client.h" +#include "cc/trees/layer_tree_settings.h" + +namespace cc { + +class LayerTreeHost; +class MutatorHost; + +// LocalLayerContext owns and manages a LayerTreeHostImpl to be controlled +// indirectly by a client's corresponding LayerTreeHost. +class CC_EXPORT LocalLayerContext : public LayerContext, + public LayerTreeHostClient, + public LayerTreeHostSingleThreadClient { + public: + explicit LocalLayerContext(MutatorHost* mutator_host); + ~LocalLayerContext() override; + + // LayerContext: + void SetTargetLocalSurfaceId(const viz::LocalSurfaceId& id) override; + void SetVisible(bool visible) override; + void Commit(const CommitState& state) override; + + // LayerTreeHostClient: + void WillBeginMainFrame() override; + void DidBeginMainFrame() override; + void WillUpdateLayers() override; + void DidUpdateLayers() override; + void BeginMainFrame(const viz::BeginFrameArgs& args) override; + void OnDeferMainFrameUpdatesChanged(bool) override; + void OnDeferCommitsChanged( + bool defer_status, + PaintHoldingReason reason, + absl::optional<PaintHoldingCommitTrigger> trigger) override; + void OnCommitRequested() override; + void BeginMainFrameNotExpectedSoon() override; + void BeginMainFrameNotExpectedUntil(base::TimeTicks time) override; + void UpdateLayerTreeHost() override; + void ApplyViewportChanges(const ApplyViewportChangesArgs& args) override; + void UpdateCompositorScrollState( + const CompositorCommitData& commit_data) override; + void RequestNewLayerTreeFrameSink() override; + void DidInitializeLayerTreeFrameSink() override; + void DidFailToInitializeLayerTreeFrameSink() override; + void WillCommit(const CommitState&) override; + void DidCommit(base::TimeTicks commit_start_time, + base::TimeTicks commit_finish_time) override; + void DidCommitAndDrawFrame() override; + void DidReceiveCompositorFrameAck() override; + void DidCompletePageScaleAnimation() override; + void DidPresentCompositorFrame( + uint32_t frame_token, + const gfx::PresentationFeedback& feedback) override; + void RecordStartOfFrameMetrics() override; + void RecordEndOfFrameMetrics(base::TimeTicks frame_begin_time, + ActiveFrameSequenceTrackers trackers) override; + std::unique_ptr<BeginMainFrameMetrics> GetBeginMainFrameMetrics() override; + std::unique_ptr<WebVitalMetrics> GetWebVitalMetrics() override; + void NotifyThroughputTrackerResults(CustomTrackerResults results) override; + void DidObserveFirstScrollDelay( + base::TimeDelta first_scroll_delay, + base::TimeTicks first_scroll_timestamp) override; + void RunPaintBenchmark(int repeat_count, + PaintBenchmarkResult& result) override; + + // LayerTreeHostSingleThreadClient: + void ScheduleAnimationForWebTests() override; + void FrameIntervalUpdated(base::TimeDelta interval) override; + void DidSubmitCompositorFrame() override; + void DidLoseLayerTreeFrameSink() override; + void FrameSinksToThrottleUpdated( + const base::flat_set<viz::FrameSinkId>& ids) override; + + private: + const raw_ptr<MutatorHost> mutator_host_; + + // The concrete LayerTreeHost which the client is controlling. + // TODO(https://crbug.com/1431762): Own and manage a LayerTreeHostImpl + // directly instead of proxying through a single-threaded LayerTreeHost. + const LayerListSettings layer_list_settings_; + std::unique_ptr<LayerTreeHost> host_; +}; + +} // namespace cc + +#endif // CC_TREES_LOCAL_LAYER_CONTEXT_H_
diff --git a/cc/trees/ukm_manager.cc b/cc/trees/ukm_manager.cc index fa6f393..d5c2704 100644 --- a/cc/trees/ukm_manager.cc +++ b/cc/trees/ukm_manager.cc
@@ -206,8 +206,6 @@ switch (dispatch_stage) { case EventMetrics::DispatchStage::kGenerated: switch (end_stage) { - case EventMetrics::DispatchStage:: - kScrollsBlockingTouchDispatchedToRenderer: case EventMetrics::DispatchStage::kArrivedInBrowserMain: // Will build the `GenerationToRendererCompositor` metric on the // `kArrivedInBrowserMain` stage. @@ -220,9 +218,6 @@ break; } break; - case EventMetrics::DispatchStage:: - kScrollsBlockingTouchDispatchedToRenderer: - break; case EventMetrics::DispatchStage::kArrivedInBrowserMain: DCHECK_EQ(end_stage, EventMetrics::DispatchStage::kArrivedInRendererCompositor);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/omnibox/ActionChipsDelegateImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/app/omnibox/ActionChipsDelegateImpl.java index b520856..d3da39c 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/app/omnibox/ActionChipsDelegateImpl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/app/omnibox/ActionChipsDelegateImpl.java
@@ -173,6 +173,13 @@ try { var intent = Intent.parseUri( actionInSuggest.actionInfo.getActionUri(), Intent.URI_INTENT_SCHEME); + + // Don't call directly. Use `DIAL` instead to let the user decide. + // Note also that ACTION_CALL requires a dedicated permission. + if (intent.getAction().equals(Intent.ACTION_CALL)) { + intent.setAction(Intent.ACTION_DIAL); + } + intent.putExtra(WebappConstants.REUSE_URL_MATCHING_TAB_ELSE_NEW_TAB, true); startActivity(intent);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/share/ShareDelegateImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/share/ShareDelegateImpl.java index 5f759a0..02d0064 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/share/ShareDelegateImpl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/share/ShareDelegateImpl.java
@@ -7,7 +7,9 @@ import android.app.Activity; import androidx.annotation.NonNull; +import androidx.annotation.OptIn; import androidx.annotation.VisibleForTesting; +import androidx.core.os.BuildCompat; import org.chromium.base.Callback; import org.chromium.base.metrics.RecordHistogram; @@ -241,9 +243,11 @@ } @Override + @OptIn(markerClass = androidx.core.os.BuildCompat.PrereleaseSdkCheck.class) public boolean isSharingHubEnabled() { return !(mIsCustomTab - || ChromeFeatureList.isEnabled(ChromeFeatureList.SHARE_SHEET_MIGRATION_ANDROID)); + || (ChromeFeatureList.isEnabled(ChromeFeatureList.SHARE_SHEET_MIGRATION_ANDROID) + && BuildCompat.isAtLeastU())); } /**
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ContentViewFocusTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ContentViewFocusTest.java index e9748eb..7ac1251 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/ContentViewFocusTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ContentViewFocusTest.java
@@ -114,7 +114,7 @@ * @Restriction(UiRestriction.RESTRICTION_TYPE_PHONE) */ @Test - @MediumTest + @DisabledTest(message = "http://crbug.com/172473") public void testHideSelectionOnPhoneTabSwiping() throws Exception { mActivityTestRule.startMainActivityOnBlankPage(); // Setup
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/TouchToFillCreditCardTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/TouchToFillCreditCardTest.java index 8e9e4b1..ace044eb 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/TouchToFillCreditCardTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/TouchToFillCreditCardTest.java
@@ -31,6 +31,7 @@ import org.chromium.base.test.util.Batch; import org.chromium.base.test.util.CommandLineFlags; +import org.chromium.base.test.util.DisabledTest; import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard; import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.flags.ChromeSwitches; @@ -112,6 +113,7 @@ @Test @MediumTest + @DisabledTest(message = "https://crbug.com/1433074") public void testSelectingLocalCard() throws TimeoutException { // Focus the field to bring up the touch to fill for credit cards. DOMUtils.clickNode(mWebContents, CREDIT_CARD_NUMBER_FIELD_ID);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/overlays/strip/TabStripTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/overlays/strip/TabStripTest.java index 02f06a15..478e3d58 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/overlays/strip/TabStripTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/overlays/strip/TabStripTest.java
@@ -668,8 +668,12 @@ checkTabStrips(); // Open enough regular tabs to cause the strip to scroll. - ChromeTabUtils.newTabsFromMenu( - InstrumentationRegistry.getInstrumentation(), sActivityTestRule.getActivity(), 10); + StripLayoutHelper tabStrip = + TabStripUtils.getStripLayoutHelper(sActivityTestRule.getActivity(), false); + while (tabStrip.getMinimumScrollOffset() >= 0) { + ChromeTabUtils.newTabFromMenu( + InstrumentationRegistry.getInstrumentation(), sActivityTestRule.getActivity()); + } // In RTL the expectation for left/right fade opacities is swapped. boolean isLeft = !LocalizationUtils.isLayoutRtl(); @@ -712,8 +716,12 @@ checkTabStrips(); // Open enough regular tabs to cause the strip to scroll. - ChromeTabUtils.newTabsFromMenu( - InstrumentationRegistry.getInstrumentation(), sActivityTestRule.getActivity(), 10); + StripLayoutHelper tabStrip = + TabStripUtils.getStripLayoutHelper(sActivityTestRule.getActivity(), false); + while (tabStrip.getMinimumScrollOffset() >= 0) { + ChromeTabUtils.newTabFromMenu( + InstrumentationRegistry.getInstrumentation(), sActivityTestRule.getActivity()); + } // Get tab at index 0 and assert it is not visible. TabModel model = sActivityTestRule.getActivity().getTabModelSelector().getModel(false);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java index 9912ef6..2196da3 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java
@@ -820,6 +820,7 @@ */ @Test @SmallTest + @DisabledTest(message = "https://crbug.com/1433093") public void testRecordHistogramProfileButtonClick_Ntp() { HistogramWatcher histogramWatcher = HistogramWatcher.newSingleRecordWatcher( HISTOGRAM_NTP_MODULE_CLICK, BrowserUiUtils.ModuleTypeOnStartAndNTP.PROFILE_BUTTON);
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/share/ShareDelegateImplUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/share/ShareDelegateImplUnitTest.java index a5aa965..f03525fc 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/share/ShareDelegateImplUnitTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/share/ShareDelegateImplUnitTest.java
@@ -7,6 +7,7 @@ import android.app.Activity; import androidx.annotation.NonNull; +import androidx.core.os.BuildCompat; import org.junit.After; import org.junit.Assert; @@ -36,6 +37,7 @@ import org.chromium.chrome.browser.share.ShareDelegate.ShareOrigin; import org.chromium.chrome.browser.share.ShareDelegateImpl.ShareSheetDelegate; import org.chromium.chrome.browser.share.ShareDelegateImplUnitTest.ShadowAndroidShareSheetController; +import org.chromium.chrome.browser.share.ShareDelegateImplUnitTest.ShadowBuildCompatForU; import org.chromium.chrome.browser.share.ShareDelegateImplUnitTest.ShadowShareHelper; import org.chromium.chrome.browser.share.ShareDelegateImplUnitTest.ShadowShareSheetCoordinator; import org.chromium.chrome.browser.share.android_share_sheet.AndroidShareSheetController; @@ -58,7 +60,7 @@ */ @RunWith(BaseRobolectricTestRunner.class) @Config(shadows = {ShadowShareSheetCoordinator.class, ShadowShareHelper.class, - ShadowAndroidShareSheetController.class}) + ShadowAndroidShareSheetController.class, ShadowBuildCompatForU.class}) @Features.EnableFeatures(ChromeFeatureList.SHARE_SHEET_MIGRATION_ANDROID) public class ShareDelegateImplUnitTest { @Rule @@ -107,6 +109,7 @@ public void tearDown() { AppHooks.setInstanceForTesting(null); TrackerFactory.setTrackerForTests(null); + ShadowBuildCompatForU.sIsAtLeastU = false; ShadowShareSheetCoordinator.reset(); ShadowShareHelper.reset(); ShadowAndroidShareSheetController.reset(); @@ -142,7 +145,8 @@ } @Test - public void shareWithAndroidShareSheet() { + public void shareWithAndroidShareSheetForU() { + ShadowBuildCompatForU.sIsAtLeastU = true; Assert.assertFalse("ShareHub enabled.", mShareDelegate.isSharingHubEnabled()); ShareParams shareParams = new ShareParams.Builder(mWindowAndroid, "", "").build(); @@ -155,6 +159,11 @@ ShadowAndroidShareSheetController.sShareWithSystemShareSheetUiCalled); } + @Test + public void androidShareSheetDisableNonU() { + Assert.assertTrue("ShareHub should be enabled T-.", mShareDelegate.isSharingHubEnabled()); + } + @Implements(ShareHelper.class) static class ShadowShareHelper { static boolean sShareWithLastUsedComponentCalled; @@ -214,4 +223,15 @@ sShareWithSystemShareSheetUiCalled = false; } } + + // Work around shadow to assume runtime is at least U. + // TODO(https://crbug.com/1420388): Switch to @Config(sdk=34) this once API 34 exists. + @Implements(BuildCompat.class) + static class ShadowBuildCompatForU { + static boolean sIsAtLeastU; + @Implementation + protected static boolean isAtLeastU() { + return sIsAtLeastU; + } + } }
diff --git a/chrome/android/profiles/newest.txt b/chrome/android/profiles/newest.txt index 22d20a4..94d8fc9 100644 --- a/chrome/android/profiles/newest.txt +++ b/chrome/android/profiles/newest.txt
@@ -1 +1 @@ -chromeos-chrome-amd64-114.0.5703.0_rc-r1-merged.afdo.bz2 +chromeos-chrome-amd64-114.0.5712.0_rc-r1-merged.afdo.bz2
diff --git a/chrome/app/chrome_main_delegate.cc b/chrome/app/chrome_main_delegate.cc index 8d5a7b5b..ec470021 100644 --- a/chrome/app/chrome_main_delegate.cc +++ b/chrome/app/chrome_main_delegate.cc
@@ -228,6 +228,7 @@ #include "content/public/browser/zygote_host/zygote_host_linux.h" #include "media/base/media_switches.h" #include "ui/base/resource/data_pack_with_resource_sharing_lacros.h" +#include "ui/gfx/switches.h" #endif base::LazyInstance<ChromeContentGpuClient>::DestructorAtExit @@ -831,6 +832,11 @@ } } } + + if (init_params->EnableCpuMappableNativeGpuMemoryBuffers()) { + base::CommandLine::ForCurrentProcess()->AppendSwitch( + switches::kEnableNativeGpuMemoryBuffers); + } } #endif // BUILDFLAG(IS_CHROMEOS_LACROS)
diff --git a/chrome/app_shim/app_shim_controller.h b/chrome/app_shim/app_shim_controller.h index 7217271..3c1b10d0 100644 --- a/chrome/app_shim/app_shim_controller.h +++ b/chrome/app_shim/app_shim_controller.h
@@ -83,6 +83,9 @@ NSMenu* GetApplicationDockMenu(); + // Called when the app is about to terminate. + void ApplicationWillTerminate(); + private: friend class TestShimClient; friend class apps::MachBootstrapAcceptorTest;
diff --git a/chrome/app_shim/app_shim_controller.mm b/chrome/app_shim/app_shim_controller.mm index 51d9451a..19e4cb37 100644 --- a/chrome/app_shim/app_shim_controller.mm +++ b/chrome/app_shim/app_shim_controller.mm
@@ -647,3 +647,7 @@ return dockMenu; } + +void AppShimController::ApplicationWillTerminate() { + host_->ApplicationWillTerminate(); +}
diff --git a/chrome/app_shim/app_shim_delegate.mm b/chrome/app_shim/app_shim_delegate.mm index 08b0e40..7370ec2 100644 --- a/chrome/app_shim/app_shim_delegate.mm +++ b/chrome/app_shim/app_shim_delegate.mm
@@ -61,4 +61,10 @@ return _appShimController->GetApplicationDockMenu(); } +// Called when the app is shutting down. Used to persist the current state of +// the app. +- (void)applicationWillTerminate:(NSNotification*)aNotification { + _appShimController->ApplicationWillTerminate(); +} + @end
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 3944631..071c652b 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -4606,6 +4606,11 @@ kOsIntegrationSubManagersConfigVariations, "OsIntegrationSubManagers")}, + {"access-code-cast-freeze-ui", + flag_descriptions::kAccessCodeCastFreezeUiName, + flag_descriptions::kAccessCodeCastFreezeUiDescription, kOsDesktop, + FEATURE_VALUE_TYPE(features::kAccessCodeCastFreezeUI)}, + #endif // !BUILDFLAG(IS_ANDROID) #if BUILDFLAG(IS_ANDROID) @@ -5457,6 +5462,11 @@ flag_descriptions::kOmniboxMostVisitedTilesAddRecycledViewPoolDescription, kOsAndroid, FEATURE_VALUE_TYPE(omnibox::kOmniboxMostVisitedTilesAddRecycledViewPool)}, + + {"omnibox-warm-recycled-view-pool", + flag_descriptions::kOmniboxWarmRecycledViewPoolName, + flag_descriptions::kOmniboxWarmRecycledViewPoolDescription, kOsAndroid, + FEATURE_VALUE_TYPE(chrome::android::kOmniboxWarmRecycledViewPool)}, #endif // BUILDFLAG(IS_ANDROID) {"omnibox-local-history-zero-suggest-beyond-ntp", @@ -6353,14 +6363,6 @@ 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, @@ -10238,6 +10240,14 @@ } #endif // BUILDFLAG(IS_CHROMEOS_ASH) +#if !BUILDFLAG(IS_ANDROID) + // Only show the Access Code Cast Freeze UI flag if the Access Code Cast + // policy is enabled. + if (!strcmp("access-code-cast-freeze-ui", entry.internal_name)) { + return !media_router::IsAccessCodeCastEnabled(); + } +#endif // !BUILDFALG(IS_ANDROID) + // enable-unsafe-webgpu is only available on Dev/Canary channels. if (!strcmp("enable-unsafe-webgpu", entry.internal_name) && channel != version_info::Channel::DEV &&
diff --git a/chrome/browser/android/vr/arcore_device/arcore_device_unittest.cc b/chrome/browser/android/vr/arcore_device/arcore_device_unittest.cc index f26edd6..43a93eac7 100644 --- a/chrome/browser/android/vr/arcore_device/arcore_device_unittest.cc +++ b/chrome/browser/android/vr/arcore_device/arcore_device_unittest.cc
@@ -27,6 +27,7 @@ #include "mojo/public/cpp/bindings/associated_remote.h" #include "mojo/public/cpp/bindings/pending_remote.h" #include "mojo/public/cpp/bindings/remote.h" +#include "services/viz/public/mojom/compositing/layer_context.mojom.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -232,6 +233,7 @@ SubmitCompositorFrameSyncCallback callback) override {} void InitializeCompositorFrameSinkType( viz::mojom::CompositorFrameSinkType type) override {} + void BindLayerContext(viz::mojom::PendingLayerContextPtr context) override {} void SetThreadIds(const std::vector<int32_t>& thread_ids) override {} // mojom::ExternalBeginFrameController implementation.
diff --git a/chrome/browser/apps/app_shim/app_shim_host_mac.cc b/chrome/browser/apps/app_shim/app_shim_host_mac.cc index 26244455b..60386eaf2 100644 --- a/chrome/browser/apps/app_shim/app_shim_host_mac.cc +++ b/chrome/browser/apps/app_shim/app_shim_host_mac.cc
@@ -188,6 +188,10 @@ client_->OnShimOpenAppWithOverrideUrl(this, override_url); } +void AppShimHost::ApplicationWillTerminate() { + client_->OnShimWillTerminate(this); +} + base::FilePath AppShimHost::GetProfilePath() const { // This should only be used by single-profile-app paths. DCHECK(!profile_path_.empty());
diff --git a/chrome/browser/apps/app_shim/app_shim_host_mac.h b/chrome/browser/apps/app_shim/app_shim_host_mac.h index ed5b945..c9dea072 100644 --- a/chrome/browser/apps/app_shim/app_shim_host_mac.h +++ b/chrome/browser/apps/app_shim/app_shim_host_mac.h
@@ -76,6 +76,10 @@ // url (e.g. user clicks on an item in the application dock menu). virtual void OnShimOpenAppWithOverrideUrl(AppShimHost* host, const GURL& override_url) = 0; + + // Invoked by the shim host when the app is about to terminate (for example + // because the user quit it). + virtual void OnShimWillTerminate(AppShimHost* host) = 0; }; AppShimHost(Client* client, @@ -138,6 +142,7 @@ void ProfileSelectedFromMenu(const base::FilePath& profile_path) override; void UrlsOpened(const std::vector<GURL>& urls) override; void OpenAppWithOverrideUrl(const GURL& override_url) override; + void ApplicationWillTerminate() override; // Weak, owns |this|. const raw_ptr<Client> client_;
diff --git a/chrome/browser/apps/app_shim/app_shim_host_mac_unittest.cc b/chrome/browser/apps/app_shim/app_shim_host_mac_unittest.cc index 69c1eec..52b4b0dd 100644 --- a/chrome/browser/apps/app_shim/app_shim_host_mac_unittest.cc +++ b/chrome/browser/apps/app_shim/app_shim_host_mac_unittest.cc
@@ -188,6 +188,7 @@ const std::vector<GURL>& urls) override {} void OnShimOpenAppWithOverrideUrl(AppShimHost* host, const GURL& override_url) override {} + void OnShimWillTerminate(AppShimHost* host) override {} chrome::mojom::AppShimLaunchResult launch_result_ = chrome::mojom::AppShimLaunchResult::kSuccess;
diff --git a/chrome/browser/apps/app_shim/app_shim_listener_browsertest_mac.mm b/chrome/browser/apps/app_shim/app_shim_listener_browsertest_mac.mm index e853aa9..cde7451a 100644 --- a/chrome/browser/apps/app_shim/app_shim_listener_browsertest_mac.mm +++ b/chrome/browser/apps/app_shim/app_shim_listener_browsertest_mac.mm
@@ -208,6 +208,7 @@ void ProfileSelectedFromMenu(const base::FilePath& profile_path) override {} void UrlsOpened(const std::vector<GURL>& urls) override {} void OpenAppWithOverrideUrl(const GURL& override_url) override {} + void ApplicationWillTerminate() override {} std::unique_ptr<base::RunLoop> runner_; mojo::Receiver<chrome::mojom::AppShimHost> receiver_{this};
diff --git a/chrome/browser/apps/app_shim/app_shim_manager_mac.cc b/chrome/browser/apps/app_shim/app_shim_manager_mac.cc index 5e1097b..d370eef5 100644 --- a/chrome/browser/apps/app_shim/app_shim_manager_mac.cc +++ b/chrome/browser/apps/app_shim/app_shim_manager_mac.cc
@@ -308,6 +308,14 @@ // The profile state for the profiles currently running this app. std::map<Profile*, std::unique_ptr<ProfileState>> profiles; + + // When an app is terminated, we only want to save the last active profiles + // once. This field is set to true when a clean shutdown has already saved + // last active profiles, to prevent the code that exists to handle unclean + // shutdowns from overwriting the last active profiles. In case of a clean + // shutdown some browser windows/profiles might have already closed by the + // time OnShimProcessDisconnected runs. + bool did_save_last_active_profiles_on_terminate = false; }; AppShimManager::ProfileState::ProfileState( @@ -621,6 +629,7 @@ base::OnceClosure callback = base::BindOnce(&AppShimManager::LoadAndLaunchApp_OnProfilesAndAppReady, weak_factory_.GetWeakPtr(), profile_paths_to_launch, + /*first_profile_is_from_bootstrap=*/!profile_path.empty(), params, std::move(launch_callback)); { // This will update |callback| to be a chain of callbacks that load the @@ -708,6 +717,7 @@ void AppShimManager::LoadAndLaunchApp_OnProfilesAndAppReady( const std::vector<base::FilePath>& profile_paths_to_launch, + bool first_profile_is_from_bootstrap, const LoadAndLaunchAppParams& params, LoadAndLaunchAppCallback launch_callback) { // Launch all of the profiles in |profile_paths_to_launch|. Record the most @@ -753,10 +763,10 @@ if (params.HasFilesOrURLs()) break; - // If this was the first profile in |profile_paths_to_launch|, then this - // was the profile specified in the bootstrap, so stop here. - if (iter == 0) + // If this was the profile specified in the bootstrap, stop here. + if (first_profile_is_from_bootstrap && iter == 0) { break; + } } // If we launched any profile, report success. @@ -1026,7 +1036,9 @@ // For multi-profile apps, just delete the AppState, which will take down // |host| and all profiles' state. if (app_state->IsMultiProfile()) { - app_state->SaveLastActiveProfiles(); + if (!app_state->did_save_last_active_profiles_on_terminate) { + app_state->SaveLastActiveProfiles(); + } DCHECK_EQ(host, app_state->multi_profile_host.get()); apps_.erase(found_app); if (apps_.empty()) @@ -1136,6 +1148,19 @@ params, base::DoNothing()); } +void AppShimManager::OnShimWillTerminate(AppShimHost* host) { + auto found_app = apps_.find(host->GetAppId()); + DCHECK(found_app != apps_.end()); + AppState* app_state = found_app->second.get(); + DCHECK(app_state); + + if (app_state->IsMultiProfile()) { + DCHECK(!app_state->did_save_last_active_profiles_on_terminate); + app_state->SaveLastActiveProfiles(); + app_state->did_save_last_active_profiles_on_terminate = true; + } +} + void AppShimManager::OnProfileAdded(Profile* profile) { if (profile->IsOffTheRecord()) return;
diff --git a/chrome/browser/apps/app_shim/app_shim_manager_mac.h b/chrome/browser/apps/app_shim/app_shim_manager_mac.h index b9f80718..94bcdc6 100644 --- a/chrome/browser/apps/app_shim/app_shim_manager_mac.h +++ b/chrome/browser/apps/app_shim/app_shim_manager_mac.h
@@ -184,6 +184,7 @@ const std::vector<GURL>& urls) override; void OnShimOpenAppWithOverrideUrl(AppShimHost* host, const GURL& override_url) override; + void OnShimWillTerminate(AppShimHost* host) override; // AppLifetimeMonitor::Observer overrides: void OnAppStart(content::BrowserContext* context, const std::string& app_id) override; @@ -336,6 +337,7 @@ LoadAndLaunchAppCallback* launch_callback); void LoadAndLaunchApp_OnProfilesAndAppReady( const std::vector<base::FilePath>& profile_paths_to_launch, + bool first_profile_is_from_bootstrap, const LoadAndLaunchAppParams& params, LoadAndLaunchAppCallback launch_callback); void LoadAndLaunchApp_LaunchIfAppropriate(
diff --git a/chrome/browser/ash/arc/bluetooth/arc_bluetooth_bridge.cc b/chrome/browser/ash/arc/bluetooth/arc_bluetooth_bridge.cc index 6c057133..6cf5930 100644 --- a/chrome/browser/ash/arc/bluetooth/arc_bluetooth_bridge.cc +++ b/chrome/browser/ash/arc/bluetooth/arc_bluetooth_bridge.cc
@@ -606,6 +606,58 @@ OnForgetDone(mojom::BluetoothAddress::From(address)); } +void ArcBluetoothBridge::OnGetServiceRecordsFinished( + mojom::BluetoothAddressPtr remote_addr, + const BluetoothUUID& target_uuid, + const std::vector<bluez::BluetoothServiceRecordBlueZ>& records_bluez) { + auto* sdp_bluetooth_instance = ARC_GET_INSTANCE_FOR_METHOD( + arc_bridge_service_->bluetooth(), OnGetSdpRecords); + if (!sdp_bluetooth_instance) { + LOG(ERROR) << "Could not get bluetooth instance to return SDP records"; + return; + } + + std::vector<mojom::BluetoothSdpRecordPtr> records; + for (const auto& r : records_bluez) { + records.push_back(mojom::BluetoothSdpRecord::From(r)); + } + + sdp_bluetooth_instance->OnGetSdpRecords(mojom::BluetoothStatus::SUCCESS, + std::move(remote_addr), target_uuid, + std::move(records)); +} + +void ArcBluetoothBridge::OnGetServiceRecordsError( + mojom::BluetoothAddressPtr remote_addr, + const BluetoothUUID& target_uuid, + bluez::BluetoothServiceRecordBlueZ::ErrorCode error_code) { + auto* sdp_bluetooth_instance = ARC_GET_INSTANCE_FOR_METHOD( + arc_bridge_service_->bluetooth(), OnGetSdpRecords); + if (!sdp_bluetooth_instance) { + LOG(ERROR) << "Could not get bluetooth instance to return SDP error"; + return; + } + + mojom::BluetoothStatus status; + + switch (error_code) { + case bluez::BluetoothServiceRecordBlueZ::ErrorCode::ERROR_ADAPTER_NOT_READY: + status = mojom::BluetoothStatus::NOT_READY; + break; + case bluez::BluetoothServiceRecordBlueZ::ErrorCode:: + ERROR_DEVICE_DISCONNECTED: + status = mojom::BluetoothStatus::RMT_DEV_DOWN; + break; + default: + status = mojom::BluetoothStatus::FAIL; + break; + } + + sdp_bluetooth_instance->OnGetSdpRecords( + status, std::move(remote_addr), target_uuid, + std::vector<mojom::BluetoothSdpRecordPtr>()); +} + void ArcBluetoothBridge::GattServiceAdded(BluetoothAdapter* adapter, BluetoothDevice* device, BluetoothRemoteGattService* service) { @@ -1162,7 +1214,7 @@ void ArcBluetoothBridge::OnPoweredOn( ArcBluetoothBridge::AdapterStateCallback callback, - bool save_user_pref) const { + bool save_user_pref) { // Saves the power state to user preference only if Android initiated it. if (save_user_pref) SetPrimaryUserBluetoothPowerSetting(true); @@ -1173,11 +1225,14 @@ // should do this after the above callback since Android will clear its // device cache after receiving the "ON" state of adapter. SendCachedDevices(); + + // Allow derived classes to perform additional logic if desired. + HandlePoweredOn(); } void ArcBluetoothBridge::OnPoweredOff( ArcBluetoothBridge::AdapterStateCallback callback, - bool save_user_pref) const { + bool save_user_pref) { // Saves the power state to user preference only if Android initiated it. if (save_user_pref) SetPrimaryUserBluetoothPowerSetting(false); @@ -2714,112 +2769,17 @@ namespace { -constexpr int kAutoSockPort = 0; -constexpr int kMinRfcommChannel = 1; -constexpr int kMaxRfcommChannel = 30; - -// Copied from the values of L2CAP_PSM_LE_DYN_START and L2CAP_PSM_LE_DYN_END -// in /include/net/bluetooth/l2cap.h -constexpr int kMinL2capLePsm = 0x0080; -constexpr int kMaxL2capLePsm = 0x00FF; - -union BluetoothSocketAddress { - sockaddr sock; - sockaddr_rc rfcomm; - sockaddr_l2 l2cap; -}; - bool IsValidPort(mojom::BluetoothSocketType sock_type, int port) { switch (sock_type) { case mojom::BluetoothSocketType::TYPE_RFCOMM: - return port <= kMaxRfcommChannel && port >= kMinRfcommChannel; + return port <= ArcBluetoothBridge::kMaxRfcommChannel && + port >= ArcBluetoothBridge::kMinRfcommChannel; case mojom::BluetoothSocketType::TYPE_L2CAP_LE: - return port <= kMaxL2capLePsm && port >= kMinL2capLePsm; + return port <= ArcBluetoothBridge::kMaxL2capLePsm && + port >= ArcBluetoothBridge::kMinL2capLePsm; } } -int32_t GetSockOptvalFromFlags(mojom::BluetoothSocketType sock_type, - mojom::BluetoothSocketFlagsPtr sock_flags) { - int optval = 0; - switch (sock_type) { - case mojom::BluetoothSocketType::TYPE_RFCOMM: - optval |= sock_flags->encrypt ? RFCOMM_LM_ENCRYPT : 0; - optval |= sock_flags->auth ? RFCOMM_LM_AUTH : 0; - optval |= sock_flags->auth_mitm ? RFCOMM_LM_SECURE : 0; - optval |= sock_flags->auth_16_digit ? RFCOMM_LM_SECURE : 0; - return optval; - case mojom::BluetoothSocketType::TYPE_L2CAP_LE: - optval |= sock_flags->encrypt ? L2CAP_LM_ENCRYPT : 0; - optval |= sock_flags->auth ? L2CAP_LM_AUTH : 0; - optval |= sock_flags->auth_mitm ? L2CAP_LM_SECURE : 0; - optval |= sock_flags->auth_16_digit ? L2CAP_LM_SECURE : 0; - return optval; - } -} - -// Opens an AF_BLUETOOTH socket with |sock_type|, sets L2CAP_LM or RFCOMM_LM -// with |optval|, and binds the socket to address with |port|. -base::ScopedFD OpenBluetoothSocketImpl(mojom::BluetoothSocketType sock_type, - int32_t optval, - uint16_t port) { - int protocol; - int level; - int optname; - switch (sock_type) { - case mojom::BluetoothSocketType::TYPE_RFCOMM: - protocol = BTPROTO_RFCOMM; - level = SOL_RFCOMM; - optname = RFCOMM_LM; - break; - case mojom::BluetoothSocketType::TYPE_L2CAP_LE: - protocol = BTPROTO_L2CAP; - level = SOL_L2CAP; - optname = L2CAP_LM; - break; - default: - LOG(ERROR) << "Unknown socket type " << sock_type; - return {}; - } - - base::ScopedFD sock(socket(AF_BLUETOOTH, SOCK_STREAM, protocol)); - if (!sock.is_valid()) { - PLOG(ERROR) << "Failed to open bluetooth socket."; - return {}; - } - if (setsockopt(sock.get(), level, optname, &optval, sizeof(optval)) == -1) { - PLOG(ERROR) << "Failed to setopt() on socket."; - return {}; - } - if (fcntl(sock.get(), F_SETFL, O_NONBLOCK | fcntl(sock.get(), F_GETFL)) == - -1) { - PLOG(ERROR) << "Failed to fcntl() on socket."; - return {}; - } - - BluetoothSocketAddress sa = {}; - switch (sock_type) { - case mojom::BluetoothSocketType::TYPE_RFCOMM: - sa.rfcomm.rc_family = AF_BLUETOOTH; - sa.rfcomm.rc_channel = port; - break; - case mojom::BluetoothSocketType::TYPE_L2CAP_LE: - sa.l2cap.l2_family = AF_BLUETOOTH; - sa.l2cap.l2_psm = htobs(port); - sa.l2cap.l2_bdaddr_type = BDADDR_LE_PUBLIC; - break; - default: - LOG(ERROR) << "Unknown socket type " << sock_type; - return {}; - } - - if (bind(sock.get(), &sa.sock, sizeof(sa)) == -1) { - PLOG(ERROR) << "Failed to bind()"; - return {}; - } - - return sock; -} - } // namespace void ArcBluetoothBridge::BluetoothSocketListen( @@ -2843,29 +2803,8 @@ return; } - int32_t optval = GetSockOptvalFromFlags(sock_type, std::move(sock_flags)); - uint16_t listen_port = static_cast<uint16_t>(port); - auto sock_wrapper = - CreateBluetoothListenSocket(sock_type, optval, &listen_port); - if (!sock_wrapper) { - std::move(callback).Run( - mojom::BluetoothStatus::FAIL, /*port=*/0, - mojo::PendingReceiver<mojom::BluetoothListenSocketClient>()); - return; - } - - std::move(callback).Run(mojom::BluetoothStatus::SUCCESS, listen_port, - sock_wrapper->remote.BindNewPipeAndPassReceiver()); - sock_wrapper->remote.set_disconnect_handler( - base::BindOnce(&ArcBluetoothBridge::CloseBluetoothListeningSocket, - weak_factory_.GetWeakPtr(), sock_wrapper.get())); - listening_sockets_.insert(std::move(sock_wrapper)); -} - -void ArcBluetoothBridge::CloseBluetoothListeningSocket( - BluetoothListeningSocket* ptr) { - auto itr = listening_sockets_.find(ptr); - listening_sockets_.erase(itr); + CreateBluetoothListenSocket(sock_type, std::move(sock_flags), port, + std::move(callback)); } void ArcBluetoothBridge::BluetoothSocketConnect( @@ -2890,277 +2829,9 @@ return; } - int32_t optval = GetSockOptvalFromFlags(sock_type, std::move(sock_flags)); - auto sock_wrapper = CreateBluetoothConnectSocket( - sock_type, optval, std::move(remote_addr), static_cast<uint16_t>(port)); - if (!sock_wrapper) { - std::move(callback).Run( - mojom::BluetoothStatus::FAIL, - mojo::PendingReceiver<arc::mojom::BluetoothConnectSocketClient>()); - return; - } - - std::move(callback).Run(mojom::BluetoothStatus::SUCCESS, - sock_wrapper->remote.BindNewPipeAndPassReceiver()); - sock_wrapper->remote.set_disconnect_handler( - base::BindOnce(&ArcBluetoothBridge::CloseBluetoothConnectingSocket, - weak_factory_.GetWeakPtr(), sock_wrapper.get())); - connecting_sockets_.insert(std::move(sock_wrapper)); -} - -void ArcBluetoothBridge::CloseBluetoothConnectingSocket( - BluetoothConnectingSocket* ptr) { - auto itr = connecting_sockets_.find(ptr); - connecting_sockets_.erase(itr); -} - -std::unique_ptr<ArcBluetoothBridge::BluetoothListeningSocket> -ArcBluetoothBridge::CreateBluetoothListenSocket( - mojom::BluetoothSocketType sock_type, - int32_t optval, - uint16_t* port) { - DCHECK(port); - base::ScopedFD sock = OpenBluetoothSocketImpl(sock_type, optval, *port); - if (!sock.is_valid()) { - LOG(ERROR) << "Failed to open listen socket."; - return nullptr; - } - - if (listen(sock.get(), /*backlog=*/1) == -1) { - PLOG(ERROR) << "Failed to listen()"; - return nullptr; - } - - BluetoothSocketAddress local_addr; - socklen_t addr_len = sizeof(local_addr); - if (getsockname(sock.get(), &local_addr.sock, &addr_len) == -1) { - PLOG(ERROR) << "Failed to getsockname()"; - return nullptr; - } - - auto sock_wrapper = std::make_unique<BluetoothListeningSocket>(); - sock_wrapper->sock_type = sock_type; - sock_wrapper->controller = base::FileDescriptorWatcher::WatchReadable( - sock.get(), - base::BindRepeating(&ArcBluetoothBridge::OnBluetoothListeningSocketReady, - weak_factory_.GetWeakPtr(), sock_wrapper.get())); - sock_wrapper->file = std::move(sock); - - switch (sock_type) { - case mojom::BluetoothSocketType::TYPE_RFCOMM: - *port = local_addr.rfcomm.rc_channel; - break; - case mojom::BluetoothSocketType::TYPE_L2CAP_LE: - *port = btohs(local_addr.l2cap.l2_psm); - break; - default: - LOG(ERROR) << "Unknown socket type " << sock_type; - return nullptr; - } - - return sock_wrapper; -} - -void ArcBluetoothBridge::OnBluetoothListeningSocketReady( - ArcBluetoothBridge::BluetoothListeningSocket* sock_wrapper) { - BluetoothSocketAddress sa; - socklen_t addr_len = sizeof(sa); - base::ScopedFD accept_fd( - accept(sock_wrapper->file.get(), &sa.sock, &addr_len)); - if (!accept_fd.is_valid()) { - PLOG(ERROR) << "Failed to accept()"; - return; - } - if (fcntl(accept_fd.get(), F_SETFL, - O_NONBLOCK | fcntl(accept_fd.get(), F_GETFL)) == -1) { - PLOG(ERROR) << "Failed to fnctl()"; - return; - } - - mojo::ScopedHandle handle = - mojo::WrapPlatformHandle(mojo::PlatformHandle(std::move(accept_fd))); - - // Tells Android we successfully accept() a new connection. - if (sock_wrapper->created_by_deprecated_method) { - auto connection = mojom::BluetoothRfcommConnection::New(); - connection->sock = std::move(handle); - connection->addr = - mojom::BluetoothAddress::From<bdaddr_t>(sa.rfcomm.rc_bdaddr); - connection->channel = sa.rfcomm.rc_channel; - sock_wrapper->deprecated_remote->OnAccepted(std::move(connection)); - } else { - auto connection = mojom::BluetoothSocketConnection::New(); - connection->sock = std::move(handle); - switch (sock_wrapper->sock_type) { - case mojom::BluetoothSocketType::TYPE_RFCOMM: - connection->addr = - mojom::BluetoothAddress::From<bdaddr_t>(sa.rfcomm.rc_bdaddr); - connection->port = sa.rfcomm.rc_channel; - break; - case mojom::BluetoothSocketType::TYPE_L2CAP_LE: - connection->addr = - mojom::BluetoothAddress::From<bdaddr_t>(sa.l2cap.l2_bdaddr); - connection->port = btohs(sa.l2cap.l2_psm); - break; - default: - LOG(ERROR) << "Unknown socket type " << sock_wrapper->sock_type; - return; - } - sock_wrapper->remote->OnAccepted(std::move(connection)); - } -} - -std::unique_ptr<ArcBluetoothBridge::BluetoothConnectingSocket> -ArcBluetoothBridge::CreateBluetoothConnectSocket( - mojom::BluetoothSocketType sock_type, - int32_t optval, - mojom::BluetoothAddressPtr addr, - uint16_t port) { - base::ScopedFD sock = - OpenBluetoothSocketImpl(sock_type, optval, kAutoSockPort); - if (!sock.is_valid()) { - LOG(ERROR) << "Failed to open connect socket."; - return nullptr; - } - - std::string addr_str = addr->To<std::string>(); - BluetoothDevice* device = bluetooth_adapter_->GetDevice(addr_str); - if (!device) - return nullptr; - - const auto addr_type = device->GetAddressType(); - if (addr_type == BluetoothDevice::ADDR_TYPE_UNKNOWN) { - LOG(ERROR) << "Unknown address type."; - return nullptr; - } - - BluetoothSocketAddress sa = {}; - switch (sock_type) { - case mojom::BluetoothSocketType::TYPE_RFCOMM: - sa.rfcomm.rc_family = AF_BLUETOOTH; - sa.rfcomm.rc_bdaddr = addr->To<bdaddr_t>(); - sa.rfcomm.rc_channel = static_cast<uint8_t>(port); - break; - case mojom::BluetoothSocketType::TYPE_L2CAP_LE: - sa.l2cap.l2_family = AF_BLUETOOTH; - sa.l2cap.l2_bdaddr = addr->To<bdaddr_t>(); - sa.l2cap.l2_psm = htobs(port); - sa.l2cap.l2_bdaddr_type = addr_type == BluetoothDevice::ADDR_TYPE_PUBLIC - ? BDADDR_LE_PUBLIC - : BDADDR_LE_RANDOM; - break; - default: - LOG(ERROR) << "Unknown socket type " << sock_type; - return nullptr; - } - - int ret = HANDLE_EINTR(connect( - sock.get(), reinterpret_cast<const struct sockaddr*>(&sa), sizeof(sa))); - - auto sock_wrapper = - std::make_unique<ArcBluetoothBridge::BluetoothConnectingSocket>(); - sock_wrapper->sock_type = sock_type; - if (ret == 0) { - // connect() returns success immediately. - sock_wrapper->file = std::move(sock); - // BluetoothSocketConnect() is a blocking mojo call on the ARC side, so the - // callback needs to be triggered asynchronously and thus we use a PostTask - // here. - base::SequencedTaskRunner::GetCurrentDefault()->PostTask( - FROM_HERE, - base::BindOnce(&ArcBluetoothBridge::OnBluetoothConnectingSocketReady, - weak_factory_.GetWeakPtr(), sock_wrapper.get())); - return sock_wrapper; - } - if (errno != EINPROGRESS) { - PLOG(ERROR) << "Failed to connect."; - return nullptr; - } - - sock_wrapper->controller = base::FileDescriptorWatcher::WatchWritable( - sock.get(), - base::BindRepeating(&ArcBluetoothBridge::OnBluetoothConnectingSocketReady, - weak_factory_.GetWeakPtr(), sock_wrapper.get())); - sock_wrapper->file = std::move(sock); - return sock_wrapper; -} - -void ArcBluetoothBridge::OnBluetoothConnectingSocketReady( - ArcBluetoothBridge::BluetoothConnectingSocket* sock_wrapper) { - // When connect() is ready, we will transfer this fd to Android, and Android - // is responsible for closing it. The file watcher |controller| needs to be - // disabled first, and then the fd ownership is transferred. - sock_wrapper->controller.reset(); - base::ScopedFD fd = std::move(sock_wrapper->file); - - // Checks whether connect() succeeded. - int err = 0; - socklen_t len = sizeof(err); - int ret = getsockopt(fd.get(), SOL_SOCKET, SO_ERROR, &err, &len); - if (ret != 0 || err != 0) { - LOG(ERROR) << "Failed to connect. err=" << err; - if (sock_wrapper->created_by_deprecated_method) - sock_wrapper->deprecated_remote->OnConnectFailed(); - else - sock_wrapper->remote->OnConnectFailed(); - return; - } - - // Gets peer address. - BluetoothSocketAddress peer_sa; - socklen_t peer_sa_len = sizeof(peer_sa); - if (getpeername(fd.get(), &peer_sa.sock, &peer_sa_len) == -1) { - PLOG(ERROR) << "Failed to getpeername()."; - if (sock_wrapper->created_by_deprecated_method) - sock_wrapper->deprecated_remote->OnConnectFailed(); - else - sock_wrapper->remote->OnConnectFailed(); - return; - } - - // Gets our port. - BluetoothSocketAddress local_sa; - socklen_t local_sa_len = sizeof(local_sa); - if (getsockname(fd.get(), &local_sa.sock, &local_sa_len) == -1) { - PLOG(ERROR) << "Failed to getsockname()"; - if (sock_wrapper->created_by_deprecated_method) - sock_wrapper->deprecated_remote->OnConnectFailed(); - else - sock_wrapper->remote->OnConnectFailed(); - return; - } - - mojo::ScopedHandle handle = - mojo::WrapPlatformHandle(mojo::PlatformHandle(std::move(fd))); - - // Notifies Android. - if (sock_wrapper->created_by_deprecated_method) { - auto connection = mojom::BluetoothRfcommConnection::New(); - connection->sock = std::move(handle); - connection->addr = - mojom::BluetoothAddress::From<bdaddr_t>(peer_sa.rfcomm.rc_bdaddr); - connection->channel = local_sa.rfcomm.rc_channel; - sock_wrapper->deprecated_remote->OnConnected(std::move(connection)); - } else { - auto connection = mojom::BluetoothSocketConnection::New(); - connection->sock = std::move(handle); - switch (sock_wrapper->sock_type) { - case mojom::BluetoothSocketType::TYPE_RFCOMM: - connection->addr = - mojom::BluetoothAddress::From<bdaddr_t>(peer_sa.rfcomm.rc_bdaddr); - connection->port = local_sa.rfcomm.rc_channel; - break; - case mojom::BluetoothSocketType::TYPE_L2CAP_LE: - connection->addr = - mojom::BluetoothAddress::From<bdaddr_t>(peer_sa.l2cap.l2_bdaddr); - connection->port = btohs(local_sa.l2cap.l2_psm); - break; - default: - LOG(ERROR) << "Unknown socket type " << sock_wrapper->sock_type; - return; - } - sock_wrapper->remote->OnConnected(std::move(connection)); - } + CreateBluetoothConnectSocket(sock_type, std::move(sock_flags), + std::move(remote_addr), port, + std::move(callback)); } // static
diff --git a/chrome/browser/ash/arc/bluetooth/arc_bluetooth_bridge.h b/chrome/browser/ash/arc/bluetooth/arc_bluetooth_bridge.h index 92dc487e..308d27ce 100644 --- a/chrome/browser/ash/arc/bluetooth/arc_bluetooth_bridge.h +++ b/chrome/browser/ash/arc/bluetooth/arc_bluetooth_bridge.h
@@ -73,6 +73,15 @@ using RemoveSdpRecordCallback = base::OnceCallback<void(arc::mojom::BluetoothStatus)>; + static constexpr int kAutoSockPort = 0; + static constexpr int kMinRfcommChannel = 1; + static constexpr int kMaxRfcommChannel = 30; + + // Copied from the values of L2CAP_PSM_LE_DYN_START and L2CAP_PSM_LE_DYN_END + // in /include/net/bluetooth/l2cap.h + static constexpr int kMinL2capLePsm = 0x0080; + static constexpr int kMaxL2capLePsm = 0x00FF; + // Returns singleton instance for the given BrowserContext, // or nullptr if the browser |context| is not allowed to use ARC. static ArcBluetoothBridge* GetForBrowserContext( @@ -341,6 +350,8 @@ static void EnsureFactoryBuilt(); protected: + virtual void HandlePoweredOn() = 0; + void ReserveAdvertisementHandleImpl( ReserveAdvertisementHandleCallback callback); void EnableAdvertisementImpl( @@ -367,8 +378,8 @@ enum class AdapterPowerState { TURN_OFF, TURN_ON }; // Chrome observer callbacks - void OnPoweredOn(AdapterStateCallback callback, bool save_user_pref) const; - void OnPoweredOff(AdapterStateCallback callback, bool save_user_pref) const; + void OnPoweredOn(AdapterStateCallback callback, bool save_user_pref); + void OnPoweredOff(AdapterStateCallback callback, bool save_user_pref); void OnPoweredError(AdapterStateCallback callback) const; void OnDiscoveryStarted( std::unique_ptr<device::BluetoothDiscoverySession> session); @@ -384,6 +395,15 @@ void OnForgetDone(mojom::BluetoothAddressPtr addr); void OnForgetError(mojom::BluetoothAddressPtr addr) const; + void OnGetServiceRecordsFinished( + mojom::BluetoothAddressPtr remote_addr, + const device::BluetoothUUID& target_uuid, + const std::vector<bluez::BluetoothServiceRecordBlueZ>& records_bluez); + void OnGetServiceRecordsError( + mojom::BluetoothAddressPtr remote_addr, + const device::BluetoothUUID& target_uuid, + bluez::BluetoothServiceRecordBlueZ::ErrorCode error_code); + void OnGattConnectStateChanged(mojom::BluetoothAddressPtr addr, bool connected) const; void OnGattConnect( @@ -544,10 +564,6 @@ // Chrome. struct BluetoothListeningSocket { mojom::BluetoothSocketType sock_type; - // TODO(b/163099156): Remove the following two fields when - // RfcommListenDeprecated()/RfcommConnectDeprecated() are removed. - bool created_by_deprecated_method = false; - mojo::Remote<mojom::RfcommListeningSocketClient> deprecated_remote; mojo::Remote<mojom::BluetoothListenSocketClient> remote; base::ScopedFD file; std::unique_ptr<base::FileDescriptorWatcher::Controller> controller; @@ -556,10 +572,6 @@ }; struct BluetoothConnectingSocket { mojom::BluetoothSocketType sock_type; - // TODO(b/163099156): Remove the following two fields when - // RfcommListenDeprecated()/RfcommConnectDeprecated() are removed. - bool created_by_deprecated_method = false; - mojo::Remote<mojom::RfcommConnectingSocketClient> deprecated_remote; mojo::Remote<mojom::BluetoothConnectSocketClient> remote; base::ScopedFD file; std::unique_ptr<base::FileDescriptorWatcher::Controller> controller; @@ -567,26 +579,24 @@ ~BluetoothConnectingSocket(); }; - // Creates a Bluetooth socket with socket option |optval|, and then bind() and - // listen() with requested |port| number. The actual port number will be - // filled in |port| as the return value. Returns a BluetoothListeningSocket - // that holds the socket. - std::unique_ptr<BluetoothListeningSocket> CreateBluetoothListenSocket( + // Creates a Bluetooth socket with options in |flags| and starts listening to + // it with the requested |port| number. The actual port number must be filled + // in and sent to the callback in this function implementation. Returns a + // BluetoothListeningSocket that holds the socket. + virtual void CreateBluetoothListenSocket( mojom::BluetoothSocketType type, - int32_t optval, - uint16_t* port); + mojom::BluetoothSocketFlagsPtr flags, + int port, + BluetoothSocketListenCallback callback) = 0; // Creates a Bluetooth socket with socket option |optval|, and then calls // connect() to (|addr|, |port|). This connect() call is non-blocking. // Returns a BluetoothConnectingSocket that holds the socket. - std::unique_ptr<BluetoothConnectingSocket> CreateBluetoothConnectSocket( + virtual void CreateBluetoothConnectSocket( mojom::BluetoothSocketType type, - int32_t optval, + mojom::BluetoothSocketFlagsPtr flags, mojom::BluetoothAddressPtr addr, - uint16_t port); - - // Closes Bluetooth sockets. Releases the corresponding resources. - void CloseBluetoothListeningSocket(BluetoothListeningSocket* socket); - void CloseBluetoothConnectingSocket(BluetoothConnectingSocket* socket); + int port, + BluetoothSocketConnectCallback callback) = 0; // Called when the listening socket is ready to accept(). void OnBluetoothListeningSocketReady( @@ -704,13 +714,6 @@ // Start/StopLEScan(). ArcBluetoothTaskQueue discovery_queue_; - // Bluetooth sockets that live in Chrome. - std::set<std::unique_ptr<BluetoothListeningSocket>, base::UniquePtrComparator> - listening_sockets_; - std::set<std::unique_ptr<BluetoothConnectingSocket>, - base::UniquePtrComparator> - connecting_sockets_; - // Observes the ARC connection to Bluetooth service in Android. We need to do // some cleanup when it is down. class BluetoothArcConnectionObserver
diff --git a/chrome/browser/ash/arc/bluetooth/arc_bluez_bridge.cc b/chrome/browser/ash/arc/bluetooth/arc_bluez_bridge.cc index ef1038c57..cd322f0 100644 --- a/chrome/browser/ash/arc/bluetooth/arc_bluez_bridge.cc +++ b/chrome/browser/ash/arc/bluetooth/arc_bluez_bridge.cc
@@ -4,8 +4,16 @@ #include "chrome/browser/ash/arc/bluetooth/arc_bluez_bridge.h" +#include <bluetooth/bluetooth.h> +#include <bluetooth/l2cap.h> +#include <bluetooth/rfcomm.h> +#include <fcntl.h> +#include <stdint.h> +#include <sys/socket.h> + #include "ash/components/arc/bluetooth/bluetooth_type_converters.h" #include "ash/components/arc/session/arc_bridge_service.h" +#include "base/posix/eintr_wrapper.h" #include "device/bluetooth/bluetooth_common.h" #include "device/bluetooth/bluetooth_device.h" #include "device/bluetooth/bluez/bluetooth_device_bluez.h" @@ -94,6 +102,8 @@ return static_cast<bluez::BluetoothAdapterBlueZ*>(bluetooth_adapter_.get()); } +void ArcBluezBridge::HandlePoweredOn() {} + void ArcBluezBridge::GetSdpRecords(mojom::BluetoothAddressPtr remote_addr, const BluetoothUUID& target_uuid) { BluetoothDevice* device = @@ -111,7 +121,7 @@ mojom::BluetoothAddressPtr remote_addr_clone = remote_addr.Clone(); device_bluez->GetServiceRecords( - base::BindOnce(&ArcBluezBridge::OnGetServiceRecordsDone, + base::BindOnce(&ArcBluezBridge::OnGetServiceRecordsFinished, weak_factory_.GetWeakPtr(), std::move(remote_addr), target_uuid), base::BindOnce(&ArcBluezBridge::OnGetServiceRecordsError, @@ -154,6 +164,18 @@ std::move(split_callback.second))); } +void ArcBluezBridge::CloseBluetoothListeningSocket( + BluetoothListeningSocket* ptr) { + auto itr = listening_sockets_.find(ptr); + listening_sockets_.erase(itr); +} + +void ArcBluezBridge::CloseBluetoothConnectingSocket( + BluetoothConnectingSocket* ptr) { + auto itr = connecting_sockets_.find(ptr); + connecting_sockets_.erase(itr); +} + void ArcBluezBridge::OnGetServiceRecordsDone( mojom::BluetoothAddressPtr remote_addr, const BluetoothUUID& target_uuid, @@ -204,4 +226,348 @@ std::vector<mojom::BluetoothSdpRecordPtr>()); } +namespace { + +union BluetoothSocketAddress { + sockaddr sock; + sockaddr_rc rfcomm; + sockaddr_l2 l2cap; +}; + +int32_t GetSockOptvalFromFlags(mojom::BluetoothSocketType sock_type, + mojom::BluetoothSocketFlagsPtr sock_flags) { + int optval = 0; + switch (sock_type) { + case mojom::BluetoothSocketType::TYPE_RFCOMM: + optval |= sock_flags->encrypt ? RFCOMM_LM_ENCRYPT : 0; + optval |= sock_flags->auth ? RFCOMM_LM_AUTH : 0; + optval |= sock_flags->auth_mitm ? RFCOMM_LM_SECURE : 0; + optval |= sock_flags->auth_16_digit ? RFCOMM_LM_SECURE : 0; + return optval; + case mojom::BluetoothSocketType::TYPE_L2CAP_LE: + optval |= sock_flags->encrypt ? L2CAP_LM_ENCRYPT : 0; + optval |= sock_flags->auth ? L2CAP_LM_AUTH : 0; + optval |= sock_flags->auth_mitm ? L2CAP_LM_SECURE : 0; + optval |= sock_flags->auth_16_digit ? L2CAP_LM_SECURE : 0; + return optval; + } +} + +// Opens an AF_BLUETOOTH socket with |sock_type|, sets L2CAP_LM or RFCOMM_LM +// with |optval|, and binds the socket to address with |port|. +base::ScopedFD OpenBluetoothSocketImpl(mojom::BluetoothSocketType sock_type, + int32_t optval, + uint16_t port) { + int protocol; + int level; + int optname; + switch (sock_type) { + case mojom::BluetoothSocketType::TYPE_RFCOMM: + protocol = BTPROTO_RFCOMM; + level = SOL_RFCOMM; + optname = RFCOMM_LM; + break; + case mojom::BluetoothSocketType::TYPE_L2CAP_LE: + protocol = BTPROTO_L2CAP; + level = SOL_L2CAP; + optname = L2CAP_LM; + break; + default: + LOG(ERROR) << "Unknown socket type " << sock_type; + return {}; + } + + base::ScopedFD sock(socket(AF_BLUETOOTH, SOCK_STREAM, protocol)); + if (!sock.is_valid()) { + PLOG(ERROR) << "Failed to open bluetooth socket."; + return {}; + } + if (setsockopt(sock.get(), level, optname, &optval, sizeof(optval)) == -1) { + PLOG(ERROR) << "Failed to setopt() on socket."; + return {}; + } + if (fcntl(sock.get(), F_SETFL, O_NONBLOCK | fcntl(sock.get(), F_GETFL)) == + -1) { + PLOG(ERROR) << "Failed to fcntl() on socket."; + return {}; + } + + BluetoothSocketAddress sa = {}; + switch (sock_type) { + case mojom::BluetoothSocketType::TYPE_RFCOMM: + sa.rfcomm.rc_family = AF_BLUETOOTH; + sa.rfcomm.rc_channel = port; + break; + case mojom::BluetoothSocketType::TYPE_L2CAP_LE: + sa.l2cap.l2_family = AF_BLUETOOTH; + sa.l2cap.l2_psm = htobs(port); + sa.l2cap.l2_bdaddr_type = BDADDR_LE_PUBLIC; + break; + default: + LOG(ERROR) << "Unknown socket type " << sock_type; + return {}; + } + + if (bind(sock.get(), &sa.sock, sizeof(sa)) == -1) { + PLOG(ERROR) << "Failed to bind()"; + return {}; + } + + return sock; +} + +} // namespace + +void ArcBluezBridge::OnBluezListeningSocketReady( + ArcBluezBridge::BluetoothListeningSocket* sock_wrapper) { + BluetoothSocketAddress sa; + socklen_t addr_len = sizeof(sa); + base::ScopedFD accept_fd( + accept(sock_wrapper->file.get(), &sa.sock, &addr_len)); + if (!accept_fd.is_valid()) { + PLOG(ERROR) << "Failed to accept()"; + return; + } + if (fcntl(accept_fd.get(), F_SETFL, + O_NONBLOCK | fcntl(accept_fd.get(), F_GETFL)) == -1) { + PLOG(ERROR) << "Failed to fnctl()"; + return; + } + + mojo::ScopedHandle handle = + mojo::WrapPlatformHandle(mojo::PlatformHandle(std::move(accept_fd))); + + // Tells Android we successfully accept() a new connection. + auto connection = mojom::BluetoothSocketConnection::New(); + connection->sock = std::move(handle); + switch (sock_wrapper->sock_type) { + case mojom::BluetoothSocketType::TYPE_RFCOMM: + connection->addr = + mojom::BluetoothAddress::From<bdaddr_t>(sa.rfcomm.rc_bdaddr); + connection->port = sa.rfcomm.rc_channel; + break; + case mojom::BluetoothSocketType::TYPE_L2CAP_LE: + connection->addr = + mojom::BluetoothAddress::From<bdaddr_t>(sa.l2cap.l2_bdaddr); + connection->port = btohs(sa.l2cap.l2_psm); + break; + default: + LOG(ERROR) << "Unknown socket type " << sock_wrapper->sock_type; + return; + } + + sock_wrapper->remote->OnAccepted(std::move(connection)); +} + +void ArcBluezBridge::OnBluezConnectingSocketReady( + ArcBluezBridge::BluetoothConnectingSocket* sock_wrapper) { + // When connect() is ready, we will transfer this fd to Android, and Android + // is responsible for closing it. The file watcher |controller| needs to be + // disabled first, and then the fd ownership is transferred. + sock_wrapper->controller.reset(); + base::ScopedFD fd = std::move(sock_wrapper->file); + + // Checks whether connect() succeeded. + int err = 0; + socklen_t len = sizeof(err); + int ret = getsockopt(fd.get(), SOL_SOCKET, SO_ERROR, &err, &len); + if (ret != 0 || err != 0) { + LOG(ERROR) << "Failed to connect. err=" << err; + sock_wrapper->remote->OnConnectFailed(); + } + + // Gets peer address. + BluetoothSocketAddress peer_sa; + socklen_t peer_sa_len = sizeof(peer_sa); + if (getpeername(fd.get(), &peer_sa.sock, &peer_sa_len) == -1) { + PLOG(ERROR) << "Failed to getpeername()."; + sock_wrapper->remote->OnConnectFailed(); + } + + // Gets our port. + BluetoothSocketAddress local_sa; + socklen_t local_sa_len = sizeof(local_sa); + if (getsockname(fd.get(), &local_sa.sock, &local_sa_len) == -1) { + PLOG(ERROR) << "Failed to getsockname()"; + sock_wrapper->remote->OnConnectFailed(); + } + + mojo::ScopedHandle handle = + mojo::WrapPlatformHandle(mojo::PlatformHandle(std::move(fd))); + + // Notifies Android. + auto connection = mojom::BluetoothSocketConnection::New(); + connection->sock = std::move(handle); + switch (sock_wrapper->sock_type) { + case mojom::BluetoothSocketType::TYPE_RFCOMM: + connection->addr = + mojom::BluetoothAddress::From<bdaddr_t>(peer_sa.rfcomm.rc_bdaddr); + connection->port = local_sa.rfcomm.rc_channel; + break; + case mojom::BluetoothSocketType::TYPE_L2CAP_LE: + connection->addr = + mojom::BluetoothAddress::From<bdaddr_t>(peer_sa.l2cap.l2_bdaddr); + connection->port = btohs(local_sa.l2cap.l2_psm); + break; + default: + LOG(ERROR) << "Unknown socket type " << sock_wrapper->sock_type; + return; + } + sock_wrapper->remote->OnConnected(std::move(connection)); +} + +void ArcBluezBridge::CreateBluetoothListenSocket( + mojom::BluetoothSocketType type, + mojom::BluetoothSocketFlagsPtr flags, + int port, + BluetoothSocketListenCallback callback) { + std::unique_ptr<ArcBluezBridge::BluetoothListeningSocket> sock_wrapper = + nullptr; + int32_t optval = GetSockOptvalFromFlags(type, std::move(flags)); + uint16_t listen_port = static_cast<uint16_t>(port); + + do { + base::ScopedFD sock = OpenBluetoothSocketImpl(type, optval, listen_port); + if (!sock.is_valid()) { + LOG(ERROR) << "Failed to open listen socket."; + break; + } + + if (listen(sock.get(), /*backlog=*/1) == -1) { + PLOG(ERROR) << "Failed to listen()"; + break; + } + + BluetoothSocketAddress local_addr; + socklen_t addr_len = sizeof(local_addr); + if (getsockname(sock.get(), &local_addr.sock, &addr_len) == -1) { + PLOG(ERROR) << "Failed to getsockname()"; + break; + } + + sock_wrapper = std::make_unique<BluetoothListeningSocket>(); + sock_wrapper->sock_type = type; + sock_wrapper->controller = base::FileDescriptorWatcher::WatchReadable( + sock.get(), + base::BindRepeating(&ArcBluezBridge::OnBluezListeningSocketReady, + weak_factory_.GetWeakPtr(), sock_wrapper.get())); + sock_wrapper->file = std::move(sock); + + if (type == mojom::BluetoothSocketType::TYPE_RFCOMM) { + listen_port = local_addr.rfcomm.rc_channel; + } else if (type == mojom::BluetoothSocketType::TYPE_L2CAP_LE) { + listen_port = btohs(local_addr.l2cap.l2_psm); + } else { + LOG(ERROR) << "Unknown socket type " << type; + break; + } + } while (!sock_wrapper.get()); + + if (sock_wrapper) { + std::move(callback).Run(mojom::BluetoothStatus::SUCCESS, listen_port, + sock_wrapper->remote.BindNewPipeAndPassReceiver()); + sock_wrapper->remote.set_disconnect_handler( + base::BindOnce(&ArcBluezBridge::CloseBluetoothListeningSocket, + weak_factory_.GetWeakPtr(), sock_wrapper.get())); + listening_sockets_.insert(std::move(sock_wrapper)); + } else { + std::move(callback).Run( + mojom::BluetoothStatus::FAIL, /*port=*/0, + mojo::PendingReceiver<mojom::BluetoothListenSocketClient>()); + } +} + +void ArcBluezBridge::CreateBluetoothConnectSocket( + mojom::BluetoothSocketType type, + mojom::BluetoothSocketFlagsPtr flags, + mojom::BluetoothAddressPtr addr, + int port, + BluetoothSocketConnectCallback callback) { + std::unique_ptr<ArcBluetoothBridge::BluetoothConnectingSocket> sock_wrapper = + nullptr; + int32_t optval = GetSockOptvalFromFlags(type, std::move(flags)); + base::ScopedFD sock = OpenBluetoothSocketImpl(type, optval, kAutoSockPort); + int ret = 0; + + do { + if (!sock.is_valid()) { + LOG(ERROR) << "Failed to open connect socket."; + break; + } + + std::string addr_str = addr->To<std::string>(); + BluetoothDevice* device = bluetooth_adapter_->GetDevice(addr_str); + if (!device) { + break; + } + + const auto addr_type = device->GetAddressType(); + if (addr_type == BluetoothDevice::ADDR_TYPE_UNKNOWN) { + LOG(ERROR) << "Unknown address type."; + break; + } + + BluetoothSocketAddress sa = {}; + if (type == mojom::BluetoothSocketType::TYPE_RFCOMM) { + sa.rfcomm.rc_family = AF_BLUETOOTH; + sa.rfcomm.rc_bdaddr = addr->To<bdaddr_t>(); + sa.rfcomm.rc_channel = static_cast<uint8_t>(port); + } else if (type == mojom::BluetoothSocketType::TYPE_L2CAP_LE) { + sa.l2cap.l2_family = AF_BLUETOOTH; + sa.l2cap.l2_bdaddr = addr->To<bdaddr_t>(); + sa.l2cap.l2_psm = htobs(port); + sa.l2cap.l2_bdaddr_type = addr_type == BluetoothDevice::ADDR_TYPE_PUBLIC + ? BDADDR_LE_PUBLIC + : BDADDR_LE_RANDOM; + } else { + LOG(ERROR) << "Unknown socket type " << type; + } + + ret = HANDLE_EINTR(connect( + sock.get(), reinterpret_cast<const struct sockaddr*>(&sa), sizeof(sa))); + + sock_wrapper = + std::make_unique<ArcBluetoothBridge::BluetoothConnectingSocket>(); + sock_wrapper->sock_type = type; + } while (sock_wrapper == nullptr); + + if (sock_wrapper) { + if (ret == 0) { + // connect() returns success immediately. + sock_wrapper->file = std::move(sock); + // BluetoothSocketConnect() is a blocking mojo call on the ARC side, so + // the callback needs to be triggered asynchronously and thus we use a + // PostTask here. + base::SequencedTaskRunner::GetCurrentDefault()->PostTask( + FROM_HERE, + base::BindOnce(&ArcBluezBridge::OnBluezConnectingSocketReady, + weak_factory_.GetWeakPtr(), sock_wrapper.get())); + } else if (errno == EINPROGRESS) { + sock_wrapper->controller = base::FileDescriptorWatcher::WatchWritable( + sock.get(), + base::BindRepeating(&ArcBluezBridge::OnBluezConnectingSocketReady, + weak_factory_.GetWeakPtr(), sock_wrapper.get())); + sock_wrapper->file = std::move(sock); + } else { + PLOG(ERROR) << "Failed to connect."; + std::move(callback).Run( + mojom::BluetoothStatus::FAIL, + mojo::PendingReceiver<arc::mojom::BluetoothConnectSocketClient>()); + return; + } + } else { + std::move(callback).Run( + mojom::BluetoothStatus::FAIL, + mojo::PendingReceiver<arc::mojom::BluetoothConnectSocketClient>()); + return; + } + + std::move(callback).Run(mojom::BluetoothStatus::SUCCESS, + sock_wrapper->remote.BindNewPipeAndPassReceiver()); + sock_wrapper->remote.set_disconnect_handler( + base::BindOnce(&ArcBluezBridge::CloseBluetoothConnectingSocket, + weak_factory_.GetWeakPtr(), sock_wrapper.get())); + connecting_sockets_.insert(std::move(sock_wrapper)); +} + } // namespace arc
diff --git a/chrome/browser/ash/arc/bluetooth/arc_bluez_bridge.h b/chrome/browser/ash/arc/bluetooth/arc_bluez_bridge.h index d03cd810..1a43dfb5 100644 --- a/chrome/browser/ash/arc/bluetooth/arc_bluez_bridge.h +++ b/chrome/browser/ash/arc/bluetooth/arc_bluez_bridge.h
@@ -30,9 +30,15 @@ void RemoveSdpRecord(uint32_t service_handle, RemoveSdpRecordCallback callback) override; + // Closes Bluetooth sockets. Releases the corresponding resources. + void CloseBluetoothListeningSocket(BluetoothListeningSocket* socket); + void CloseBluetoothConnectingSocket(BluetoothConnectingSocket* socket); + protected: bluez::BluetoothAdapterBlueZ* GetAdapter() const; + void HandlePoweredOn() override; + void OnGetServiceRecordsDone( mojom::BluetoothAddressPtr remote_addr, const device::BluetoothUUID& target_uuid, @@ -42,7 +48,33 @@ const device::BluetoothUUID& target_uuid, bluez::BluetoothServiceRecordBlueZ::ErrorCode error_code); + // Called when the listening socket is ready to accept(). + void OnBluezListeningSocketReady(BluetoothListeningSocket* sock_wrapper); + + // Called when the connecting socket is ready. + void OnBluezConnectingSocketReady(BluetoothConnectingSocket* sock_wrapper); + + void CreateBluetoothListenSocket( + mojom::BluetoothSocketType type, + mojom::BluetoothSocketFlagsPtr flags, + int port, + BluetoothSocketListenCallback callback) override; + + void CreateBluetoothConnectSocket( + mojom::BluetoothSocketType type, + mojom::BluetoothSocketFlagsPtr flags, + mojom::BluetoothAddressPtr addr, + int port, + BluetoothSocketConnectCallback callback) override; + private: + // Bluetooth sockets that live in Chrome. + std::set<std::unique_ptr<BluetoothListeningSocket>, base::UniquePtrComparator> + listening_sockets_; + std::set<std::unique_ptr<BluetoothConnectingSocket>, + base::UniquePtrComparator> + connecting_sockets_; + // WeakPtrFactory to use for callbacks. base::WeakPtrFactory<ArcBluezBridge> weak_factory_{this}; };
diff --git a/chrome/browser/ash/arc/bluetooth/arc_floss_bridge.cc b/chrome/browser/ash/arc/bluetooth/arc_floss_bridge.cc index 23e5fe2..8a81bd2 100644 --- a/chrome/browser/ash/arc/bluetooth/arc_floss_bridge.cc +++ b/chrome/browser/ash/arc/bluetooth/arc_floss_bridge.cc
@@ -2,13 +2,25 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <bluetooth/bluetooth.h> +#include <bluetooth/l2cap.h> +#include <bluetooth/rfcomm.h> + +#include "ash/components/arc/bluetooth/bluetooth_type_converters.h" +#include "base/functional/callback_helpers.h" +#include "base/guid.h" #include "chrome/browser/ash/arc/bluetooth/arc_floss_bridge.h" +#include "device/bluetooth/bluetooth_socket.h" +#include "device/bluetooth/floss/floss_dbus_manager.h" +#include "device/bluetooth/floss/floss_socket_manager.h" #include "base/logging.h" #include "ash/components/arc/bluetooth/bluetooth_type_converters.h" #include "ash/components/arc/session/arc_bridge_service.h" #include "device/bluetooth/floss/bluetooth_device_floss.h" +#include "device/bluetooth/floss/floss_dbus_manager.h" +#include "device/bluetooth/floss/floss_sdp_types.h" using device::BluetoothUUID; using floss::BluetoothDeviceFloss; @@ -19,31 +31,172 @@ ArcBridgeService* bridge_service) : ArcBluetoothBridge(context, bridge_service) {} -ArcFlossBridge::~ArcFlossBridge() = default; +ArcFlossBridge::~ArcFlossBridge() { + if (GetAdapter() && GetAdapter()->IsPowered() && + floss::FlossDBusManager::Get()->GetAdapterClient()->HasObserver(this)) { + floss::FlossDBusManager::Get()->GetAdapterClient()->RemoveObserver(this); + } +} floss::BluetoothAdapterFloss* ArcFlossBridge::GetAdapter() const { return static_cast<floss::BluetoothAdapterFloss*>(bluetooth_adapter_.get()); } +void ArcFlossBridge::HandlePoweredOn() { + floss::FlossDBusManager::Get()->GetAdapterClient()->AddObserver(this); +} + +void ArcFlossBridge::OnSdpSearchResult(mojom::BluetoothAddressPtr remote_addr, + const device::BluetoothUUID& target_uuid, + floss::DBusResult<bool> result) { + if (!result.has_value()) { + OnGetServiceRecordsError( + std::move(remote_addr), target_uuid, + bluez::BluetoothServiceRecordBlueZ::ErrorCode::UNKNOWN); + return; + } + + if (!*result) { + OnGetServiceRecordsError( + std::move(remote_addr), target_uuid, + bluez::BluetoothServiceRecordBlueZ::ErrorCode::UNKNOWN); + return; + } +} + void ArcFlossBridge::GetSdpRecords(mojom::BluetoothAddressPtr remote_addr, const BluetoothUUID& target_uuid) { - NOTIMPLEMENTED(); + if (!AdapterReadyAndRegistered()) { + OnGetServiceRecordsError( + std::move(remote_addr), target_uuid, + bluez::BluetoothServiceRecordBlueZ::ErrorCode::ERROR_ADAPTER_NOT_READY); + return; + } + + const floss::FlossDeviceId remote_device = floss::FlossDeviceId( + {.address = remote_addr->To<std::string>(), .name = ""}); + floss::ResponseCallback<bool> response_callback = base::BindOnce( + &ArcFlossBridge::OnSdpSearchResult, weak_factory_.GetWeakPtr(), + std::move(remote_addr), target_uuid); + + floss::FlossDBusManager::Get()->GetAdapterClient()->SdpSearch( + std::move(response_callback), remote_device, target_uuid); +} + +void ArcFlossBridge::CreateSdpRecordComplete(device::BluetoothUUID uuid, + floss::DBusResult<bool> result) { + if (!result.has_value()) { + arc::mojom::BluetoothCreateSdpRecordResultPtr callback_result = + arc::mojom::BluetoothCreateSdpRecordResult::New(); + callback_result->status = mojom::BluetoothStatus::FAIL; + CompleteCreateSdpRecord(uuid, std::move(callback_result)); + return; + } + + if (!*result) { + arc::mojom::BluetoothCreateSdpRecordResultPtr callback_result = + arc::mojom::BluetoothCreateSdpRecordResult::New(); + callback_result->status = mojom::BluetoothStatus::FAIL; + CompleteCreateSdpRecord(uuid, std::move(callback_result)); + return; + } } void ArcFlossBridge::CreateSdpRecord(mojom::BluetoothSdpRecordPtr record_mojo, CreateSdpRecordCallback callback) { - auto result = mojom::BluetoothCreateSdpRecordResult::New(); - result->status = mojom::BluetoothStatus::FAIL; - std::move(callback).Run(std::move(result)); + if (!AdapterReadyAndRegistered()) { + arc::mojom::BluetoothCreateSdpRecordResultPtr result = + arc::mojom::BluetoothCreateSdpRecordResult::New(); + result->status = mojom::BluetoothStatus::NOT_READY; + std::move(callback).Run(std::move(result)); + return; + } + const floss::BtSdpRecord sdp_record = + mojo::TypeConverter<floss::BtSdpRecord, + bluez::BluetoothServiceRecordBlueZ>:: + Convert(mojo::TypeConverter< + bluez::BluetoothServiceRecordBlueZ, + mojom::BluetoothSdpRecordPtr>::Convert(record_mojo)); + const absl::optional<device::BluetoothUUID> uuid = + floss::GetUUIDFromSdpRecord(sdp_record); + if (!uuid.has_value()) { + arc::mojom::BluetoothCreateSdpRecordResultPtr result = + arc::mojom::BluetoothCreateSdpRecordResult::New(); + result->status = mojom::BluetoothStatus::PARM_INVALID; + std::move(callback).Run(std::move(result)); + return; + } + create_sdp_record_callbacks_.insert_or_assign(*uuid, std::move(callback)); - NOTIMPLEMENTED(); + floss::ResponseCallback<bool> response_callback = + base::BindOnce(&ArcFlossBridge::CreateSdpRecordComplete, + weak_factory_.GetWeakPtr(), *uuid); + floss::FlossDBusManager::Get()->GetAdapterClient()->CreateSdpRecord( + std::move(response_callback), sdp_record); +} + +void ArcFlossBridge::RemoveSdpRecordComplete(RemoveSdpRecordCallback callback, + floss::DBusResult<bool> result) { + if (!result.has_value()) { + std::move(callback).Run(arc::mojom::BluetoothStatus::FAIL); + return; + } + + if (!*result) { + std::move(callback).Run(arc::mojom::BluetoothStatus::FAIL); + return; + } + + std::move(callback).Run(arc::mojom::BluetoothStatus::SUCCESS); } void ArcFlossBridge::RemoveSdpRecord(uint32_t service_handle, RemoveSdpRecordCallback callback) { - std::move(callback).Run(mojom::BluetoothStatus::FAIL); + if (!AdapterReadyAndRegistered()) { + std::move(callback).Run(arc::mojom::BluetoothStatus::NOT_READY); + return; + } - NOTIMPLEMENTED(); + floss::ResponseCallback<bool> response_callback = + base::BindOnce(&ArcFlossBridge::RemoveSdpRecordComplete, + weak_factory_.GetWeakPtr(), std::move(callback)); + floss::FlossDBusManager::Get()->GetAdapterClient()->RemoveSdpRecord( + std::move(response_callback), service_handle); +} + +void ArcFlossBridge::CloseBluetoothListeningSocket( + BluetoothListeningSocket* ptr) {} + +void ArcFlossBridge::CloseBluetoothConnectingSocket( + BluetoothConnectingSocket* ptr) {} + +void ArcFlossBridge::SdpSearchComplete( + const floss::FlossDeviceId device, + const device::BluetoothUUID uuid, + const std::vector<floss::BtSdpRecord> records) { + mojom::BluetoothAddressPtr address = + mojom::BluetoothAddress::From(device.address); + std::vector<bluez::BluetoothServiceRecordBlueZ> records_bluez; + for (auto record : records) { + records_bluez.push_back( + mojo::TypeConverter<bluez::BluetoothServiceRecordBlueZ, + floss::BtSdpRecord>::Convert(record)); + } + OnGetServiceRecordsFinished(std::move(address), uuid, records_bluez); +} + +void ArcFlossBridge::SdpRecordCreated(const floss::BtSdpRecord record, + const int32_t handle) { + const absl::optional<device::BluetoothUUID> uuid = + floss::GetUUIDFromSdpRecord(record); + if (!uuid.has_value()) { + return; + } + arc::mojom::BluetoothCreateSdpRecordResultPtr callback_result = + arc::mojom::BluetoothCreateSdpRecordResult::New(); + callback_result->status = mojom::BluetoothStatus::SUCCESS; + callback_result->service_handle = handle; + CompleteCreateSdpRecord(*uuid, std::move(callback_result)); } void ArcFlossBridge::SendCachedDevices() const { @@ -70,5 +223,46 @@ GetDeviceProperties(mojom::BluetoothPropertyType::ALL, device)); } } +void ArcFlossBridge::CreateBluetoothListenSocket( + mojom::BluetoothSocketType type, + mojom::BluetoothSocketFlagsPtr flags, + int port, + ArcFlossBridge::BluetoothSocketListenCallback callback) { + NOTIMPLEMENTED(); +} + +void ArcFlossBridge::CreateBluetoothConnectSocket( + mojom::BluetoothSocketType type, + mojom::BluetoothSocketFlagsPtr flags, + mojom::BluetoothAddressPtr addr, + int port, + ArcFlossBridge::BluetoothSocketConnectCallback callback) { + NOTIMPLEMENTED(); +} + +void ArcFlossBridge::CompleteCreateSdpRecord( + device::BluetoothUUID uuid, + arc::mojom::BluetoothCreateSdpRecordResultPtr result) { + if (!base::Contains(create_sdp_record_callbacks_, uuid)) { + return; + } + + CreateSdpRecordCallback callback = + std::move(create_sdp_record_callbacks_[uuid]); + create_sdp_record_callbacks_.erase(uuid); + std::move(callback).Run(std::move(result)); +} + +bool ArcFlossBridge::AdapterReadyAndRegistered() { + if (!GetAdapter() || !GetAdapter()->IsPresent()) { + return false; + } + + if (!floss::FlossDBusManager::Get()->GetAdapterClient()->HasObserver(this)) { + floss::FlossDBusManager::Get()->GetAdapterClient()->AddObserver(this); + } + + return true; +} } // namespace arc
diff --git a/chrome/browser/ash/arc/bluetooth/arc_floss_bridge.h b/chrome/browser/ash/arc/bluetooth/arc_floss_bridge.h index be1e91d..065e692 100644 --- a/chrome/browser/ash/arc/bluetooth/arc_floss_bridge.h +++ b/chrome/browser/ash/arc/bluetooth/arc_floss_bridge.h
@@ -6,14 +6,17 @@ #include "ash/components/arc/mojom/bluetooth.mojom.h" #include "chrome/browser/ash/arc/bluetooth/arc_bluetooth_bridge.h" +#include "device/bluetooth/bluetooth_device.h" #include "device/bluetooth/floss/bluetooth_adapter_floss.h" +#include "device/bluetooth/floss/floss_adapter_client.h" namespace arc { // Floss specialization for Arc Bluetooth bridge. Use this class whenever the // common |device::BluetoothAdapter| or |device::BluetoothDevice| class apis are // insufficient. -class ArcFlossBridge : public ArcBluetoothBridge { +class ArcFlossBridge : public ArcBluetoothBridge, + public floss::FlossAdapterClient::Observer { public: ArcFlossBridge(content::BrowserContext* context, ArcBridgeService* bridge_service); @@ -33,8 +36,61 @@ void RemoveSdpRecord(uint32_t service_handle, RemoveSdpRecordCallback callback) override; + // Closes Bluetooth sockets. Releases the corresponding resources. + void CloseBluetoothListeningSocket(BluetoothListeningSocket* socket); + void CloseBluetoothConnectingSocket(BluetoothConnectingSocket* socket); + + // floss::FlossAdapterClient::Observer overrides + void SdpSearchComplete( + const floss::FlossDeviceId device, + const device::BluetoothUUID uuid, + const std::vector<floss::BtSdpRecord> records) override; + + void SdpRecordCreated(const floss::BtSdpRecord record, + const int32_t handle) override; + protected: floss::BluetoothAdapterFloss* GetAdapter() const; + + void HandlePoweredOn() override; + + void OnSdpSearchResult(mojom::BluetoothAddressPtr remote_addr, + const device::BluetoothUUID& target_uuid, + floss::DBusResult<bool> result); + + void RemoveSdpRecordComplete(RemoveSdpRecordCallback callback, + floss::DBusResult<bool> result); + + void CreateSdpRecordComplete(device::BluetoothUUID uuid, + floss::DBusResult<bool> result); + + void CompleteCreateSdpRecord( + device::BluetoothUUID uuid, + arc::mojom::BluetoothCreateSdpRecordResultPtr result); + + private: + bool AdapterReadyAndRegistered(); + + // Map of SDP record UUIDs to CreateSdpRecordCallback for SdpRecordCreated to + // use to resolve CreateSdpRecord calls. + base::flat_map<device::BluetoothUUID, CreateSdpRecordCallback> + create_sdp_record_callbacks_{}; + + void CreateBluetoothListenSocket( + mojom::BluetoothSocketType type, + mojom::BluetoothSocketFlagsPtr flags, + int port, + BluetoothSocketListenCallback callback) override; + + void CreateBluetoothConnectSocket( + mojom::BluetoothSocketType type, + mojom::BluetoothSocketFlagsPtr flags, + mojom::BluetoothAddressPtr addr, + int port, + BluetoothSocketConnectCallback callback) override; + + // WeakPtrFactory to use for callbacks. + base::WeakPtrFactory<ArcFlossBridge> weak_factory_{this}; }; } // namespace arc
diff --git a/chrome/browser/ash/crosapi/crosapi_util.cc b/chrome/browser/ash/crosapi/crosapi_util.cc index af4adbf..b832c19 100644 --- a/chrome/browser/ash/crosapi/crosapi_util.cc +++ b/chrome/browser/ash/crosapi/crosapi_util.cc
@@ -154,6 +154,7 @@ #include "services/device/public/mojom/hid.mojom.h" #include "services/media_session/public/mojom/audio_focus.mojom.h" #include "services/media_session/public/mojom/media_controller.mojom.h" +#include "ui/gfx/switches.h" using MojoOptionalBool = crosapi::mojom::DeviceSettings::OptionalBool; @@ -603,6 +604,10 @@ params->standalone_browser_app_service_blocklist = extensions::BuildStandaloneBrowserAppServiceBlockListInitParam(); + + params->enable_cpu_mappable_native_gpu_memory_buffers = + base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableNativeGpuMemoryBuffers); } template <typename BrowserParams>
diff --git a/chrome/browser/ash/login/oobe_quick_start/connectivity/authenticated_connection.cc b/chrome/browser/ash/login/oobe_quick_start/connectivity/authenticated_connection.cc index 9960f0f..4ab2f9e8 100644 --- a/chrome/browser/ash/login/oobe_quick_start/connectivity/authenticated_connection.cc +++ b/chrome/browser/ash/login/oobe_quick_start/connectivity/authenticated_connection.cc
@@ -8,11 +8,13 @@ #include "base/functional/callback_helpers.h" #include "chrome/browser/ash/login/oobe_quick_start/connectivity/fido_assertion_info.h" #include "chrome/browser/ash/login/oobe_quick_start/connectivity/random_session_id.h" +#include "chrome/browser/ash/login/oobe_quick_start/connectivity/wifi_credentials.h" #include "chrome/browser/ash/login/oobe_quick_start/logging/logging.h" #include "chrome/browser/nearby_sharing/public/cpp/nearby_connection.h" #include "chromeos/ash/components/quick_start/quick_start_message.h" #include "chromeos/ash/components/quick_start/quick_start_requests.h" #include "chromeos/ash/services/nearby/public/mojom/quick_start_decoder.mojom.h" +#include "chromeos/ash/services/nearby/public/mojom/quick_start_decoder_types.mojom-shared.h" #include "chromeos/ash/services/nearby/public/mojom/quick_start_decoder_types.mojom.h" namespace ash::quick_start { @@ -74,15 +76,41 @@ SendMessage( requests::BuildRequestWifiCredentialsMessage(session_id, shared_secret_str), - base::BindOnce(&AuthenticatedConnection::OnWifiCredentialsResponse, + base::BindOnce(&AuthenticatedConnection::OnRequestWifiCredentialsResponse, weak_ptr_factory_.GetWeakPtr(), std::move(callback))); } -void AuthenticatedConnection::OnWifiCredentialsResponse( +void AuthenticatedConnection::OnRequestWifiCredentialsResponse( RequestWifiCredentialsCallback callback, absl::optional<std::vector<uint8_t>> response_bytes) { - // TODO (b/234655072): Implement response parsing. - NOTIMPLEMENTED(); + if (!response_bytes.has_value()) { + QS_LOG(ERROR) << "No response bytes received for wifi credentials request"; + std::move(callback).Run(absl::nullopt); + return; + } + + auto parse_mojo_response_callback = + base::BindOnce(&AuthenticatedConnection::ParseWifiCredentialsResponse, + weak_ptr_factory_.GetWeakPtr(), std::move(callback)); + + decoder_->DecodeWifiCredentialsResponse( + response_bytes.value(), std::move(parse_mojo_response_callback)); +} + +void AuthenticatedConnection::ParseWifiCredentialsResponse( + RequestWifiCredentialsCallback callback, + ::ash::quick_start::mojom::GetWifiCredentialsResponsePtr response) { + if (!response->is_credentials()) { + std::move(callback).Run(absl::nullopt); + return; + } + + WifiCredentials credentials; + credentials.ssid = response->get_credentials()->ssid; + credentials.password = response->get_credentials()->password; + credentials.is_hidden = response->get_credentials()->is_hidden; + credentials.security_type = response->get_credentials()->security_type; + std::move(callback).Run(std::move(credentials)); } void AuthenticatedConnection::OnRequestAccountTransferAssertionResponse(
diff --git a/chrome/browser/ash/login/oobe_quick_start/connectivity/authenticated_connection.h b/chrome/browser/ash/login/oobe_quick_start/connectivity/authenticated_connection.h index 2d9aaa5..dd40b1d 100644 --- a/chrome/browser/ash/login/oobe_quick_start/connectivity/authenticated_connection.h +++ b/chrome/browser/ash/login/oobe_quick_start/connectivity/authenticated_connection.h
@@ -52,8 +52,8 @@ base::OnceCallback<void(absl::optional<std::vector<uint8_t>>)>; // Parses a raw response and converts it to a WifiCredentialsResponse - void OnWifiCredentialsResponse( - RequestWifiCredentialsCallback, + void OnRequestWifiCredentialsResponse( + RequestWifiCredentialsCallback callback, absl::optional<std::vector<uint8_t>> response_bytes); // Parses a raw AssertionResponse and converts it into a FidoAssertionInfo @@ -61,6 +61,10 @@ RequestAccountTransferAssertionCallback callback, absl::optional<std::vector<uint8_t>> response_bytes); + void ParseWifiCredentialsResponse( + RequestWifiCredentialsCallback callback, + ::ash::quick_start::mojom::GetWifiCredentialsResponsePtr response); + void GenerateFidoAssertionInfo( RequestAccountTransferAssertionCallback callback, ::ash::quick_start::mojom::GetAssertionResponsePtr response);
diff --git a/chrome/browser/ash/login/oobe_quick_start/connectivity/authenticated_connection_unittest.cc b/chrome/browser/ash/login/oobe_quick_start/connectivity/authenticated_connection_unittest.cc index 2584266..6e39a26 100644 --- a/chrome/browser/ash/login/oobe_quick_start/connectivity/authenticated_connection_unittest.cc +++ b/chrome/browser/ash/login/oobe_quick_start/connectivity/authenticated_connection_unittest.cc
@@ -9,6 +9,7 @@ #include "base/json/json_reader.h" #include "base/run_loop.h" #include "base/test/task_environment.h" +#include "base/test/test_future.h" #include "base/values.h" #include "chrome/browser/ash/login/oobe_quick_start/connectivity/fake_quick_start_decoder.h" #include "chrome/browser/ash/login/oobe_quick_start/connectivity/fido_assertion_info.h" @@ -18,6 +19,8 @@ #include "chrome/browser/nearby_sharing/public/cpp/nearby_connection.h" #include "chromeos/ash/components/quick_start/quick_start_message.h" #include "chromeos/ash/components/quick_start/quick_start_requests.h" +#include "chromeos/ash/services/nearby/public/mojom/quick_start_decoder.mojom.h" +#include "chromeos/ash/services/nearby/public/mojom/quick_start_decoder_types.mojom-shared.h" #include "chromeos/ash/services/nearby/public/mojom/quick_start_decoder_types.mojom.h" #include "components/cbor/reader.h" #include "components/cbor/values.h" @@ -85,10 +88,6 @@ assertion_info_ = assertion_info; } - void VerifyWifiCredentials(absl::optional<WifiCredentials> credentials) { - // TODO: Verify Wifi Credentials once parsed - } - protected: RandomSessionId session_id_ = RandomSessionId(kRandomSessionId); base::test::SingleThreadTaskEnvironment task_environment_; @@ -103,10 +102,15 @@ // Random Session ID for testing int32_t session_id = 1; - authenticated_connection_->RequestWifiCredentials( - session_id, - base::BindOnce(&AuthenticatedConnectionTest::VerifyWifiCredentials, - base::Unretained(this))); + fake_quick_start_decoder_->SetWifiCredentialsResponse( + mojom::GetWifiCredentialsResponse::NewCredentials( + mojom::WifiCredentials::New("ssid", mojom::WifiSecurityType::kPSK, + true, "password"))); + + base::test::TestFuture<absl::optional<WifiCredentials>> future; + + authenticated_connection_->RequestWifiCredentials(session_id, + future.GetCallback()); fake_nearby_connection_->AppendReadableData({0x00, 0x01, 0x02}); std::vector<uint8_t> wifi_request = fake_nearby_connection_->GetWrittenData(); @@ -142,6 +146,33 @@ // TODO(b/234655072): Create kSecondarySharedSecret const and check value // equals after AuthenticatedConnection refactor is merged. EXPECT_TRUE(wifi_request_payload.FindString("shared_secret")); + + const absl::optional<WifiCredentials>& credentials = future.Get(); + EXPECT_TRUE(credentials.has_value()); + EXPECT_EQ(credentials->ssid, "ssid"); + EXPECT_EQ(credentials->password, "password"); + EXPECT_EQ(credentials->security_type, + ash::quick_start::mojom::WifiSecurityType::kPSK); + EXPECT_TRUE(credentials->is_hidden); +} + +TEST_F(AuthenticatedConnectionTest, + RequestWifiCredentialsReturnsEmptyOnFailure) { + // Random Session ID for testing + int32_t session_id = 1; + fake_quick_start_decoder_->SetWifiCredentialsResponse( + mojom::GetWifiCredentialsResponse::NewFailureReason( + mojom::GetWifiCredentialsFailureReason::kMissingWifiHiddenStatus)); + + base::test::TestFuture<absl::optional<WifiCredentials>> future; + + authenticated_connection_->RequestWifiCredentials(session_id, + future.GetCallback()); + + fake_nearby_connection_->AppendReadableData({0x00, 0x01, 0x02}); + + absl::optional<WifiCredentials> credentials = future.Get(); + EXPECT_FALSE(future.Get().has_value()); } TEST_F(AuthenticatedConnectionTest, RequestAccountTransferAssertion) {
diff --git a/chrome/browser/ash/login/oobe_quick_start/connectivity/fake_quick_start_decoder.cc b/chrome/browser/ash/login/oobe_quick_start/connectivity/fake_quick_start_decoder.cc index e0380e7..075dab69 100644 --- a/chrome/browser/ash/login/oobe_quick_start/connectivity/fake_quick_start_decoder.cc +++ b/chrome/browser/ash/login/oobe_quick_start/connectivity/fake_quick_start_decoder.cc
@@ -4,6 +4,8 @@ #include "fake_quick_start_decoder.h" +#include "chromeos/ash/services/nearby/public/mojom/quick_start_decoder_types.mojom-forward.h" + namespace ash::quick_start { FakeQuickStartDecoder::~FakeQuickStartDecoder() = default; @@ -22,6 +24,12 @@ EXPECT_EQ(expected_data_, data); } +void FakeQuickStartDecoder::DecodeWifiCredentialsResponse( + const std::vector<uint8_t>& data, + DecodeWifiCredentialsResponseCallback callback) { + std::move(callback).Run(std::move(wifi_credentials_response_)); +} + void FakeQuickStartDecoder::DecodeGetAssertionResponse( const std::vector<uint8_t>& data, DecodeGetAssertionResponseCallback callback) { @@ -54,4 +62,9 @@ response_data_ = data; } +void FakeQuickStartDecoder::SetWifiCredentialsResponse( + mojom::GetWifiCredentialsResponsePtr response) { + wifi_credentials_response_ = std::move(response); +} + } // namespace ash::quick_start
diff --git a/chrome/browser/ash/login/oobe_quick_start/connectivity/fake_quick_start_decoder.h b/chrome/browser/ash/login/oobe_quick_start/connectivity/fake_quick_start_decoder.h index eac849a..8b4321d 100644 --- a/chrome/browser/ash/login/oobe_quick_start/connectivity/fake_quick_start_decoder.h +++ b/chrome/browser/ash/login/oobe_quick_start/connectivity/fake_quick_start_decoder.h
@@ -28,6 +28,9 @@ void DecodeGetAssertionResponse( const std::vector<uint8_t>& data, DecodeGetAssertionResponseCallback callback) override; + void DecodeWifiCredentialsResponse( + const std::vector<uint8_t>& data, + DecodeWifiCredentialsResponseCallback callback) override; void SetExpectedData(std::vector<uint8_t> expected_data); void SetAssertionResponse( @@ -39,6 +42,9 @@ const std::vector<uint8_t>& signature, const std::vector<uint8_t>& data); + void SetWifiCredentialsResponse( + mojom::GetWifiCredentialsResponsePtr response); + private: std::vector<uint8_t> expected_data_; mojom::GetAssertionResponse::GetAssertionStatus response_status_; @@ -49,6 +55,7 @@ std::vector<uint8_t> response_signature_; std::vector<uint8_t> response_data_; mojo::ReceiverSet<ash::quick_start::mojom::QuickStartDecoder> receiver_set_; + mojom::GetWifiCredentialsResponsePtr wifi_credentials_response_; }; } // namespace ash::quick_start
diff --git a/chrome/browser/ash/login/oobe_quick_start/connectivity/wifi_credentials.cc b/chrome/browser/ash/login/oobe_quick_start/connectivity/wifi_credentials.cc index a6ed628f..8c10e39 100644 --- a/chrome/browser/ash/login/oobe_quick_start/connectivity/wifi_credentials.cc +++ b/chrome/browser/ash/login/oobe_quick_start/connectivity/wifi_credentials.cc
@@ -3,6 +3,9 @@ // found in the LICENSE file. #include "wifi_credentials.h" +#include "base/notreached.h" + +#include "chromeos/ash/services/nearby/public/mojom/quick_start_decoder_types.mojom-shared.h" namespace ash::quick_start {
diff --git a/chrome/browser/ash/login/oobe_quick_start/connectivity/wifi_credentials.h b/chrome/browser/ash/login/oobe_quick_start/connectivity/wifi_credentials.h index 0767a203..f683af2 100644 --- a/chrome/browser/ash/login/oobe_quick_start/connectivity/wifi_credentials.h +++ b/chrome/browser/ash/login/oobe_quick_start/connectivity/wifi_credentials.h
@@ -7,6 +7,9 @@ #include <string> +#include "chromeos/ash/services/nearby/public/mojom/quick_start_decoder_types.mojom-shared.h" +#include "chromeos/ash/services/nearby/public/mojom/quick_start_decoder_types.mojom.h" + namespace ash::quick_start { // A `struct` to store the information related to a device's Wifi Credentials. @@ -29,7 +32,7 @@ bool is_hidden; // The Security Type of the Wifi Network. - std::string security_type; + ash::quick_start::mojom::WifiSecurityType security_type; }; } // namespace ash::quick_start
diff --git a/chrome/browser/ash/policy/networking/network_policy_application_browsertest.cc b/chrome/browser/ash/policy/networking/network_policy_application_browsertest.cc index 3eb91f2..aa7bc3d 100644 --- a/chrome/browser/ash/policy/networking/network_policy_application_browsertest.cc +++ b/chrome/browser/ash/policy/networking/network_policy_application_browsertest.cc
@@ -1125,6 +1125,77 @@ } } +// Tests behavior of BlockedHexSSIDs on login screen and in a user session. +// Also tests that if a blocked SSID was connected on the sign-in screen, it is +// disconnected when a user signs in. +IN_PROC_BROWSER_TEST_F(NetworkPolicyApplicationTest, BlockedHexSSIDs) { + constexpr char kGuidWifi1[] = "wifi_orig_guid_1"; + constexpr char kGuidWifi2[] = "wifi_orig_guid_2"; + + CrosNetworkConfigGuidsAvailableWaiter available_waiter( + cros_network_config_.get(), {kGuidWifi1, kGuidWifi2}); + AddPskWifiService(kServiceWifi1, kGuidWifi1, "WifiOne", shill::kStateIdle); + AddPskWifiService(kServiceWifi2, kGuidWifi2, "WifiTwo", shill::kStateIdle); + available_waiter.Wait(); + + // Check that initially no policies applied and CrosNetworkStateProperties + // has no prohibited networks. + { + EXPECT_THAT(CrosNetworkConfigGetGlobalPolicy()->blocked_hex_ssids, + IsEmpty()); + + EXPECT_FALSE(IsProhibitedByPolicyInCrosNetworkConfig(kGuidWifi1)); + EXPECT_FALSE(IsProhibitedByPolicyInCrosNetworkConfig(kGuidWifi2)); + } + + // Apply device ONC policy. + // 576966694F6E65 is hex-encoded ASCII "WifiOne" + { + const char kDeviceONC[] = R"( + { + "GlobalNetworkConfiguration": { + "BlockedHexSSIDs": [ "576966694F6E65" ] + }, + "NetworkConfigurations": [ ] + })"; + SetDeviceOpenNetworkConfiguration(kDeviceONC, /*wait_applied=*/true); + + EXPECT_THAT(CrosNetworkConfigGetGlobalPolicy()->blocked_hex_ssids, + ElementsAre("576966694F6E65")); + } + + // The network is still connectable because BlockedHexSSIDs is not applied on + // the sign-in screen. + EXPECT_FALSE(IsProhibitedByPolicyInCrosNetworkConfig(kGuidWifi1)); + EXPECT_FALSE(IsProhibitedByPolicyInCrosNetworkConfig(kGuidWifi2)); + + ConnectToService(kServiceWifi1); + EXPECT_EQ(GetWifiStateFromShillClient(kGuidWifi1), shill::kStateOnline); + EXPECT_EQ(GetWifiStateFromShillClient(kGuidWifi2), shill::kStateIdle); + + // Sign-in a user and apply user without ONC policy. + // The blocked network should be automatically disconnected. + { + ServiceStateWaiter wifi_disconnected_waiter(shill_service_client_test_, + kServiceWifi1); + + LoginUser(test_account_id_); + const std::string user_hash = GetTestUserHash(); + shill_profile_client_test_->AddProfile(kUserProfilePath, user_hash); + + wifi_disconnected_waiter.Wait(shill::kStateIdle); + } + + EXPECT_TRUE(IsProhibitedByPolicyInCrosNetworkConfig(kGuidWifi1)); + EXPECT_FALSE(IsProhibitedByPolicyInCrosNetworkConfig(kGuidWifi2)); + + EXPECT_EQ(GetWifiStateFromShillClient(kGuidWifi1), shill::kStateIdle); + EXPECT_EQ(GetWifiStateFromShillClient(kGuidWifi2), shill::kStateIdle); + + // TODO(b/277809215): Attempt to connect to the prohibited service using + // CrosNetworkConfig. +} + // Behavior of AllowOnlyPolicyNetworksToConnectIfAvailable when no policy // networks are configured. IN_PROC_BROWSER_TEST_F(NetworkPolicyApplicationTest, @@ -1300,16 +1371,17 @@ wifi_connected_waiter.Wait(shill::kStateOnline); } - // Expects that the non-policy WiFi services are now prohibited. + // Expects that the non-policy WiFi services are now prohibited and that the + // policy-provided network has connected. EXPECT_TRUE(IsProhibitedByPolicyInCrosNetworkConfig(kGuidWifi1)); EXPECT_TRUE(IsProhibitedByPolicyInCrosNetworkConfig(kGuidWifi2)); EXPECT_FALSE(IsProhibitedByPolicyInCrosNetworkConfig("wifi_policy_1")); EXPECT_FALSE(IsProhibitedByPolicyInCrosNetworkConfig("wifi_policy_2")); - // Note that we're intentionally not verifying the service state because fake - // shill does not reset the service state to idle when a disconnect would - // happen in real life due to connecting to another service. - // TODO(b/276358423): Change the default connect behavior to do that. + EXPECT_EQ(GetWifiStateFromShillClient(kGuidWifi1), shill::kStateIdle); + EXPECT_EQ(GetWifiStateFromShillClient(kGuidWifi2), shill::kStateIdle); + EXPECT_EQ(GetWifiStateFromShillClient("wifi_policy_1"), shill::kStateIdle); + EXPECT_EQ(GetWifiStateFromShillClient("wifi_policy_2"), shill::kStateOnline); // Now the policy-provided network becomes invisible again, and no network is // prohibited anymore.
diff --git a/chrome/browser/ash/policy/reporting/metrics_reporting/apps/app_usage_telemetry_sampler_browsertest.cc b/chrome/browser/ash/policy/reporting/metrics_reporting/apps/app_usage_telemetry_sampler_browsertest.cc new file mode 100644 index 0000000..37343e6 --- /dev/null +++ b/chrome/browser/ash/policy/reporting/metrics_reporting/apps/app_usage_telemetry_sampler_browsertest.cc
@@ -0,0 +1,481 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <memory> +#include <string> +#include <tuple> + +#include "base/check.h" +#include "base/functional/bind.h" +#include "base/no_destructor.h" +#include "base/notreached.h" +#include "base/strings/string_piece_forward.h" +#include "base/synchronization/lock.h" +#include "base/test/scoped_feature_list.h" +#include "base/thread_annotations.h" +#include "base/time/time.h" +#include "base/time/time_override.h" +#include "chrome/browser/apps/app_service/metrics/app_platform_metrics.h" +#include "chrome/browser/apps/app_service/metrics/app_platform_metrics_utils.h" +#include "chrome/browser/ash/login/test/cryptohome_mixin.h" +#include "chrome/browser/ash/policy/affiliation/affiliation_mixin.h" +#include "chrome/browser/ash/policy/affiliation/affiliation_test_helper.h" +#include "chrome/browser/ash/policy/core/device_policy_cros_browser_test.h" +#include "chrome/browser/ash/policy/reporting/metrics_reporting/metric_reporting_manager.h" +#include "chrome/browser/ash/profiles/profile_helper.h" +#include "chrome/browser/ash/settings/scoped_testing_cros_settings.h" +#include "chrome/browser/ash/settings/stub_cros_settings_provider.h" +#include "chrome/browser/chromeos/reporting/metric_default_utils.h" +#include "chrome/browser/policy/dm_token_utils.h" +#include "chrome/browser/sync/sync_service_factory.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/browser_window.h" +#include "chrome/browser/ui/web_applications/test/web_app_browsertest_util.h" +#include "chrome/browser/web_applications/mojom/user_display_mode.mojom-shared.h" +#include "chrome/browser/web_applications/test/web_app_install_test_utils.h" +#include "chrome/browser/web_applications/user_display_mode.h" +#include "chrome/browser/web_applications/web_app_id.h" +#include "chrome/test/base/in_process_browser_test.h" +#include "chromeos/ash/components/settings/cros_settings_names.h" +#include "chromeos/dbus/missive/missive_client_test_observer.h" +#include "components/app_constants/constants.h" +#include "components/keyed_service/content/browser_context_dependency_manager.h" +#include "components/keyed_service/core/keyed_service.h" +#include "components/reporting/proto/synced/metric_data.pb.h" +#include "components/reporting/proto/synced/record.pb.h" +#include "components/reporting/proto/synced/record_constants.pb.h" +#include "components/services/app_service/public/protos/app_types.pb.h" +#include "components/sync/test/test_sync_service.h" +#include "components/ukm/test_ukm_recorder.h" +#include "content/public/browser/browser_context.h" +#include "content/public/test/browser_test.h" +#include "content/public/test/test_launcher.h" +#include "content/public/test/test_utils.h" +#include "services/metrics/public/cpp/ukm_source.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/public/mojom/manifest/display_mode.mojom-shared.h" +#include "url/gurl.h" + +using ::testing::AllOf; +using ::testing::Eq; +using ::testing::Ge; +using ::testing::Le; +using ::testing::StrEq; +using ::testing::UnorderedPointwise; + +namespace reporting { +namespace { + +// Test DM token used to associate reported events. +constexpr char kDMToken[] = "token"; + +// Standalone webapp start URL. +constexpr char kWebAppUrl[] = "https://test.example.com"; + +// App usage UKM entry name. +constexpr char kAppUsageUKMEntryName[] = "ChromeOSApp.UsageTime"; + +// App usage collection interval. +constexpr base::TimeDelta kAppUsageCollectionInterval = base::Minutes(5); + +// UKM app usage reporting interval. +constexpr base::TimeDelta kAppUsageUKMReportingInterval = base::Hours(2); + +// Additional webapp usage buffer period before the browser is actually closed. +// Used when validating reported app usage data. +constexpr base::TimeDelta kWebAppUsageBufferPeriod = base::Seconds(5); + +MATCHER(ContainsAppId, + "Matches app id in app usage proto with the expected one") { + return std::get<0>(arg).app_id() == std::get<1>(arg); +} + +// Mock clock that supplies a mock time and can be advanced for testing +// purposes. Needed to simulate usage, and trigger telemetry collection and +// reporting. Only applicable for browser tests where a `TaskEnvironment` is +// unavailable. +class MockClock { + public: + // Returns a MockClock which will not be deleted. Should be called once while + // single-threaded to initialize ScopedTimeClockOverrides to avoid threading + // issues. + static MockClock& Get() { + static base::NoDestructor<MockClock> mock_clock; + return *mock_clock; + } + + MockClock(const MockClock&) = delete; + MockClock& operator=(const MockClock&) = delete; + ~MockClock() = default; + + // Advance clock by the specified duration. + void Advance(const base::TimeDelta& duration) { + base::AutoLock lock(lock_); + offset_ += duration; + } + + private: + friend base::NoDestructor<MockClock>; + + static base::Time MockedNow() { + return base::subtle::TimeNowIgnoringOverride() + Get().Offset(); + } + + static base::TimeTicks MockedTicksNow() { + return base::subtle::TimeTicksNowIgnoringOverride() + Get().Offset(); + } + + MockClock() + : time_override_(std::make_unique<base::subtle::ScopedTimeClockOverrides>( + &MockClock::MockedNow, + &MockClock::MockedTicksNow, + nullptr)) {} + + // Returns the offset duration. + const base::TimeDelta& Offset() { + base::AutoLock lock(lock_); + return offset_; + } + + const std::unique_ptr<base::subtle::ScopedTimeClockOverrides> time_override_; + + // A lock is necessary because `MockedNow` and `MockedTicksNow` can be + // accessed by components from different threads when they retrieve the + // current time. + base::Lock lock_; + base::TimeDelta offset_ GUARDED_BY(lock_); +}; + +// Assert app usage telemetry data in a record with relevant DM token and +// returns the underlying `MetricData` object. +const MetricData AssertAppUsageTelemetryData(Priority priority, + const Record& record) { + EXPECT_THAT(priority, Eq(Priority::MANUAL_BATCH)); + EXPECT_THAT(record.destination(), Eq(Destination::TELEMETRY_METRIC)); + + MetricData record_data; + EXPECT_TRUE(record_data.ParseFromString(record.data())); + EXPECT_TRUE(record_data.has_timestamp_ms()); + EXPECT_TRUE(record.has_dm_token()); + EXPECT_THAT(record.dm_token(), StrEq(kDMToken)); + return record_data; +} + +// Returns true if the record includes app usage telemetry. False otherwise. +bool IsAppUsageTelemetry(const Record& record) { + MetricData record_data; + return record_data.ParseFromString(record.data()) && + record_data.has_telemetry_data() && + record_data.telemetry_data().has_app_telemetry() && + record_data.telemetry_data().app_telemetry().has_app_usage_data(); +} + +// Browser test that validates app usage telemetry reported by the +// `AppUsageTelemetrySampler`. Inheriting from `DevicePolicyCrosBrowserTest` +// enables use of `AffiliationMixin` for setting up profile/device affiliation. +// Only available in Ash. +class AppUsageTelemetrySamplerBrowserTest + : public ::policy::DevicePolicyCrosBrowserTest { + protected: + AppUsageTelemetrySamplerBrowserTest() { + // Initialize the MockClock. + MockClock::Get(); + crypto_home_mixin_.MarkUserAsExisting(affiliation_mixin_.account_id()); + scoped_feature_list_.InitAndEnableFeature(kEnableAppMetricsReporting); + ::policy::SetDMTokenForTesting( + ::policy::DMToken::CreateValidTokenForTesting(kDMToken)); + } + + void SetUpCommandLine(base::CommandLine* command_line) override { + ::policy::AffiliationTestHelper::AppendCommandLineSwitchesForLoginManager( + command_line); + ::policy::DevicePolicyCrosBrowserTest::SetUpCommandLine(command_line); + } + + void SetUpOnMainThread() override { + ::policy::DevicePolicyCrosBrowserTest::SetUpOnMainThread(); + SetPolicyEnabled(true); + if (::content::IsPreTest()) { + // Preliminary setup - set up affiliated user. + ::policy::AffiliationTestHelper::PreLoginUser( + affiliation_mixin_.account_id()); + return; + } + + // Login as affiliated user otherwise and set up test environment. + ::policy::AffiliationTestHelper::LoginUser(affiliation_mixin_.account_id()); + ::web_app::test::UninstallAllWebApps(profile()); + test_ukm_recorder_ = std::make_unique<::ukm::TestAutoSetUkmRecorder>(); + } + + void SetUpInProcessBrowserTestFixture() override { + ::policy::DevicePolicyCrosBrowserTest::SetUpInProcessBrowserTestFixture(); + create_sync_service_subscription_ = + BrowserContextDependencyManager::GetInstance() + ->RegisterCreateServicesCallbackForTesting(base::BindRepeating( + &AppUsageTelemetrySamplerBrowserTest::SetUpSyncService, + base::Unretained(this))); + } + + void SetUpSyncService(::content::BrowserContext* context) { + SyncServiceFactory::GetInstance()->SetTestingFactoryAndUse( + context, base::BindRepeating([](::content::BrowserContext* context) + -> std::unique_ptr<KeyedService> { + return std::make_unique<::syncer::TestSyncService>(); + })); + } + + // Helper that installs a standalone webapp with the specified start url. + ::web_app::AppId InstallStandaloneWebApp(const GURL& start_url) { + auto web_app_info = std::make_unique<WebAppInstallInfo>(); + web_app_info->start_url = start_url; + web_app_info->scope = start_url.GetWithoutFilename(); + web_app_info->display_mode = ::blink::mojom::DisplayMode::kStandalone; + web_app_info->user_display_mode = + ::web_app::mojom::UserDisplayMode::kStandalone; + return ::web_app::test::InstallWebApp(profile(), std::move(web_app_info)); + } + + // Helper that simulates app usage for the specified app and usage duration. + void SimulateAppUsage(const ::web_app::AppId& app_id, + const base::TimeDelta& running_time) { + // Launch web app and simulate web app usage before closing the browser + // window to prevent further usage tracking. + Browser* const app_browser = + ::web_app::LaunchWebAppBrowser(profile(), app_id); + MockClock::Get().Advance(running_time); + ::web_app::CloseAndWait(app_browser); + + // Trigger usage telemetry collection by advancing the clock. Wait before + // returning to ensure usage data gets persisted in the user pref store. + MockClock::Get().Advance(kAppUsageCollectionInterval); + ::content::RunAllTasksUntilIdle(); + } + + void VerifyAppUsage(const AppUsageData::AppUsage& app_usage, + const ::web_app::AppId& app_id, + const base::TimeDelta& running_time) { + EXPECT_TRUE(app_usage.has_app_instance_id()); + EXPECT_THAT(app_usage.app_type(), + Eq(::apps::ApplicationType::APPLICATION_TYPE_WEB)); + + // There is some minor usage (usually in milliseconds) as we attempt to + // close the browser and before it is actually closed, so we account for + // that below as we validate reported usage. + const auto& max_expected_usage = running_time + kWebAppUsageBufferPeriod; + EXPECT_THAT(app_usage.running_time_ms(), + AllOf(Ge(running_time.InMilliseconds()), + Le(max_expected_usage.InMilliseconds()))); + + // Also verify app usage data is reset if not yet cleared from the pref + // store because this data was reported. + const auto& app_usage_dict = + profile()->GetPrefs()->GetDict(::apps::kAppUsageTime); + if (app_usage_dict.contains(app_usage.app_instance_id())) { + EXPECT_THAT( + *app_usage_dict.FindDictByDottedPath(app_usage.app_instance_id()) + ->FindString(::apps::kReportingUsageTimeDurationKey), + StrEq("0")); + } + } + + const AppUsageData::AppUsage& GetAppUsageInfoForApp( + const AppUsageData& app_usage_data, + const ::web_app::AppId& app_id) { + for (const auto& app_usage : app_usage_data.app_usage()) { + if (app_usage.app_id() == app_id) { + return app_usage; + } + } + NOTREACHED_NORETURN() << "App usage info missing for app with id: " + << app_id; + } + + void VerifyWebAppUsageUKM(base::StringPiece instance_id, + const base::TimeDelta& running_time) { + const auto entries = + test_ukm_recorder_->GetEntriesByName(kAppUsageUKMEntryName); + int usage_time = 0; + for (const auto* entry : entries) { + const ::ukm::UkmSource* source = + test_ukm_recorder_->GetSourceForSourceId(entry->source_id); + if (!source || source->url() != GURL(kWebAppUrl)) { + continue; + } + usage_time += *(test_ukm_recorder_->GetEntryMetric(entry, "Duration")); + test_ukm_recorder_->ExpectEntryMetric(entry, "UserDeviceMatrix", 0); + test_ukm_recorder_->ExpectEntryMetric(entry, "AppType", + (int)::apps::AppTypeName::kWeb); + } + + // There is some minor usage (usually in milliseconds) as we attempt to + // close the browser and before it is actually closed, so we account for + // that below as we validate app usage reported to UKM. + const auto& max_expected_usage = running_time + kWebAppUsageBufferPeriod; + EXPECT_THAT(usage_time, AllOf(Ge(running_time.InMilliseconds()), + Le(max_expected_usage.InMilliseconds()))); + + // Also verify app usage data is reset if not yet cleared from the pref + // store because this data was already reported to UKM. + const auto& app_usage_dict = + profile()->GetPrefs()->GetDict(::apps::kAppUsageTime); + if (app_usage_dict.contains(instance_id)) { + EXPECT_THAT(*app_usage_dict.FindDictByDottedPath(instance_id) + ->FindString(::apps::kUsageTimeDurationKey), + StrEq("0")); + } + } + + void SetPolicyEnabled(bool is_enabled) { + scoped_testing_cros_settings_.device_settings()->SetBoolean( + ::ash::kReportDeviceAppInfo, is_enabled); + } + + Profile* profile() const { + return ::ash::ProfileHelper::Get()->GetProfileByAccountId( + affiliation_mixin_.account_id()); + } + + ::syncer::TestSyncService* sync_service() const { + return static_cast<::syncer::TestSyncService*>( + SyncServiceFactory::GetForProfile(profile())); + } + + ::policy::DevicePolicyCrosTestHelper test_helper_; + ::policy::AffiliationMixin affiliation_mixin_{&mixin_host_, &test_helper_}; + ::ash::CryptohomeMixin crypto_home_mixin_{&mixin_host_}; + + base::test::ScopedFeatureList scoped_feature_list_; + ::ash::ScopedTestingCrosSettings scoped_testing_cros_settings_; + + base::CallbackListSubscription create_sync_service_subscription_; + std::unique_ptr<::ukm::TestAutoSetUkmRecorder> test_ukm_recorder_; +}; + +IN_PROC_BROWSER_TEST_F(AppUsageTelemetrySamplerBrowserTest, + PRE_ReportUsageData) { + // Dummy case that sets up the affiliated user through SetUpOnMainThread + // PRE-condition. +} + +IN_PROC_BROWSER_TEST_F(AppUsageTelemetrySamplerBrowserTest, ReportUsageData) { + ASSERT_TRUE(base::FeatureList::IsEnabled(kEnableAppMetricsReporting)); + + // Install webapp and simulate its usage. + const auto& app_id = InstallStandaloneWebApp(GURL(kWebAppUrl)); + static constexpr base::TimeDelta kAppUsageDuration = base::Minutes(2); + ::chromeos::MissiveClientTestObserver missive_observer( + base::BindRepeating(&IsAppUsageTelemetry)); + SimulateAppUsage(app_id, kAppUsageDuration); + + // Force telemetry collection by advancing the timer and verify data that is + // being enqueued via ERP. + MockClock::Get().Advance( + metrics::kDefaultDeviceActivityHeartbeatCollectionRate); + const auto [priority, record] = missive_observer.GetNextEnqueuedRecord(); + const auto& metric_data = AssertAppUsageTelemetryData(priority, record); + + // Data reported includes usage from the web app + the native Chrome + // component application since these leverage the browser. + const auto& app_usage_data = + metric_data.telemetry_data().app_telemetry().app_usage_data(); + ASSERT_THAT(app_usage_data.app_usage().size(), Eq(2)); + ASSERT_THAT( + app_usage_data.app_usage(), + UnorderedPointwise( + ContainsAppId(), + {app_id, static_cast<std::string>(::app_constants::kChromeAppId)})); + const auto& app_usage = GetAppUsageInfoForApp(app_usage_data, app_id); + VerifyAppUsage(app_usage, app_id, kAppUsageDuration); + + // Trigger upload to UKM by advancing the timer. + MockClock::Get().Advance(kAppUsageUKMReportingInterval); + ::content::RunAllTasksUntilIdle(); + VerifyWebAppUsageUKM(app_usage.app_instance_id(), kAppUsageDuration); + + // Advance the timer and verify data is cleared by the next upload cycle. + MockClock::Get().Advance(kAppUsageUKMReportingInterval); + ::content::RunAllTasksUntilIdle(); + ASSERT_FALSE(profile() + ->GetPrefs() + ->GetDict(::apps::kAppUsageTime) + .contains(app_usage.app_instance_id())); +} + +IN_PROC_BROWSER_TEST_F(AppUsageTelemetrySamplerBrowserTest, + PRE_ReportUsageDataWhenSyncDisabled) { + // Dummy case that sets up the affiliated user through SetUpOnMainThread + // PRE-condition. +} + +IN_PROC_BROWSER_TEST_F(AppUsageTelemetrySamplerBrowserTest, + ReportUsageDataWhenSyncDisabled) { + ASSERT_TRUE(base::FeatureList::IsEnabled(kEnableAppMetricsReporting)); + sync_service()->SetDisableReasons( + ::syncer::SyncService::DISABLE_REASON_ENTERPRISE_POLICY); + + // Install web app and simulate its usage. + const auto& app_id = InstallStandaloneWebApp(GURL(kWebAppUrl)); + static constexpr base::TimeDelta kAppUsageDuration = base::Minutes(2); + ::chromeos::MissiveClientTestObserver missive_observer( + base::BindRepeating(&IsAppUsageTelemetry)); + SimulateAppUsage(app_id, kAppUsageDuration); + + // Force telemetry collection by advancing the timer and verify data that is + // being enqueued via ERP. + MockClock::Get().Advance( + metrics::kDefaultDeviceActivityHeartbeatCollectionRate); + const auto [priority, record] = missive_observer.GetNextEnqueuedRecord(); + const auto& metric_data = AssertAppUsageTelemetryData(priority, record); + + // Data reported includes usage from the web app + the native Chrome + // component application since these leverage the browser. + const auto& app_usage_data = + metric_data.telemetry_data().app_telemetry().app_usage_data(); + ASSERT_THAT(app_usage_data.app_usage().size(), Eq(2)); + ASSERT_THAT( + app_usage_data.app_usage(), + UnorderedPointwise( + ContainsAppId(), + {app_id, static_cast<std::string>(::app_constants::kChromeAppId)})); + const auto& app_usage = GetAppUsageInfoForApp(app_usage_data, app_id); + VerifyAppUsage(app_usage, app_id, kAppUsageDuration); + + // Advance timer and verify no data is reported to UKM. + MockClock::Get().Advance(kAppUsageUKMReportingInterval); + ::content::RunAllTasksUntilIdle(); + ASSERT_THAT( + test_ukm_recorder_->GetEntriesByName(kAppUsageUKMEntryName).size(), + Eq(0uL)); +} + +IN_PROC_BROWSER_TEST_F(AppUsageTelemetrySamplerBrowserTest, + PRE_ReportUsageDataWhenPolicyDisabled) { + // Dummy case that sets up the affiliated user through SetUpOnMainThread + // PRE-condition. +} + +IN_PROC_BROWSER_TEST_F(AppUsageTelemetrySamplerBrowserTest, + ReportUsageDataWhenPolicyDisabled) { + ASSERT_TRUE(base::FeatureList::IsEnabled(kEnableAppMetricsReporting)); + SetPolicyEnabled(false); + + // Install web app and simulate its usage. + const auto& app_id = InstallStandaloneWebApp(GURL(kWebAppUrl)); + static constexpr base::TimeDelta kAppUsageDuration = base::Minutes(2); + ::chromeos::MissiveClientTestObserver missive_observer( + base::BindRepeating(&IsAppUsageTelemetry)); + SimulateAppUsage(app_id, kAppUsageDuration); + + // Force telemetry collection by advancing the timer and verify no data is + // being enqueued. + MockClock::Get().Advance( + metrics::kDefaultDeviceActivityHeartbeatCollectionRate); + ::content::RunAllTasksUntilIdle(); + ASSERT_FALSE(missive_observer.HasNewEnqueuedRecords()); +} + +} // namespace +} // namespace reporting
diff --git a/chrome/browser/ash/policy/status_collector/device_status_collector.cc b/chrome/browser/ash/policy/status_collector/device_status_collector.cc index 79f54fa..146bcf4 100644 --- a/chrome/browser/ash/policy/status_collector/device_status_collector.cc +++ b/chrome/browser/ash/policy/status_collector/device_status_collector.cc
@@ -43,6 +43,7 @@ #include "base/version.h" #include "chrome/browser/ash/app_mode/arc/arc_kiosk_app_manager.h" #include "chrome/browser/ash/app_mode/kiosk_app_manager.h" +#include "chrome/browser/ash/crosapi/browser_util.h" #include "chrome/browser/ash/crostini/crostini_pref_names.h" #include "chrome/browser/ash/crostini/crostini_reporting_util.h" #include "chrome/browser/ash/crostini/crostini_util.h" @@ -2261,6 +2262,8 @@ em::DeviceStatusReportRequest* status) { status->set_os_version(os_version_); status->set_browser_version(version_info::GetVersionNumber()); + status->set_is_lacros_primary_browser( + crosapi::browser_util::IsLacrosPrimaryBrowser()); status->set_channel(ConvertToProtoChannel(chrome::GetChannel())); // TODO(b/144081278): Remove when resolved.
diff --git a/chrome/browser/ash/policy/status_collector/device_status_collector_browsertest.cc b/chrome/browser/ash/policy/status_collector/device_status_collector_browsertest.cc index 92d9df1..7b86d28 100644 --- a/chrome/browser/ash/policy/status_collector/device_status_collector_browsertest.cc +++ b/chrome/browser/ash/policy/status_collector/device_status_collector_browsertest.cc
@@ -1755,6 +1755,7 @@ // Expect the version info to be reported by default. GetStatus(); EXPECT_TRUE(device_status_.has_browser_version()); + EXPECT_TRUE(device_status_.has_is_lacros_primary_browser()); EXPECT_TRUE(device_status_.has_channel()); EXPECT_TRUE(device_status_.has_os_version()); EXPECT_TRUE(device_status_.has_firmware_version()); @@ -1768,6 +1769,7 @@ ->set_status(::tpm_manager::STATUS_DBUS_ERROR); GetStatus(); EXPECT_TRUE(device_status_.has_browser_version()); + EXPECT_TRUE(device_status_.has_is_lacros_primary_browser()); EXPECT_TRUE(device_status_.has_channel()); EXPECT_TRUE(device_status_.has_os_version()); EXPECT_TRUE(device_status_.has_firmware_version()); @@ -1784,6 +1786,7 @@ ash::kReportDeviceVersionInfo, false); GetStatus(); EXPECT_FALSE(device_status_.has_browser_version()); + EXPECT_FALSE(device_status_.has_is_lacros_primary_browser()); EXPECT_FALSE(device_status_.has_channel()); EXPECT_FALSE(device_status_.has_os_version()); EXPECT_FALSE(device_status_.has_firmware_version()); @@ -1794,6 +1797,7 @@ ash::kReportDeviceVersionInfo, true); GetStatus(); EXPECT_TRUE(device_status_.has_browser_version()); + EXPECT_TRUE(device_status_.has_is_lacros_primary_browser()); EXPECT_TRUE(device_status_.has_channel()); EXPECT_TRUE(device_status_.has_os_version()); EXPECT_TRUE(device_status_.has_firmware_version());
diff --git a/chrome/browser/ash/set_time_dialog.cc b/chrome/browser/ash/set_time_dialog.cc index 6cb65516..d56f7a6 100644 --- a/chrome/browser/ash/set_time_dialog.cc +++ b/chrome/browser/ash/set_time_dialog.cc
@@ -17,8 +17,8 @@ // Dialog width and height in DIPs. const int kDefaultWidth = 530; -const int kDefaultHeightWithTimezone = 286; -const int kDefaultHeightWithoutTimezone = 228; +const int kDefaultHeightWithTimezone = 396; +const int kDefaultHeightWithoutTimezone = 238; } // namespace
diff --git a/chrome/browser/autocomplete/search_provider_unittest.cc b/chrome/browser/autocomplete/search_provider_unittest.cc index a7181bdc..7406cc148 100644 --- a/chrome/browser/autocomplete/search_provider_unittest.cc +++ b/chrome/browser/autocomplete/search_provider_unittest.cc
@@ -2546,11 +2546,10 @@ // Check for the match and field trial triggered bits. AutocompleteMatch match; EXPECT_TRUE(FindMatchWithContents(u"foo bar", &match)); - EXPECT_EQ( - client_->GetOmniboxTriggeredFeatureService() - ->GetFeatureTriggeredInSession( - OmniboxTriggeredFeatureService::Feature::kRemoteSearchFeature), - trigger); + EXPECT_EQ(client_->GetOmniboxTriggeredFeatureService() + ->GetFeatureTriggeredInSession( + metrics::OmniboxEventProto_Feature_REMOTE_SEARCH_FEATURE), + trigger); }; {
diff --git a/chrome/browser/autofill/autofill_image_fetcher_impl.cc b/chrome/browser/autofill/autofill_image_fetcher_impl.cc index 886d89e..6fbdbe2 100644 --- a/chrome/browser/autofill/autofill_image_fetcher_impl.cc +++ b/chrome/browser/autofill/autofill_image_fetcher_impl.cc
@@ -15,6 +15,9 @@ #include "components/image_fetcher/core/request_metadata.h" #include "net/http/http_status_code.h" #include "net/traffic_annotation/network_traffic_annotation.h" +#include "third_party/skia/include/core/SkColor.h" +#include "ui/gfx/canvas.h" +#include "ui/gfx/geometry/rect_f.h" #include "ui/gfx/image/image.h" #include "ui/gfx/image/image_skia.h" #include "ui/gfx/image/image_skia_operations.h" @@ -60,6 +63,16 @@ // The SkAlpha value for the image grey overlay. constexpr double kImageOverlayAlpha = 0.04; // 4% +// The border color used for card art images. +constexpr SkColor kCardArtBorderColor = SkColorSetARGB(0xFF, 0xE3, 0xE3, 0xE3); + +// The stroke width of the card art border. +constexpr int kCardArtBorderStrokeWidth = 2; + +// The width and length card art is resized to. +constexpr int kCardArtImageWidth = 40; +constexpr int kCardArtImageHeight = 24; + } // namespace AutofillImageFetcherImpl::AutofillImageFetcherImpl(ProfileKey* key) @@ -106,12 +119,52 @@ if (!card_art_image.IsEmpty()) { if (base::FeatureList::IsEnabled( features::kAutofillEnableNewCardArtAndNetworkImages)) { - credit_card_art_image->card_art_image = - gfx::Image(gfx::ImageSkiaOperations::CreateImageWithRoundRectClip( - kCardArtImageRadius, - gfx::ImageSkiaOperations::CreateResizedImage( - card_art_image.AsImageSkia(), - skia::ImageOperations::RESIZE_BEST, gfx::Size(40, 24)))); + if (card_art_url == + "https://www.gstatic.com/autofill/virtualcard/icon/" + "capitalone_40_24.png") { + // Render Capital One asset directly. No need to calculate and add grey + // border to image. + credit_card_art_image->card_art_image = card_art_image; + } else { + // Create the outer rectange. The outer rectangle is for the + // entire image which includes the card art and additional border. + gfx::RectF outer_rect = + gfx::RectF(kCardArtImageWidth, kCardArtImageHeight); + + // The inner rectangle only includes the card art. To calculate the + // inner rectangle, we need to factor the space that the border stroke + // will take up. + gfx::RectF inner_rect = gfx::RectF( + /*x=*/kCardArtBorderStrokeWidth, /*y=*/kCardArtBorderStrokeWidth, + /*width=*/kCardArtImageWidth - (kCardArtBorderStrokeWidth * 2), + /*height=*/kCardArtImageHeight - (kCardArtBorderStrokeWidth * 2)); + gfx::Canvas canvas = + gfx::Canvas(gfx::Size(kCardArtImageWidth, kCardArtImageHeight), + /*image_scale=*/1.0f, /*is_opaque=*/false); + cc::PaintFlags card_art_paint; + card_art_paint.setAntiAlias(true); + + // Draw card art with rounded corners in the inner rectangle. + canvas.DrawRoundRect(inner_rect, kCardArtImageRadius, card_art_paint); + canvas.DrawImageInt( + gfx::ImageSkiaOperations::CreateResizedImage( + card_art_image.AsImageSkia(), + skia::ImageOperations::RESIZE_BEST, + gfx::Size(kCardArtImageWidth, kCardArtImageHeight)), + outer_rect.x(), outer_rect.y(), card_art_paint); + + // Draw border around card art using outer rectangle. + card_art_paint.setStrokeWidth(kCardArtBorderStrokeWidth); + card_art_paint.setColor(kCardArtBorderColor); + card_art_paint.setStyle(cc::PaintFlags::kStroke_Style); + canvas.DrawRoundRect(outer_rect, kCardArtImageRadius, card_art_paint); + + // Add radius around entire image. + credit_card_art_image->card_art_image = + gfx::Image(gfx::ImageSkiaOperations::CreateImageWithRoundRectClip( + kCardArtImageRadius, + gfx::ImageSkia::CreateFromBitmap(canvas.GetBitmap(), 1.0f))); + } } else { credit_card_art_image->card_art_image = AutofillImageFetcherImpl::ApplyGreyOverlay(card_art_image);
diff --git a/chrome/browser/back_press/android/BUILD.gn b/chrome/browser/back_press/android/BUILD.gn index 228f42e..a195957 100644 --- a/chrome/browser/back_press/android/BUILD.gn +++ b/chrome/browser/back_press/android/BUILD.gn
@@ -33,6 +33,7 @@ "//base:base_java_test_support", "//base:base_junit_test_support", "//base/test:test_support_java", + "//chrome/browser/flags:java", "//components/browser_ui/widget/android:java", "//third_party/androidx:androidx_activity_activity_java", "//third_party/junit:junit",
diff --git a/chrome/browser/back_press/android/java/src/org/chromium/chrome/browser/back_press/BackPressManager.java b/chrome/browser/back_press/android/java/src/org/chromium/chrome/browser/back_press/BackPressManager.java index 0ccafb0..05885ab5 100644 --- a/chrome/browser/back_press/android/java/src/org/chromium/chrome/browser/back_press/BackPressManager.java +++ b/chrome/browser/back_press/android/java/src/org/chromium/chrome/browser/back_press/BackPressManager.java
@@ -73,6 +73,7 @@ static final String FAILURE_HISTOGRAM = "Android.BackPress.Failure"; private final BackPressHandler[] mHandlers = new BackPressHandler[Type.NUM_TYPES]; + private final boolean mUseSystemBack; private final Callback<Boolean>[] mObserverCallbacks = new Callback[Type.NUM_TYPES]; private Runnable mFallbackOnBackPressed; @@ -115,6 +116,8 @@ public BackPressManager() { mFallbackOnBackPressed = () -> {}; + mUseSystemBack = MinimizeAppAndCloseTabBackPressHandler.shouldUseSystemBack(); + backPressStateChanged(); } /** @@ -179,7 +182,11 @@ } private void backPressStateChanged() { - mCallback.setEnabled(shouldInterceptBackPress()); + boolean intercept = shouldInterceptBackPress(); + // If not using system back and MINIMIZE_APP_AND_CLOSE_TAB has registered, this must be + // true, since MINIMIZE_APP_AND_CLOSE_TAB unconditionally consumes last back press. + assert mUseSystemBack || !has(Type.MINIMIZE_APP_AND_CLOSE_TAB) || intercept; + mCallback.setEnabled(intercept || !mUseSystemBack); } private void handleBackPress() { @@ -213,12 +220,10 @@ removeHandler(i); } } - // All handlers have been removed, so no handler will consume the back event. As a result, - // the callback should be disabled so that the OS can handle the back press. - assert !mCallback.isEnabled(); } - private boolean shouldInterceptBackPress() { + @VisibleForTesting + boolean shouldInterceptBackPress() { for (BackPressHandler handler : mHandlers) { if (handler == null) continue; if (!Boolean.TRUE.equals(handler.getHandleBackPressChangedSupplier().get())) continue;
diff --git a/chrome/browser/back_press/android/java/src/org/chromium/chrome/browser/back_press/BackPressManagerUnitTest.java b/chrome/browser/back_press/android/java/src/org/chromium/chrome/browser/back_press/BackPressManagerUnitTest.java index 9d5d466cb..b19a1a5 100644 --- a/chrome/browser/back_press/android/java/src/org/chromium/chrome/browser/back_press/BackPressManagerUnitTest.java +++ b/chrome/browser/back_press/android/java/src/org/chromium/chrome/browser/back_press/BackPressManagerUnitTest.java
@@ -4,14 +4,19 @@ package org.chromium.chrome.browser.back_press; +import android.os.Build; + import org.junit.Assert; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.annotation.Config; +import org.chromium.base.FeatureList; import org.chromium.base.supplier.ObservableSupplierImpl; import org.chromium.base.test.BaseRobolectricTestRunner; import org.chromium.base.test.util.CallbackHelper; +import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.components.browser_ui.widget.gesture.BackPressHandler; /** @@ -41,6 +46,16 @@ } @Test + @Before + public void setup() { + MinimizeAppAndCloseTabBackPressHandler.setVersionForTesting(Build.VERSION_CODES.TIRAMISU); + FeatureList.TestValues testValues = new FeatureList.TestValues(); + testValues.addFieldTrialParamOverride( + ChromeFeatureList.BACK_GESTURE_REFACTOR, "system_back", "true"); + FeatureList.setTestValues(testValues); + } + + @Test public void testBasic() { BackPressManager manager = new BackPressManager(); EmptyBackPressHandler h1 = new EmptyBackPressHandler(); @@ -259,6 +274,27 @@ manager.getCallback().isEnabled()); } + // Test callback is always enabled to trigger fallbacks for groups without system back. + @Test + public void testAlwaysEnabledCallback() { + FeatureList.TestValues testValues = new FeatureList.TestValues(); + testValues.addFieldTrialParamOverride( + ChromeFeatureList.BACK_GESTURE_REFACTOR, "system_back", "false"); + FeatureList.setTestValues(testValues); + + BackPressManager manager = new BackPressManager(); + EmptyBackPressHandler h1 = new EmptyBackPressHandler(); + EmptyBackPressHandler h2 = new EmptyBackPressHandler(); + manager.addHandler(h1, 0); + manager.addHandler(h2, 1); + h1.getHandleBackPressChangedSupplier().set(true); + Assert.assertTrue("Callback should be enabled if any of handlers are enabled", + manager.getCallback().isEnabled()); + h1.getHandleBackPressChangedSupplier().set(false); + Assert.assertFalse("No handler is enabled", manager.shouldInterceptBackPress()); + Assert.assertTrue("Callback is always enabled", manager.getCallback().isEnabled()); + } + private int getHandlerCount(BackPressManager manager) { int count = 0; for (BackPressHandler handler : manager.getHandlersForTesting()) {
diff --git a/chrome/browser/back_press/android/java/src/org/chromium/chrome/browser/back_press/MinimizeAppAndCloseTabBackPressHandler.java b/chrome/browser/back_press/android/java/src/org/chromium/chrome/browser/back_press/MinimizeAppAndCloseTabBackPressHandler.java index 3afd921..090070cf 100644 --- a/chrome/browser/back_press/android/java/src/org/chromium/chrome/browser/back_press/MinimizeAppAndCloseTabBackPressHandler.java +++ b/chrome/browser/back_press/android/java/src/org/chromium/chrome/browser/back_press/MinimizeAppAndCloseTabBackPressHandler.java
@@ -130,6 +130,10 @@ minimizeApp = true; shouldCloseTab = false; } else { + // TAB history handler has a higher priority and should navigate page back before + // minimizing app and closing tab. + assert !currentTab.canGoBack() + : "Tab should be navigated back before closing or exiting app"; // At this point we know either the tab will close or the app will minimize. NativePage nativePage = currentTab.getNativePage(); if (nativePage != null) { @@ -177,7 +181,7 @@ mBackPressSupplier.set(tab != null && mBackShouldCloseTab.test(tab)); } - private static boolean shouldUseSystemBack() { + static boolean shouldUseSystemBack() { // https://developer.android.com/about/versions/12/behavior-changes-all#back-press // Starting from 12, root launcher activities are no longer finished on Back press. // Limiting to T, since some OEMs seem to still finish activity on 12.
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd index d2102c1..12e05da 100644 --- a/chrome/browser/browser_resources.grd +++ b/chrome/browser/browser_resources.grd
@@ -160,6 +160,7 @@ <include name="IDR_DEVICE_EMULATOR_PAGES_JS" file="${root_gen_dir}\chrome\browser\resources\chromeos\emulator\device_emulator_pages.js" use_base_dir="false" type="BINDATA" /> <include name="IDR_DEVICE_EMULATOR_SHARED_STYLES_JS" file="${root_gen_dir}\chrome\browser\resources\chromeos\emulator\shared_styles.js" use_base_dir="false" type="BINDATA" /> <include name="IDR_SET_TIME_HTML" file="resources\chromeos\set_time_dialog\set_time.html" type="BINDATA" /> + <include name="IDR_SET_TIME_JS" file="resources\chromeos\set_time_dialog\set_time.js" type="BINDATA" /> <include name="IDR_SET_TIME_DIALOG_HTML_JS" file="${root_gen_dir}\chrome\browser\resources\chromeos\set_time_dialog\set_time_dialog.html.js" use_base_dir="false" type="BINDATA" /> <include name="IDR_SET_TIME_DIALOG_JS" file="resources\chromeos\set_time_dialog\set_time_dialog.js" type="BINDATA" /> <include name="IDR_SET_TIME_BROWSER_PROXY_JS" file="resources\chromeos\set_time_dialog\set_time_browser_proxy.js" type="BINDATA" />
diff --git a/chrome/browser/chrome_browser_interface_binders.cc b/chrome/browser/chrome_browser_interface_binders.cc index 0d1aaeb..837f459b 100644 --- a/chrome/browser/chrome_browser_interface_binders.cc +++ b/chrome/browser/chrome_browser_interface_binders.cc
@@ -293,6 +293,7 @@ #include "chrome/browser/ui/webui/ash/office_fallback/office_fallback_ui.h" #include "chrome/browser/ui/webui/ash/parent_access/parent_access_ui.h" #include "chrome/browser/ui/webui/ash/parent_access/parent_access_ui.mojom.h" +#include "chrome/browser/ui/webui/ash/set_time_ui.h" #include "chrome/browser/ui/webui/ash/smb_shares/smb_credentials_dialog.h" #include "chrome/browser/ui/webui/ash/smb_shares/smb_share_dialog.h" #include "chrome/browser/ui/webui/ash/vm/vm.mojom.h" @@ -978,7 +979,7 @@ ash::FirmwareUpdateAppUI, ash::ScanningUI, ash::OSFeedbackUI, ash::ShortcutCustomizationAppUI, ash::printing::printing_manager::PrintManagementUI, - ash::InternetDetailDialogUI, + ash::InternetDetailDialogUI, ash::SetTimeUI, #endif NewTabPageUI, OmniboxPopupUI, BookmarksSidePanelUI, CustomizeChromeUI>( map);
diff --git a/chrome/browser/first_party_sets/first_party_sets_navigation_throttle.cc b/chrome/browser/first_party_sets/first_party_sets_navigation_throttle.cc index 4c97c8f..f80959c 100644 --- a/chrome/browser/first_party_sets/first_party_sets_navigation_throttle.cc +++ b/chrome/browser/first_party_sets/first_party_sets_navigation_throttle.cc
@@ -53,6 +53,9 @@ base::BindOnce(&FirstPartySetsNavigationThrottle::OnTimeOut, weak_factory_.GetWeakPtr())); + CHECK(!throttle_navigation_timer_.has_value()); + throttle_navigation_timer_ = {base::ElapsedTimer()}; + return content::NavigationThrottle::DEFER; } return content::NavigationThrottle::PROCEED; @@ -114,6 +117,10 @@ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(!resumed_); resumed_ = true; + + CHECK(throttle_navigation_timer_.has_value()); + base::UmaHistogramTimes("FirstPartySets.NavigationThrottle.ResumeDelta", + throttle_navigation_timer_->Elapsed()); NavigationThrottle::Resume(); }
diff --git a/chrome/browser/first_party_sets/first_party_sets_navigation_throttle.h b/chrome/browser/first_party_sets/first_party_sets_navigation_throttle.h index 61bafbd..11b8f02 100644 --- a/chrome/browser/first_party_sets/first_party_sets_navigation_throttle.h +++ b/chrome/browser/first_party_sets/first_party_sets_navigation_throttle.h
@@ -11,6 +11,7 @@ #include "base/memory/weak_ptr.h" #include "base/sequence_checker.h" #include "base/thread_annotations.h" +#include "base/timer/elapsed_timer.h" #include "base/timer/timer.h" #include "content/public/browser/navigation_throttle.h" @@ -61,6 +62,10 @@ base::OneShotTimer resume_navigation_timer_ GUARDED_BY_CONTEXT(sequence_checker_); + // Timer starting when a navigation gets deferred. + absl::optional<base::ElapsedTimer> throttle_navigation_timer_ + GUARDED_BY_CONTEXT(sequence_checker_); + // Stores the state of whether the navigation has been resumed, to make sure // the navigation is only resumed once. bool resumed_ GUARDED_BY_CONTEXT(sequence_checker_) = false;
diff --git a/chrome/browser/first_party_sets/first_party_sets_navigation_throttle_unittest.cc b/chrome/browser/first_party_sets/first_party_sets_navigation_throttle_unittest.cc index 4f3d4ed..7fe23e5 100644 --- a/chrome/browser/first_party_sets/first_party_sets_navigation_throttle_unittest.cc +++ b/chrome/browser/first_party_sets/first_party_sets_navigation_throttle_unittest.cc
@@ -153,6 +153,8 @@ } TEST_F(FirstPartySetsNavigationThrottleTest, WillStartRequest_Proceed) { + base::HistogramTester histograms; + // Create throttle for main frames. content::MockNavigationHandle handle(GURL(kExampleURL), main_rfh()); ASSERT_TRUE(handle.IsInOutermostMainFrame()); @@ -167,6 +169,9 @@ ->is_ready()); EXPECT_EQ(content::NavigationThrottle::PROCEED, throttle->WillStartRequest().action()); + + histograms.ExpectTotalCount("FirstPartySets.NavigationThrottle.ResumeDelta", + 0); } TEST_F(FirstPartySetsNavigationThrottleTest, ResumeOnReady) { @@ -189,6 +194,9 @@ run_loop.Run(); + histograms.ExpectTotalCount("FirstPartySets.NavigationThrottle.ResumeDelta", + 1); + EXPECT_FALSE(throttle->GetTimerForTesting().IsRunning()); histograms.ExpectUniqueSample( "FirstPartySets.NavigationThrottle.ResumeOnTimeout", false, @@ -222,6 +230,9 @@ histograms.ExpectBucketCount( "FirstPartySets.NavigationThrottle.ResumeOnTimeout", false, /*expected_count=*/0); + + histograms.ExpectTotalCount("FirstPartySets.NavigationThrottle.ResumeDelta", + 1); } } // namespace first_party_sets
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index 2612a55..c5c4701 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -29,6 +29,11 @@ [ { + "name": "access-code-cast-freeze-ui", + "owners": [ "bzielinski@google.com", "dorianbrandon@google.com", "cros-edu-eng@google.com" ], + "expiry_milestone": 118 + }, + { "name": "accessible-pdf-form", "owners": [ "bravi@microsoft.com", "mohitb@microsoft.com" ], "expiry_milestone": 110 @@ -5741,6 +5746,11 @@ "expiry_milestone": 120 }, { + "name": "omnibox-warm-recycled-view-pool", + "owners": [ "pnoland", "chrome-omnibox-team@google.com" ], + "expiry_milestone": 120 + }, + { "name": "omnibox-zero-suggest-in-memory-caching", "owners": [ "khalidpeer", "mahmadi", "chrome-omnibox-team@google.com" ], "expiry_milestone": 120
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index 2b58d6bf..578b9e8a 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -1378,12 +1378,6 @@ 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."; @@ -2217,6 +2211,12 @@ "Use an alternative implementation of calculating the cached omnibox " "current match that is valid more often."; +const char kOmniboxWarmRecycledViewPoolName[] = + "Omnibox warm recycled view pool"; +const char kOmniboxWarmRecycledViewPoolDescription[] = + "Pre-warms the Android Omnibox's RecyclerView pool by inflating " + "views before the omnibox is focused."; + const char kOmniboxReportAssistedQueryStatsName[] = "Omnibox Assisted Query Stats param"; const char kOmniboxReportAssistedQueryStatsDescription[] = @@ -4362,6 +4362,12 @@ #else // BUILDFLAG(IS_ANDROID) +const char kAccessCodeCastFreezeUiName[] = + "Pause Cast sessions (Access Code Cast users only)"; +const char kAccessCodeCastFreezeUiDescription[] = + "When enabled, adds controls to pause Cast sessions when sharing tab or " + "screen, if using Access Code Casting."; + const char kAppManagementAppDetailsName[] = "Enable App Details in App Management."; const char kAppManagementAppDetailsDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index 83e1319..bb33d3a 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -772,9 +772,6 @@ extern const char kEnableZeroCopyTabCaptureName[]; extern const char kEnableZeroCopyTabCaptureDescription[]; -extern const char kEnableRegionCaptureExperimentalSubtypesName[]; -extern const char kEnableRegionCaptureExperimentalSubtypesDescription[]; - extern const char kExperimentalWebAssemblyFeaturesName[]; extern const char kExperimentalWebAssemblyFeaturesDescription[]; @@ -1271,6 +1268,9 @@ extern const char kOmniboxRedoCurrentMatchName[]; extern const char kOmniboxRedoCurrentMatchDescription[]; +extern const char kOmniboxWarmRecycledViewPoolName[]; +extern const char kOmniboxWarmRecycledViewPoolDescription[]; + extern const char kOmniboxRevertModelBeforeClosingPopupName[]; extern const char kOmniboxRevertModelBeforeClosingPopupDescription[]; @@ -2502,6 +2502,9 @@ #else // !BUILDFLAG(IS_ANDROID) +extern const char kAccessCodeCastFreezeUiName[]; +extern const char kAccessCodeCastFreezeUiDescription[]; + extern const char kAppManagementAppDetailsName[]; extern const char kAppManagementAppDetailsDescription[];
diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc index 71a2557..876939f 100644 --- a/chrome/browser/flags/android/chrome_feature_list.cc +++ b/chrome/browser/flags/android/chrome_feature_list.cc
@@ -261,6 +261,7 @@ &kOmniboxCacheSuggestionResources, &kOmniboxConsumesImeInsets, &kOmniboxModernizeVisualUpdate, + &kOmniboxWarmRecycledViewPool, &kOpaqueOriginForIncomingIntents, &kPartnerHomepageInitialLoadImprovement, &kProbabilisticCryptidRenderer, @@ -843,6 +844,10 @@ "OmniboxModernizeVisualUpdate", base::FEATURE_DISABLED_BY_DEFAULT); +BASE_FEATURE(kOmniboxWarmRecycledViewPool, + "OmniboxWarmRecycledViewPool", + base::FEATURE_DISABLED_BY_DEFAULT); + BASE_FEATURE(kOpaqueOriginForIncomingIntents, "OpaqueOriginForIncomingIntents", base::FEATURE_ENABLED_BY_DEFAULT); @@ -965,7 +970,7 @@ BASE_FEATURE(kShareSheetMigrationAndroid, "ShareSheetMigrationAndroid", - base::FEATURE_DISABLED_BY_DEFAULT); + base::FEATURE_ENABLED_BY_DEFAULT); BASE_FEATURE(kSpecialLocaleWrapper, "SpecialLocaleWrapper",
diff --git a/chrome/browser/flags/android/chrome_feature_list.h b/chrome/browser/flags/android/chrome_feature_list.h index 9ae5d39..de67999d 100644 --- a/chrome/browser/flags/android/chrome_feature_list.h +++ b/chrome/browser/flags/android/chrome_feature_list.h
@@ -119,6 +119,7 @@ BASE_DECLARE_FEATURE(kOmniboxCacheSuggestionResources); BASE_DECLARE_FEATURE(kOmniboxConsumesImeInsets); BASE_DECLARE_FEATURE(kOmniboxModernizeVisualUpdate); +BASE_DECLARE_FEATURE(kOmniboxWarmRecycledViewPool); BASE_DECLARE_FEATURE(kOptimizeGeolocationHeaderGeneration); BASE_DECLARE_FEATURE(kPageAnnotationsService); BASE_DECLARE_FEATURE(kBookmarksImprovedSaveFlow);
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java index 67e59135..7da9938 100644 --- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java +++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
@@ -391,6 +391,7 @@ "OmniboxMostVisitedTilesAddRecycledViewPool"; public static final String OMNIBOX_UPDATED_CONNECTION_SECURITY_INDICATORS = "OmniboxUpdatedConnectionSecurityIndicators"; + public static final String OMNIBOX_WARM_RECYCLED_VIEW_POOL = "OmniboxWarmRecycledViewPool"; public static final String OPAQUE_ORIGIN_FOR_INCOMING_INTENTS = "OpaqueOriginForIncomingIntents"; public static final String OPTIMIZATION_GUIDE_PUSH_NOTIFICATIONS =
diff --git a/chrome/browser/geolocation/geolocation_browsertest.cc b/chrome/browser/geolocation/geolocation_browsertest.cc index c9a1fd1..ac3b4c6 100644 --- a/chrome/browser/geolocation/geolocation_browsertest.cc +++ b/chrome/browser/geolocation/geolocation_browsertest.cc
@@ -49,10 +49,7 @@ std::string RunScript(content::RenderFrameHost* render_frame_host, const std::string& script) { - std::string result; - EXPECT_TRUE(content::ExecuteScriptAndExtractString(render_frame_host, script, - &result)); - return result; + return content::EvalJs(render_frame_host, script).ExtractString(); } // IFrameLoader --------------------------------------------------------------- @@ -110,8 +107,7 @@ EXPECT_EQ(base::StringPrintf("\"%d\"", iframe_id), javascript_response_); content::WebContentsObserver::Observe(nullptr); // Now that we loaded the iframe, let's fetch its src. - script = base::StringPrintf( - "window.domAutomationController.send(getIFrameSrc(%d))", iframe_id); + script = base::StringPrintf("getIFrameSrc(%d)", iframe_id); iframe_url_ = GURL(RunScript(web_contents->GetPrimaryMainFrame(), script)); } @@ -365,9 +361,7 @@ const std::string& expected, const std::string& function, content::RenderFrameHost* render_frame_host) { - std::string script(base::StringPrintf( - "window.domAutomationController.send(%s)", function.c_str())); - EXPECT_EQ(expected, RunScript(render_frame_host, script)); + EXPECT_EQ(expected, RunScript(render_frame_host, function)); } void GeolocationBrowserTest::ExpectValueFromScript( @@ -378,17 +372,13 @@ bool GeolocationBrowserTest::SetPositionAndWaitUntilUpdated(double latitude, double longitude) { - content::DOMMessageQueue dom_message_queue(render_frame_host_); - fake_latitude_ = latitude; fake_longitude_ = longitude; geolocation_overrider_->UpdateLocation(fake_latitude_, fake_longitude_); - std::string result; - if (!dom_message_queue.WaitForMessage(&result)) - return false; - return result == "\"geoposition-updated\""; + return content::EvalJs(render_frame_host_, "geopositionUpdates.pop();") + .ExtractString() == "geoposition-updated"; } // Tests ----------------------------------------------------------------------
diff --git a/chrome/browser/global_keyboard_shortcuts_mac.h b/chrome/browser/global_keyboard_shortcuts_mac.h index bc4b58a..a37cdb4 100644 --- a/chrome/browser/global_keyboard_shortcuts_mac.h +++ b/chrome/browser/global_keyboard_shortcuts_mac.h
@@ -11,8 +11,6 @@ #if defined(__OBJC__) @class NSEvent; -#else // __OBJC__ -class NSEvent; #endif // __OBJC__ namespace ui { @@ -42,6 +40,8 @@ bool from_main_menu; }; +#if defined(__OBJC__) + // macOS applications are supposed to put all keyEquivalents [hotkeys] in the // menu bar. For legacy reasons, Chrome does not. There are around 30 hotkeys // that are explicitly coded to virtual keycodes. This has the following @@ -69,6 +69,8 @@ // by CommandDispatcher. bool EventUsesPerformKeyEquivalent(NSEvent* event); +#endif // __OBJC__ + // On macOS, most accelerators are defined in MainMenu.xib and are user // configurable. Furthermore, their values and enabled state depends on the key // window. Views code relies on a static mapping that is not dependent on the
diff --git a/chrome/browser/mac/dock.h b/chrome/browser/mac/dock.h index 398dd782..5a1bb78 100644 --- a/chrome/browser/mac/dock.h +++ b/chrome/browser/mac/dock.h
@@ -7,8 +7,6 @@ #if defined(__OBJC__) @class NSString; -#else -class NSString; #endif namespace dock { @@ -28,6 +26,8 @@ // Returns info about Chrome's presence in the Dock. ChromeInDockStatus ChromeIsInTheDock(); +#if defined(__OBJC__) + // Adds an icon to the Dock pointing to |installed_path| if one is not already // present. |dmg_app_path| is the path to the install source. Its tile will be // removed if present. If any changes are made to the Dock's configuration, @@ -66,6 +66,8 @@ // the properties it requires and add them to its configuration. AddIconStatus AddIcon(NSString* installed_path, NSString* dmg_app_path); +#endif // __OBJC__ + } // namespace dock #endif // CHROME_BROWSER_MAC_DOCK_H_
diff --git a/chrome/browser/media/cast_mirroring_service_host.cc b/chrome/browser/media/cast_mirroring_service_host.cc index 2672bffb..0cc5e9d 100644 --- a/chrome/browser/media/cast_mirroring_service_host.cc +++ b/chrome/browser/media/cast_mirroring_service_host.cc
@@ -151,16 +151,6 @@ Profile::FromBrowserContext(web_contents->GetBrowserContext())); } -// Returns true if this user is allowed to use Access Codes to -// discover cast devices, and IsAccessCodeCastFreezeUiEnabled flag is enabled. -bool IsAccessCodeCastFreezeUIEnabled( - const content::WebContentsMediaCaptureId& id) { - auto* web_contents = GetContents(id); - return web_contents && - media_router::IsAccessCodeCastFreezeUiEnabled( - Profile::FromBrowserContext(web_contents->GetBrowserContext())); -} - // Returns the size of the primary display in pixels, or absl::nullopt if it // cannot be determined. absl::optional<gfx::Size> GetScreenResolution() { @@ -179,9 +169,7 @@ : source_media_id_(source_media_id), gpu_client_(nullptr, base::OnTaskRunnerDeleter(nullptr)), tab_switching_ui_enabled_(IsAccessCodeCastTabSwitchingUIEnabled( - source_media_id.web_contents_id)), - freeze_ui_enabled_( - IsAccessCodeCastFreezeUIEnabled(source_media_id.web_contents_id)) { + source_media_id.web_contents_id)) { DETACH_FROM_SEQUENCE(sequence_checker_); // Observe the target WebContents for Tab mirroring. if (source_media_id_.type == content::DesktopMediaID::TYPE_WEB_CONTENTS) @@ -615,7 +603,7 @@ void CastMirroringServiceHost::Pause() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - if (freeze_ui_enabled_ && video_capture_host_) { + if (video_capture_host_) { content::GetIOThreadTaskRunner({})->PostDelayedTask( FROM_HERE, base::BindOnce(&PauseVideoCaptureHostOnIO, video_capture_host_->impl(), @@ -626,7 +614,7 @@ void CastMirroringServiceHost::Resume() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - if (freeze_ui_enabled_ && video_capture_host_) { + if (video_capture_host_) { content::GetIOThreadTaskRunner({})->PostTask( FROM_HERE, base::BindOnce(&ResumeVideoCaptureHostOnIO, video_capture_host_->impl(),
diff --git a/chrome/browser/media/cast_mirroring_service_host.h b/chrome/browser/media/cast_mirroring_service_host.h index 0da1ad69..c1836de 100644 --- a/chrome/browser/media/cast_mirroring_service_host.h +++ b/chrome/browser/media/cast_mirroring_service_host.h
@@ -193,8 +193,6 @@ base::UnguessableToken ignored_token_ = base::UnguessableToken::Create(); const media::VideoCaptureParams ignored_params_; - const bool freeze_ui_enabled_; - // Used for calls supplied to `media_stream_ui_`, mainly to handle callbacks // for TabSharingUIViews. Invalidated every time a new UI is created. base::WeakPtrFactory<CastMirroringServiceHost> weak_factory_for_ui_{this};
diff --git a/chrome/browser/media/cast_mirroring_service_host_browsertest.cc b/chrome/browser/media/cast_mirroring_service_host_browsertest.cc index 6fe56b6..9cededf 100644 --- a/chrome/browser/media/cast_mirroring_service_host_browsertest.cc +++ b/chrome/browser/media/cast_mirroring_service_host_browsertest.cc
@@ -383,6 +383,16 @@ StopMirroring(); } +IN_PROC_BROWSER_TEST_F(CastMirroringServiceHostBrowserTest, PauseSession) { + EnableAccessCodeCast(); + StartTabMirroring(); + GetVideoCaptureHost(); + StartVideoCapturing(); + PauseMirroring(); + ResumeMirroring(); + StopMirroring(); +} + class CastMirroringServiceHostBrowserTestTabSwitcher : public CastMirroringServiceHostBrowserTest, public ::testing::WithParamInterface<bool> { @@ -442,39 +452,4 @@ StopMirroring(); } -class CastMirroringServiceHostBrowserTestFreezeSession - : public CastMirroringServiceHostBrowserTest { - public: - CastMirroringServiceHostBrowserTestFreezeSession() { - feature_list_.InitWithFeatures({features::kAccessCodeCastFreezeUI}, {}); - } - - CastMirroringServiceHostBrowserTestFreezeSession( - const CastMirroringServiceHostBrowserTestFreezeSession&) = delete; - CastMirroringServiceHostBrowserTestFreezeSession& operator=( - const CastMirroringServiceHostBrowserTestFreezeSession&) = delete; - - ~CastMirroringServiceHostBrowserTestFreezeSession() override = default; - - void VerifyEnabledFeatures() { - ASSERT_TRUE( - base::FeatureList::IsEnabled(features::kAccessCodeCastFreezeUI)); - } - - private: - base::test::ScopedFeatureList feature_list_; -}; - -IN_PROC_BROWSER_TEST_F(CastMirroringServiceHostBrowserTestFreezeSession, - FreezeSession) { - VerifyEnabledFeatures(); - EnableAccessCodeCast(); - StartTabMirroring(); - GetVideoCaptureHost(); - StartVideoCapturing(); - PauseMirroring(); - ResumeMirroring(); - StopMirroring(); -} - } // namespace mirroring
diff --git a/chrome/browser/media/webrtc/region_capture_browsertest.cc b/chrome/browser/media/webrtc/region_capture_browsertest.cc index 4852f463..99df35f 100644 --- a/chrome/browser/media/webrtc/region_capture_browsertest.cc +++ b/chrome/browser/media/webrtc/region_capture_browsertest.cc
@@ -253,10 +253,7 @@ // detection of JS errors. class RegionCaptureBrowserTest : public WebRtcTestBase { public: - RegionCaptureBrowserTest() { - scoped_feature_list_.InitAndEnableFeature( - blink::features::kRegionCaptureExperimentalSubtypes); - } + RegionCaptureBrowserTest() = default; ~RegionCaptureBrowserTest() override = default; void SetUpInProcessBrowserTestFixture() override {
diff --git a/chrome/browser/printing/print_view_manager_base.cc b/chrome/browser/printing/print_view_manager_base.cc index 5e6e88b..ea3f1ea 100644 --- a/chrome/browser/printing/print_view_manager_base.cc +++ b/chrome/browser/printing/print_view_manager_base.cc
@@ -634,6 +634,17 @@ return; } + bool open_in_external_preview = + job_settings.contains(kSettingOpenPDFInPreview); + if (!open_in_external_preview && + (printer_type == mojom::PrinterType::kPdf || + printer_type == mojom::PrinterType::kExtension)) { + if (print_settings->page_setup_device_units().printable_area().IsEmpty()) { + PrinterQuery::ApplyDefaultPrintableAreaToVirtualPrinterPrintSettings( + *print_settings); + } + } + #if BUILDFLAG(IS_WIN) // TODO(crbug.com/1424368): Remove this if the printable areas can be made // fully available from `PrintBackend::GetPrinterSemanticCapsAndDefaults()`
diff --git a/chrome/browser/printing/printer_query.cc b/chrome/browser/printing/printer_query.cc index e5171c72..e75b560 100644 --- a/chrome/browser/printing/printer_query.cc +++ b/chrome/browser/printing/printer_query.cc
@@ -19,6 +19,7 @@ #include "components/crash/core/common/crash_keys.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" +#include "content/public/browser/global_routing_id.h" #include "content/public/browser/web_contents.h" #include "printing/backend/print_backend.h" #include "printing/buildflags/buildflags.h" @@ -282,6 +283,20 @@ } #endif +// static +void PrinterQuery::ApplyDefaultPrintableAreaToVirtualPrinterPrintSettings( + PrintSettings& print_settings) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + // The purpose of `print_context` is to set the default printable area. To do + // so, it doesn't need a RFH, so just default initialize the RFH id. + PrintingContextDelegate delegate((content::GlobalRenderFrameHostId())); + std::unique_ptr<PrintingContext> print_context = + PrintingContext::Create(&delegate, /*skip_system_calls=*/false); + print_context->SetPrintSettings(print_settings); + print_context->SetDefaultPrintableAreaForVirtualPrinters(); + print_settings = print_context->settings(); +} + #if BUILDFLAG(ENABLE_OOP_PRINTING) void PrinterQuery::SetClientId(PrintBackendServiceManager::ClientId client_id) { // Only supposed to be called for `PrinterQueryOop` objects.
diff --git a/chrome/browser/printing/printer_query.h b/chrome/browser/printing/printer_query.h index ac99fae..28590787 100644 --- a/chrome/browser/printing/printer_query.h +++ b/chrome/browser/printing/printer_query.h
@@ -95,6 +95,12 @@ static bool UpdatePrintableArea(PrintSettings& print_settings); #endif + // Sets the printable area in `print_settings` to be the default printable + // area. Intended to be used only for virtual printers. Does not communicate + // with printer drivers, so it does not require special OOPPD handling. + static void ApplyDefaultPrintableAreaToVirtualPrinterPrintSettings( + PrintSettings& print_settings); + #if BUILDFLAG(ENABLE_OOP_PRINTING) // Provide the client ID when the caller has registered with the // `PrintBackendServiceManager` for getting settings for system print.
diff --git a/chrome/browser/resources/BUILD.gn b/chrome/browser/resources/BUILD.gn index 535f573..e8caebe 100644 --- a/chrome/browser/resources/BUILD.gn +++ b/chrome/browser/resources/BUILD.gn
@@ -44,6 +44,7 @@ "privacy_sandbox:resources", "profile_internals:resources", "settings:resources", + "settings_shared:resources", "side_panel/bookmarks:resources", "side_panel/companion:resources", "side_panel/customize_chrome:resources",
diff --git a/chrome/browser/resources/chromeos/set_time_dialog/BUILD.gn b/chrome/browser/resources/chromeos/set_time_dialog/BUILD.gn index da85288..eced4808 100644 --- a/chrome/browser/resources/chromeos/set_time_dialog/BUILD.gn +++ b/chrome/browser/resources/chromeos/set_time_dialog/BUILD.gn
@@ -32,6 +32,7 @@ } html_to_wrapper("html_wrapper_files") { + deps = [ "//ui/webui/resources/cr_components/color_change_listener:build_ts" ] in_files = [ "set_time_dialog.html" ] use_js = true }
diff --git a/chrome/browser/resources/chromeos/set_time_dialog/set_time.html b/chrome/browser/resources/chromeos/set_time_dialog/set_time.html index 0f42e8d..a300b8f 100644 --- a/chrome/browser/resources/chromeos/set_time_dialog/set_time.html +++ b/chrome/browser/resources/chromeos/set_time_dialog/set_time.html
@@ -8,6 +8,6 @@ </head> <body> <set-time-dialog></set-time-dialog> - <script type="module" src="set_time_dialog.js"></script> + <script type="module" src="set_time.js"></script> </body> </html>
diff --git a/chrome/browser/resources/chromeos/set_time_dialog/set_time.js b/chrome/browser/resources/chromeos/set_time_dialog/set_time.js new file mode 100644 index 0000000..0500f14 --- /dev/null +++ b/chrome/browser/resources/chromeos/set_time_dialog/set_time.js
@@ -0,0 +1,31 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview + * Main entry point for the set time dialog + */ + +import './strings.m.js'; +import './set_time_dialog.js'; + +import {loadTimeData} from 'chrome://resources/ash/common/load_time_data.m.js'; +import {startColorChangeUpdater} from 'chrome://resources/cr_components/color_change_listener/colors_css_updater.js'; + +// TODO(b/257329722) After the Jelly experiment is launched, add the CSS link +// element directly to the HTML. +const jellyEnabled = loadTimeData.getBoolean('isJellyEnabled'); +if (jellyEnabled) { + const link = document.createElement('link'); + link.rel = 'stylesheet'; + link.href = 'chrome://theme/colors.css?sets=legacy,sys'; + document.head.appendChild(link); + document.body.classList.add('jelly-enabled'); +} + +window.onload = () => { + if (jellyEnabled) { + startColorChangeUpdater(); + } +};
diff --git a/chrome/browser/resources/chromeos/set_time_dialog/set_time_dialog.html b/chrome/browser/resources/chromeos/set_time_dialog/set_time_dialog.html index 8b2a7c3..91288538 100644 --- a/chrome/browser/resources/chromeos/set_time_dialog/set_time_dialog.html +++ b/chrome/browser/resources/chromeos/set_time_dialog/set_time_dialog.html
@@ -1,4 +1,4 @@ - <style include="cr-page-host-style cr-shared-style md-select"> + <style include="cr-page-host-style cr-shared-style md-select cros-color-overrides"> :host { user-select: none; } @@ -9,11 +9,6 @@ width: 100%; } - cr-dialog [slot=title] { - /* The native dialog caption area has enough visual whitespace. */ - padding-top: 0; - } - cr-dialog [slot=button-container] { /* Align right edge of "Done" button with right edge of time input. */ padding-inline-end: 20px; @@ -121,4 +116,3 @@ </cr-button> </div> </cr-dialog> - </template>
diff --git a/chrome/browser/resources/chromeos/set_time_dialog/set_time_dialog.js b/chrome/browser/resources/chromeos/set_time_dialog/set_time_dialog.js index 31a77039..28801b1 100644 --- a/chrome/browser/resources/chromeos/set_time_dialog/set_time_dialog.js +++ b/chrome/browser/resources/chromeos/set_time_dialog/set_time_dialog.js
@@ -12,12 +12,12 @@ * when the user changes the time or timezone. */ +import 'chrome://resources/cr_elements/chromeos/cros_color_overrides.css.js'; import 'chrome://resources/cr_elements/cr_button/cr_button.js'; import 'chrome://resources/cr_elements/cr_dialog/cr_dialog.js'; import 'chrome://resources/cr_elements/cr_page_host_style.css.js'; import 'chrome://resources/cr_elements/md_select.css.js'; import 'chrome://resources/cr_elements/cr_shared_style.css.js'; -import './strings.m.js'; import {assert} from 'chrome://resources/ash/common/assert.js'; import {loadTimeData} from 'chrome://resources/ash/common/load_time_data.m.js';
diff --git a/chrome/browser/resources/settings/BUILD.gn b/chrome/browser/resources/settings/BUILD.gn index 69c8e93e..8e6fd1b 100644 --- a/chrome/browser/resources/settings/BUILD.gn +++ b/chrome/browser/resources/settings/BUILD.gn
@@ -302,7 +302,6 @@ "hats_browser_proxy.ts", "i18n_setup.ts", "lazy_load.ts", - "lifetime_browser_proxy.ts", "metrics_browser_proxy.ts", "on_startup_page/on_startup_browser_proxy.ts", "on_startup_page/startup_urls_page_browser_proxy.ts", @@ -408,6 +407,7 @@ } ts_deps = [ + "//chrome/browser/resources/settings_shared:build_ts", "//third_party/polymer/v3_0:library", "//ui/webui/resources/cr_components/help_bubble:build_ts", "//ui/webui/resources/cr_components/localized_link:build_ts", @@ -430,6 +430,11 @@ [ "//ui/webui/resources/cr_components/certificate_manager:build_ts" ] } + ts_path_mappings = + [ "/shared/settings/*|" + rebase_path( + "$root_gen_dir/chrome/browser/resources/settings_shared/tsc/*", + target_gen_dir) ] + if (is_chromeos_ash) { # TODO(crbug.com/1013466): Browser Settings should not depend on ash/webui/ # code. The codepath needing this (in people_page.ts) should be removed when @@ -452,6 +457,10 @@ ] optimize_webui_excludes = [ "chrome://resources/mojo/skia/public/mojom/skcolor.mojom-webui.js" ] + optimize_webui_external_paths = + [ "/shared/settings|" + rebase_path( + "$root_gen_dir/chrome/browser/resources/settings_shared/tsc", + root_build_dir) ] } enable_source_maps = enable_webui_inline_sourcemaps
diff --git a/chrome/browser/resources/settings/chromeos/BUILD.gn b/chrome/browser/resources/settings/chromeos/BUILD.gn index 2c0d41b..66a536c 100644 --- a/chrome/browser/resources/settings/chromeos/BUILD.gn +++ b/chrome/browser/resources/settings/chromeos/BUILD.gn
@@ -59,8 +59,12 @@ "chrome://resources/mojo/services/network/public/mojom/ip_address.mojom-webui.js", "chrome://resources/mojo/skia/public/mojom/skcolor.mojom-webui.js", ] - external_paths = - [ "/shared/|" + rebase_path(nearby_share_tsc_dir, root_build_dir) ] + external_paths = [ + "/shared/settings|" + rebase_path( + "$root_gen_dir/chrome/browser/resources/settings_shared/tsc", + root_build_dir), + "/shared/|" + rebase_path(nearby_share_tsc_dir, root_build_dir), + ] } } @@ -70,6 +74,7 @@ deps = [ "//ash/webui/common/resources:build_ts", "//chrome/browser/resources/nearby_share/shared:build_ts", + "//chrome/browser/resources/settings_shared:build_ts", "//third_party/polymer/v3_0:library", "//ui/webui/resources/cr_components/app_management:build_ts", "//ui/webui/resources/cr_components/color_change_listener:build_ts", @@ -88,6 +93,10 @@ "//ash/webui/common/resources:generate_definitions", ] path_mappings = [ + "/shared/settings/*|" + rebase_path( + "$root_gen_dir/chrome/browser/resources/settings_shared/tsc/*", + target_gen_dir), + # Additional path mappings for Nearby share code "/shared/*|" + rebase_path("$nearby_share_tsc_dir/*", target_gen_dir), ]
diff --git a/chrome/browser/resources/settings/chromeos/lazy_load.ts b/chrome/browser/resources/settings/chromeos/lazy_load.ts index eff04013..ba647f7 100644 --- a/chrome/browser/resources/settings/chromeos/lazy_load.ts +++ b/chrome/browser/resources/settings/chromeos/lazy_load.ts
@@ -99,10 +99,10 @@ import '../privacy_page/secure_dns.js'; import '../privacy_page/secure_dns_input.js'; +export {LifetimeBrowserProxyImpl} from '/shared/settings/lifetime_browser_proxy.js'; export {AddSmbShareDialogElement} from 'chrome://resources/ash/common/smb_shares/add_smb_share_dialog.js'; export {SmbBrowserProxy, SmbBrowserProxyImpl, SmbMountResult} from 'chrome://resources/ash/common/smb_shares/smb_browser_proxy.js'; export {SettingsRadioGroupElement} from '../controls/settings_radio_group.js'; -export {LifetimeBrowserProxyImpl} from '../lifetime_browser_proxy.js'; export {CrostiniBrowserProxy, CrostiniBrowserProxyImpl} from './crostini_page/crostini_browser_proxy.js'; export {TimeZoneAutoDetectMethod} from './date_time_page/date_time_types.js'; export {TimeZoneBrowserProxyImpl} from './date_time_page/timezone_browser_proxy.js';
diff --git a/chrome/browser/resources/settings/chromeos/os_about_page/os_about_page.ts b/chrome/browser/resources/settings/chromeos/os_about_page/os_about_page.ts index 911a03c..4387ada 100644 --- a/chrome/browser/resources/settings/chromeos/os_about_page/os_about_page.ts +++ b/chrome/browser/resources/settings/chromeos/os_about_page/os_about_page.ts
@@ -26,6 +26,7 @@ import './eol_offer_section.js'; import './update_warning_dialog.js'; +import {LifetimeBrowserProxyImpl} from '/shared/settings/lifetime_browser_proxy.js'; import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js'; import {WebUiListenerMixin} from 'chrome://resources/cr_elements/web_ui_listener_mixin.js'; import {assert} from 'chrome://resources/js/assert_ts.js'; @@ -33,7 +34,6 @@ import {sanitizeInnerHtml} from 'chrome://resources/js/parse_html_subset.js'; import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; -import {LifetimeBrowserProxyImpl} from '../../lifetime_browser_proxy.js'; import {DeepLinkingMixin} from '../deep_linking_mixin.js'; import {MainPageMixin} from '../main_page_mixin.js'; import {recordSettingChange} from '../metrics_recorder.js';
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/change_device_language_dialog.ts b/chrome/browser/resources/settings/chromeos/os_languages_page/change_device_language_dialog.ts index 4189c075c..f4613860 100644 --- a/chrome/browser/resources/settings/chromeos/os_languages_page/change_device_language_dialog.ts +++ b/chrome/browser/resources/settings/chromeos/os_languages_page/change_device_language_dialog.ts
@@ -17,6 +17,7 @@ import './languages.js'; import '../../settings_shared.css.js'; +import {LifetimeBrowserProxyImpl} from '/shared/settings/lifetime_browser_proxy.js'; import {CrDialogElement} from 'chrome://resources/cr_elements/cr_dialog/cr_dialog.js'; import {CrScrollableMixin} from 'chrome://resources/cr_elements/cr_scrollable_mixin.js'; import {CrSearchFieldElement} from 'chrome://resources/cr_elements/cr_search_field/cr_search_field.js'; @@ -24,7 +25,6 @@ import {assert} from 'chrome://resources/js/assert_ts.js'; import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; -import {LifetimeBrowserProxyImpl} from '../../lifetime_browser_proxy.js'; import {recordSettingChange} from '../metrics_recorder.js'; import {getTemplate} from './change_device_language_dialog.html.js';
diff --git a/chrome/browser/resources/settings/chromeos/os_reset_page/os_powerwash_dialog.ts b/chrome/browser/resources/settings/chromeos/os_reset_page/os_powerwash_dialog.ts index aac5eab..8b366d1b 100644 --- a/chrome/browser/resources/settings/chromeos/os_reset_page/os_powerwash_dialog.ts +++ b/chrome/browser/resources/settings/chromeos/os_reset_page/os_powerwash_dialog.ts
@@ -15,13 +15,13 @@ import '../../settings_shared.css.js'; import './os_powerwash_dialog_esim_item.js'; +import {LifetimeBrowserProxy, LifetimeBrowserProxyImpl} from '/shared/settings/lifetime_browser_proxy.js'; import {OncMojo} from 'chrome://resources/ash/common/network/onc_mojo.js'; import {CrDialogElement} from 'chrome://resources/cr_elements/cr_dialog/cr_dialog.js'; import {ESimProfileRemote} from 'chrome://resources/mojo/chromeos/ash/services/cellular_setup/public/mojom/esim_manager.mojom-webui.js'; import {NetworkType} from 'chrome://resources/mojo/chromeos/services/network_config/public/mojom/network_types.mojom-webui.js'; import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; -import {LifetimeBrowserProxy, LifetimeBrowserProxyImpl} from '../../lifetime_browser_proxy.js'; import {recordSettingChange} from '../metrics_recorder.js'; import {routes} from '../os_settings_routes.js'; import {Router} from '../router.js';
diff --git a/chrome/browser/resources/settings/chromeos/os_settings.gni b/chrome/browser/resources/settings/chromeos/os_settings.gni index f263946b..3298380 100644 --- a/chrome/browser/resources/settings/chromeos/os_settings.gni +++ b/chrome/browser/resources/settings/chromeos/os_settings.gni
@@ -417,7 +417,6 @@ "controls/settings_boolean_control_mixin.ts", "extension_control_browser_proxy.ts", "i18n_setup.ts", - "lifetime_browser_proxy.ts", "people_page/profile_info_browser_proxy.ts", "people_page/sync_browser_proxy.ts", "privacy_page/privacy_page_browser_proxy.ts",
diff --git a/chrome/browser/resources/settings/chromeos/os_settings.ts b/chrome/browser/resources/settings/chromeos/os_settings.ts index b8095c9..68b3c268 100644 --- a/chrome/browser/resources/settings/chromeos/os_settings.ts +++ b/chrome/browser/resources/settings/chromeos/os_settings.ts
@@ -98,6 +98,7 @@ export {getContactManager, observeContactManager, setContactManagerForTesting} from '/shared/nearby_contact_manager.js'; export {getNearbyShareSettings, observeNearbyShareSettings, setNearbyShareSettingsForTesting} from '/shared/nearby_share_settings.js'; export {NearbySettings, NearbyShareSettingsMixin} from '/shared/nearby_share_settings_mixin.js'; +export {LifetimeBrowserProxyImpl} from '/shared/settings/lifetime_browser_proxy.js'; export {SettingsPrefsElement} from 'chrome://resources/cr_components/settings_prefs/prefs.js'; export {CrSettingsPrefs} from 'chrome://resources/cr_components/settings_prefs/prefs_types.js'; export {CrButtonElement} from 'chrome://resources/cr_elements/cr_button/cr_button.js'; @@ -106,7 +107,6 @@ export {SettingsDropdownMenuElement} from '../controls/settings_dropdown_menu.js'; export {SettingsSliderElement} from '../controls/settings_slider.js'; export {SettingsToggleButtonElement} from '../controls/settings_toggle_button.js'; -export {LifetimeBrowserProxyImpl} from '../lifetime_browser_proxy.js'; export {ProfileInfoBrowserProxyImpl} from '../people_page/profile_info_browser_proxy.js'; export {PageStatus, StatusAction, StoredAccount, SyncBrowserProxy, SyncBrowserProxyImpl, SyncPrefs, SyncStatus} from '../people_page/sync_browser_proxy.js'; export {PrivacyPageBrowserProxyImpl, SecureDnsMode, SecureDnsUiManagementMode} from '../privacy_page/privacy_page_browser_proxy.js';
diff --git a/chrome/browser/resources/settings/relaunch_confirmation_dialog.ts b/chrome/browser/resources/settings/relaunch_confirmation_dialog.ts index f38b2aa1..ac7ce9c 100644 --- a/chrome/browser/resources/settings/relaunch_confirmation_dialog.ts +++ b/chrome/browser/resources/settings/relaunch_confirmation_dialog.ts
@@ -5,12 +5,12 @@ import 'chrome://resources/cr_elements/cr_button/cr_button.js'; import 'chrome://resources/cr_elements/cr_dialog/cr_dialog.js'; +import {LifetimeBrowserProxyImpl} from '/shared/settings/lifetime_browser_proxy.js'; import {CrButtonElement} from 'chrome://resources/cr_elements/cr_button/cr_button.js'; import {CrDialogElement} from 'chrome://resources/cr_elements/cr_dialog/cr_dialog.js'; import {assertNotReached} from 'chrome://resources/js/assert_ts.js'; import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; -import {LifetimeBrowserProxyImpl} from './lifetime_browser_proxy.js'; import {getTemplate} from './relaunch_confirmation_dialog.html.js'; import {RestartType} from './relaunch_mixin.js';
diff --git a/chrome/browser/resources/settings/relaunch_mixin.ts b/chrome/browser/resources/settings/relaunch_mixin.ts index 079c75c..1808bb3 100644 --- a/chrome/browser/resources/settings/relaunch_mixin.ts +++ b/chrome/browser/resources/settings/relaunch_mixin.ts
@@ -5,7 +5,7 @@ // clang-format off import {assertNotReached} from 'chrome://resources/js/assert_ts.js'; import {dedupingMixin, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; -import {LifetimeBrowserProxy, LifetimeBrowserProxyImpl} from './lifetime_browser_proxy.js'; +import {LifetimeBrowserProxy, LifetimeBrowserProxyImpl} from '/shared/settings/lifetime_browser_proxy.js'; // clang-format on export enum RestartType {
diff --git a/chrome/browser/resources/settings/settings.ts b/chrome/browser/resources/settings/settings.ts index 3d8bd88f..a2d70ab1 100644 --- a/chrome/browser/resources/settings/settings.ts +++ b/chrome/browser/resources/settings/settings.ts
@@ -4,6 +4,7 @@ import './settings_ui/settings_ui.js'; +export {LifetimeBrowserProxy, LifetimeBrowserProxyImpl} from '/shared/settings/lifetime_browser_proxy.js'; export {prefToString, stringToPrefValue} from 'chrome://resources/cr_components/settings_prefs/pref_util.js'; export {SettingsPrefsElement} from 'chrome://resources/cr_components/settings_prefs/prefs.js'; export {PrefsMixin, PrefsMixinInterface} from 'chrome://resources/cr_components/settings_prefs/prefs_mixin.js'; @@ -45,7 +46,6 @@ export {ExtensionControlBrowserProxy, ExtensionControlBrowserProxyImpl} from './extension_control_browser_proxy.js'; export {HatsBrowserProxy, HatsBrowserProxyImpl, TrustSafetyInteraction} from './hats_browser_proxy.js'; export {loadTimeData} from './i18n_setup.js'; -export {LifetimeBrowserProxy, LifetimeBrowserProxyImpl} from './lifetime_browser_proxy.js'; export {MetricsBrowserProxy, MetricsBrowserProxyImpl, PrivacyElementInteractions, PrivacyGuideInteractions, PrivacyGuideSettingsStates, PrivacyGuideStepsEligibleAndReached, SafeBrowsingInteractions, SafetyCheckInteractions, SafetyCheckNotificationsModuleInteractions, SafetyCheckUnusedSitePermissionsModuleInteractions} from './metrics_browser_proxy.js'; export {NtpExtension, OnStartupBrowserProxy, OnStartupBrowserProxyImpl} from './on_startup_page/on_startup_browser_proxy.js'; export {SettingsOnStartupPageElement} from './on_startup_page/on_startup_page.js';
diff --git a/chrome/browser/resources/settings_shared/BUILD.gn b/chrome/browser/resources/settings_shared/BUILD.gn new file mode 100644 index 0000000..c828b177 --- /dev/null +++ b/chrome/browser/resources/settings_shared/BUILD.gn
@@ -0,0 +1,18 @@ +# Copyright 2023 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//ui/webui/resources/tools/build_webui.gni") + +assert(!is_android) + +build_webui("build") { + grd_prefix = "settings_shared" + grd_resource_path_prefix = "shared/settings" + + non_web_component_files = [ "lifetime_browser_proxy.ts" ] + + ts_composite = true + ts_definitions = [ "//tools/typescript/definitions/chrome_send.d.ts" ] + ts_deps = [ "//ui/webui/resources/js:build_ts" ] +}
diff --git a/chrome/browser/resources/settings_shared/OWNERS b/chrome/browser/resources/settings_shared/OWNERS new file mode 100644 index 0000000..443a569 --- /dev/null +++ b/chrome/browser/resources/settings_shared/OWNERS
@@ -0,0 +1 @@ +file://chrome/browser/resources/settings/OWNERS
diff --git a/chrome/browser/resources/settings_shared/README.md b/chrome/browser/resources/settings_shared/README.md new file mode 100644 index 0000000..b3f0542 --- /dev/null +++ b/chrome/browser/resources/settings_shared/README.md
@@ -0,0 +1,37 @@ +This directory contains code that is shared between + + * Browser Settings (chrome://settings) + * CrOS Settings (chrome://os-settings) + +The pattern used here is referred to as "limited sharing" unlike the +chrome://resources approach which is "unlimited sharing". + +This approach has the following advantages over moving shared code under +chrome://resources/: + + * It allows a limited number of WebUI surfaces to use it, instead of exposing + to all WebUI surfaces (hence the "limited sharing" name). + * It also allows leveraging $i18n{} C++ string replacements, which is not + possible in cr_elements/ or cr_components/. WebUIs that use the shared code + are still responsible for registering all necessary strings. + +The "limited sharing" mechanism works as follows + + * Code to be shared is built on its own, with a dedicated + build_webui() target. + * The resulting grd file entries `kSettingsSharedResources` are included in the + build once and registered at runtime under all WebUIDataSource instances that + need to use this code. + * Shared code is exposed under /shared/settings/* URLs (same as + chrome://settings/shared/settings/ or chrome://os-settings/shared/settings/ + respectively). + * build_webui()'s `ts_path_mappings` and `optimize_webui_external_paths` + parameters are leveraged so that the respective underlying tools (TS compiler + and Rollup) can correctly resolve such paths. + +A similar approach is also followed in c/b/r/side_panel/shared. + +Note: The files in this folder are only added as standalone files to the build +when `optimize_webui=false`. In other cases the same files are already bundled +within the UIs that use them and therefore adding them as standalone files is +unnecessary.
diff --git a/chrome/browser/resources/settings/lifetime_browser_proxy.ts b/chrome/browser/resources/settings_shared/lifetime_browser_proxy.ts similarity index 100% rename from chrome/browser/resources/settings/lifetime_browser_proxy.ts rename to chrome/browser/resources/settings_shared/lifetime_browser_proxy.ts
diff --git a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/ChromeProvidedSharingOptionsProviderBase.java b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/ChromeProvidedSharingOptionsProviderBase.java index 773c6db4..871e07a 100644 --- a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/ChromeProvidedSharingOptionsProviderBase.java +++ b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/ChromeProvidedSharingOptionsProviderBase.java
@@ -252,6 +252,7 @@ return; } if (ChromeFeatureList.isEnabled(ChromeFeatureList.SHARE_SHEET_CUSTOM_ACTIONS_POLISH)) { + mOrderedFirstPartyOptions.add(createCopyLinkFirstPartyOption()); maybeAddLongScreenshotFirstPartyOption(); maybeAddPrintFirstPartyOption(); maybeAddSendTabToSelfFirstPartyOption(); @@ -260,6 +261,9 @@ maybeAddWebStyleNotesFirstPartyOption(); maybeAddScreenshotFirstPartyOption(); maybeAddLongScreenshotFirstPartyOption(); + // Always show the copy link option as some entries does not offer the change for copy + // (e.g. feed card) + mOrderedFirstPartyOptions.add(createCopyLinkFirstPartyOption()); maybeAddCopyFirstPartyOption(); maybeAddSendTabToSelfFirstPartyOption(); maybeAddQrCodeFirstPartyOption(); @@ -313,7 +317,6 @@ } protected void maybeAddCopyFirstPartyOption() { - mOrderedFirstPartyOptions.add(createCopyLinkFirstPartyOption()); mOrderedFirstPartyOptions.add(createCopyGifFirstPartyOption()); mOrderedFirstPartyOptions.add(createCopyImageFirstPartyOption()); mOrderedFirstPartyOptions.add(createCopyFirstPartyOption()); @@ -321,10 +324,16 @@ } private FirstPartyOption createCopyLinkFirstPartyOption() { - return new FirstPartyOptionBuilder( - ContentType.LINK_PAGE_VISIBLE, ContentType.LINK_PAGE_NOT_VISIBLE) - .setContentTypesToDisableFor(ContentType.LINK_AND_TEXT) - .setIcon(R.drawable.ic_content_copy_black, R.string.sharing_copy_url) + FirstPartyOptionBuilder builder = new FirstPartyOptionBuilder( + ContentType.LINK_PAGE_VISIBLE, ContentType.LINK_PAGE_NOT_VISIBLE); + if (ChromeFeatureList.isEnabled(ChromeFeatureList.SHARE_SHEET_CUSTOM_ACTIONS_POLISH)) { + builder.setContentTypesToDisableFor( + ContentType.LINK_AND_TEXT, ContentType.IMAGE_AND_LINK); + } else { + builder.setContentTypesToDisableFor(ContentType.LINK_AND_TEXT); + } + + return builder.setIcon(R.drawable.ic_content_copy_black, R.string.sharing_copy_url) .setFeatureNameForMetrics(USER_ACTION_COPY_URL_SELECTED) .setOnClickCallback((view) -> { ClipboardManager clipboard = (ClipboardManager) mActivity.getSystemService(
diff --git a/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/android_share_sheet/AndroidShareSheetControllerUnitTest.java b/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/android_share_sheet/AndroidShareSheetControllerUnitTest.java index 5541627..07d4f43 100644 --- a/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/android_share_sheet/AndroidShareSheetControllerUnitTest.java +++ b/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/android_share_sheet/AndroidShareSheetControllerUnitTest.java
@@ -212,7 +212,7 @@ Assert.assertNotNull("Custom action is empty.", intent.getParcelableArrayExtra(INTENT_EXTRA_CHOOSER_CUSTOM_ACTIONS)); - assertCustomActions(intent, R.string.sharing_long_screenshot, + assertCustomActions(intent, R.string.sharing_copy_url, R.string.sharing_long_screenshot, R.string.print_share_activity_title, R.string.send_tab_to_self_share_activity_title, R.string.qr_code_share_icon_label); }
diff --git a/chrome/browser/ssl/ssl_config_service_manager.cc b/chrome/browser/ssl/ssl_config_service_manager.cc index 8d3bf77..682a006 100644 --- a/chrome/browser/ssl/ssl_config_service_manager.cc +++ b/chrome/browser/ssl/ssl_config_service_manager.cc
@@ -249,13 +249,11 @@ config->ech_enabled = ech_enabled_.GetValue(); if (insecure_hash_enabled_.IsManaged()) { - config->insecure_hash_enabled = - insecure_hash_enabled_.GetValue() - ? network::mojom::insecure_hash_enabled_value::kEnabled - : network::mojom::insecure_hash_enabled_value::kDisabled; + config->insecure_hash_override = insecure_hash_enabled_.GetValue() + ? network::mojom::OptionalBool::kTrue + : network::mojom::OptionalBool::kFalse; } else { - config->insecure_hash_enabled = - network::mojom::insecure_hash_enabled_value::kUnset; + config->insecure_hash_override = network::mojom::OptionalBool::kUnset; } return config;
diff --git a/chrome/browser/ui/android/omnibox/BUILD.gn b/chrome/browser/ui/android/omnibox/BUILD.gn index 88f32e2..8734bd3d 100644 --- a/chrome/browser/ui/android/omnibox/BUILD.gn +++ b/chrome/browser/ui/android/omnibox/BUILD.gn
@@ -75,6 +75,7 @@ "java/src/org/chromium/chrome/browser/omnibox/suggestions/OmniboxSuggestionsDropdownAdapter.java", "java/src/org/chromium/chrome/browser/omnibox/suggestions/OmniboxSuggestionsDropdownEmbedder.java", "java/src/org/chromium/chrome/browser/omnibox/suggestions/OmniboxSuggestionsDropdownScrollListener.java", + "java/src/org/chromium/chrome/browser/omnibox/suggestions/PreWarmingRecycledViewPool.java", "java/src/org/chromium/chrome/browser/omnibox/suggestions/SuggestionCommonProperties.java", "java/src/org/chromium/chrome/browser/omnibox/suggestions/SuggestionHost.java", "java/src/org/chromium/chrome/browser/omnibox/suggestions/SuggestionListProperties.java", @@ -415,6 +416,7 @@ "java/src/org/chromium/chrome/browser/omnibox/suggestions/DropdownItemViewInfoListManagerUnitTest.java", "java/src/org/chromium/chrome/browser/omnibox/suggestions/FaviconFetcherUnitTest.java", "java/src/org/chromium/chrome/browser/omnibox/suggestions/OmniboxSuggestionsDropdownUnitTest.java", + "java/src/org/chromium/chrome/browser/omnibox/suggestions/PreWarmingRecycledViewPoolTest.java", "java/src/org/chromium/chrome/browser/omnibox/suggestions/answer/AnswerSuggestionProcessorUnitTest.java", "java/src/org/chromium/chrome/browser/omnibox/suggestions/answer/AnswerTextNewLayoutUnitTest.java", "java/src/org/chromium/chrome/browser/omnibox/suggestions/base/ActionChipsAdapterUnitTest.java",
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/OmniboxFeatures.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/OmniboxFeatures.java index 9e5cdb0..83cab4b 100644 --- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/OmniboxFeatures.java +++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/OmniboxFeatures.java
@@ -38,6 +38,7 @@ private static final MutableFlagWithSafeDefault sJourneysRowUiFlag = new MutableFlagWithSafeDefault( ChromeFeatureList.OMNIBOX_HISTORY_CLUSTER_PROVIDER, false); + private static final MutableFlagWithSafeDefault sCacheSuggestionResources = new MutableFlagWithSafeDefault( ChromeFeatureList.OMNIBOX_CACHE_SUGGESTION_RESOURCES, false); @@ -48,6 +49,10 @@ .OMNIBOX_ADAPTIVE_SUGGESTIONS_VISIBLE_GROUP_ELIGIBILITY_UPDATE, false); + private static final MutableFlagWithSafeDefault sWarmRecycledViewPoolFlag = + new MutableFlagWithSafeDefault( + ChromeFeatureList.OMNIBOX_WARM_RECYCLED_VIEW_POOL, false); + /** * @param context The activity context. * @return Whether the new modernize visual UI update should be shown. @@ -135,4 +140,11 @@ public static boolean adaptiveSuggestionsVisibleGroupEligibilityUpdate() { return sOmniboxAdaptiveSuggestionsVisibleGroupEligibilityUpdate.isEnabled(); } + + /** + * Returns whether the omnibox's recycler view pool should be pre-warmed prior to initial use. + */ + public static boolean shouldPreWarmRecyclerViewPool() { + return sWarmRecycledViewPoolFlag.isEnabled(); + } }
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteCoordinator.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteCoordinator.java index f0e7dbdb..03ba77a 100644 --- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteCoordinator.java +++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteCoordinator.java
@@ -20,6 +20,7 @@ import org.chromium.base.ObserverList; import org.chromium.base.StrictModeContext; import org.chromium.base.supplier.ObservableSupplier; +import org.chromium.base.supplier.OneshotSupplierImpl; import org.chromium.base.supplier.Supplier; import org.chromium.chrome.browser.omnibox.LocationBarDataProvider; import org.chromium.chrome.browser.omnibox.R; @@ -75,6 +76,12 @@ private @Nullable OmniboxSuggestionsDropdown mDropdown; private @NonNull ObserverList<OmniboxSuggestionsDropdownScrollListener> mScrollListenerList = new ObserverList<>(); + private OmniboxSuggestionsDropdownAdapter mAdapter; + private Context mContext; + private boolean mUrlHasFocus; + private OneshotSupplierImpl<OmniboxSuggestionsDropdownAdapter> mAdapterSupplier = + new OneshotSupplierImpl<>(); + private PreWarmingRecycledViewPool mRecycledViewPool; public AutocompleteCoordinator(@NonNull ViewGroup parent, @NonNull AutocompleteControllerProvider controllerProvider, @@ -94,6 +101,7 @@ mParent = parent; mModalDialogManagerSupplier = modalDialogManagerSupplier; Context context = parent.getContext(); + mContext = context; PropertyModel listModel = new PropertyModel(SuggestionListProperties.ALL_KEYS); ModelList listItems = new ModelList(); @@ -128,6 +136,9 @@ mProfileChangeCallback = this::setAutocompleteProfile; mProfileSupplier.addObserver(mProfileChangeCallback); + mAdapter = createAdapter(listItems); + mRecycledViewPool = new PreWarmingRecycledViewPool(mAdapter, context, new Handler()); + // https://crbug.com/966227 Set initial layout direction ahead of inflating the suggestions. updateSuggestionListLayoutDirection(); } @@ -136,6 +147,7 @@ * Clean up resources used by this class. */ public void destroy() { + mRecycledViewPool.destroy(); mProfileSupplier.removeObserver(mProfileChangeCallback); mMediator.destroy(); if (mDropdown != null) { @@ -154,75 +166,11 @@ public void inflate() { OmniboxSuggestionsDropdown dropdown; try (StrictModeContext ignored = StrictModeContext.allowDiskReads()) { - dropdown = new OmniboxSuggestionsDropdown(context); + dropdown = new OmniboxSuggestionsDropdown(context, mRecycledViewPool); } dropdown.getViewGroup().setClipToPadding(false); - - OmniboxSuggestionsDropdownAdapter adapter = - new OmniboxSuggestionsDropdownAdapter(modelList); - dropdown.setAdapter(adapter); - - // Note: clang-format does a bad job formatting lambdas so we turn it off here. - // clang-format off - // Register a view type for a default omnibox suggestion. - adapter.registerType( - OmniboxSuggestionUiType.DEFAULT, - parent -> new BaseSuggestionView<View>( - parent.getContext(), R.layout.omnibox_basic_suggestion), - new BaseSuggestionViewBinder<View>(SuggestionViewViewBinder::bind)); - - adapter.registerType( - OmniboxSuggestionUiType.EDIT_URL_SUGGESTION, - parent -> new EditUrlSuggestionView(parent.getContext()), - new EditUrlSuggestionViewBinder()); - - adapter.registerType( - OmniboxSuggestionUiType.ANSWER_SUGGESTION, - parent -> new BaseSuggestionView<View>( - parent.getContext(), R.layout.omnibox_answer_suggestion), - new BaseSuggestionViewBinder<View>(AnswerSuggestionViewBinder::bind)); - - adapter.registerType( - OmniboxSuggestionUiType.ENTITY_SUGGESTION, - parent -> new BaseSuggestionView<View>( - parent.getContext(), R.layout.omnibox_entity_suggestion), - new BaseSuggestionViewBinder<View>(EntitySuggestionViewBinder::bind)); - - adapter.registerType( - OmniboxSuggestionUiType.TAIL_SUGGESTION, - parent -> new BaseSuggestionView<TailSuggestionView>( - new TailSuggestionView(parent.getContext())), - new BaseSuggestionViewBinder<TailSuggestionView>( - TailSuggestionViewBinder::bind)); - - adapter.registerType( - OmniboxSuggestionUiType.CLIPBOARD_SUGGESTION, - parent -> new BaseSuggestionView<View>( - parent.getContext(), R.layout.omnibox_basic_suggestion), - new BaseSuggestionViewBinder<View>(SuggestionViewViewBinder::bind)); - - adapter.registerType( - OmniboxSuggestionUiType.TILE_NAVSUGGEST, - BaseCarouselSuggestionItemViewBuilder::createView, - BaseCarouselSuggestionViewBinder::bind); - - adapter.registerType( - OmniboxSuggestionUiType.HEADER, - parent -> new HeaderView(parent.getContext()), - HeaderViewBinder::bind); - - adapter.registerType( - OmniboxSuggestionUiType.PEDAL_SUGGESTION, - parent -> new BaseSuggestionView<View>( - parent.getContext(), R.layout.omnibox_basic_suggestion), - new BaseSuggestionViewBinder<View>(SuggestionViewViewBinder::bind)); - - adapter.registerType( - OmniboxSuggestionUiType.DIVIDER_LINE, - parent -> new DividerLineView(parent.getContext()), - DividerLineViewBinder::bind); - // clang-format on + dropdown.setAdapter(mAdapter); ViewGroup container = (ViewGroup) ((ViewStub) mParent.getRootView().findViewById( R.id.omnibox_results_container_stub)) @@ -246,8 +194,76 @@ }; } + private OmniboxSuggestionsDropdownAdapter createAdapter(ModelList listItems) { + OmniboxSuggestionsDropdownAdapter adapter = + new OmniboxSuggestionsDropdownAdapter(listItems); + + // Note: clang-format does a bad job formatting lambdas so we turn it off here. + // clang-format off + // Register a view type for a default omnibox suggestion. + adapter.registerType( + OmniboxSuggestionUiType.DEFAULT, + parent -> new BaseSuggestionView<View>( + parent.getContext(), R.layout.omnibox_basic_suggestion), + new BaseSuggestionViewBinder<View>(SuggestionViewViewBinder::bind)); + + adapter.registerType( + OmniboxSuggestionUiType.EDIT_URL_SUGGESTION, + parent -> new EditUrlSuggestionView(parent.getContext()), + new EditUrlSuggestionViewBinder()); + + adapter.registerType( + OmniboxSuggestionUiType.ANSWER_SUGGESTION, + parent -> new BaseSuggestionView<View>( + parent.getContext(), R.layout.omnibox_answer_suggestion), + new BaseSuggestionViewBinder<View>(AnswerSuggestionViewBinder::bind)); + + adapter.registerType( + OmniboxSuggestionUiType.ENTITY_SUGGESTION, + parent -> new BaseSuggestionView<View>( + parent.getContext(), R.layout.omnibox_entity_suggestion), + new BaseSuggestionViewBinder<View>(EntitySuggestionViewBinder::bind)); + + adapter.registerType( + OmniboxSuggestionUiType.TAIL_SUGGESTION, + parent -> new BaseSuggestionView<TailSuggestionView>( + new TailSuggestionView(parent.getContext())), + new BaseSuggestionViewBinder<TailSuggestionView>( + TailSuggestionViewBinder::bind)); + + adapter.registerType( + OmniboxSuggestionUiType.CLIPBOARD_SUGGESTION, + parent -> new BaseSuggestionView<View>( + parent.getContext(), R.layout.omnibox_basic_suggestion), + new BaseSuggestionViewBinder<View>(SuggestionViewViewBinder::bind)); + + adapter.registerType( + OmniboxSuggestionUiType.TILE_NAVSUGGEST, + BaseCarouselSuggestionItemViewBuilder::createView, + BaseCarouselSuggestionViewBinder::bind); + + adapter.registerType( + OmniboxSuggestionUiType.HEADER, + parent -> new HeaderView(parent.getContext()), + HeaderViewBinder::bind); + + adapter.registerType( + OmniboxSuggestionUiType.PEDAL_SUGGESTION, + parent -> new BaseSuggestionView<View>( + parent.getContext(), R.layout.omnibox_basic_suggestion), + new BaseSuggestionViewBinder<View>(SuggestionViewViewBinder::bind)); + + adapter.registerType( + OmniboxSuggestionUiType.DIVIDER_LINE, + parent -> new DividerLineView(parent.getContext()), + DividerLineViewBinder::bind); + // clang-format on + return adapter; + } + @Override public void onUrlFocusChange(boolean hasFocus) { + mUrlHasFocus = hasFocus; mMediator.onUrlFocusChange(hasFocus); } @@ -296,6 +312,7 @@ */ public void onNativeInitialized() { mMediator.onNativeInitialized(); + mRecycledViewPool.onNativeInitialized(); } /**
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 80a1459c..ccd17a5 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
@@ -14,7 +14,6 @@ import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; -import android.view.ViewGroup.LayoutParams; import androidx.annotation.IntDef; import androidx.annotation.NonNull; @@ -205,49 +204,16 @@ mLastKeyboardShownState = true; } } - /** - * RecyclerView pool that records performance of the view recycling mechanism. - * @see OmniboxSuggestionsListViewListAdapter#canReuseView(View, int) - */ - private class HistogramRecordingRecycledViewPool extends RecycledViewPool { - HistogramRecordingRecycledViewPool() { - // The list below should include suggestions defined in OmniboxSuggestionUiType - // and specify the maximum anticipated volume of suggestions of each type. - // For readability reasons, keep the order of this list same as the order of - // the types defined in OmniboxSuggestionUiType. - setMaxRecycledViews(OmniboxSuggestionUiType.DEFAULT, 20); - setMaxRecycledViews(OmniboxSuggestionUiType.EDIT_URL_SUGGESTION, 1); - setMaxRecycledViews(OmniboxSuggestionUiType.ANSWER_SUGGESTION, 1); - setMaxRecycledViews(OmniboxSuggestionUiType.ENTITY_SUGGESTION, 8); - setMaxRecycledViews(OmniboxSuggestionUiType.TAIL_SUGGESTION, 15); - setMaxRecycledViews(OmniboxSuggestionUiType.CLIPBOARD_SUGGESTION, 1); - setMaxRecycledViews(OmniboxSuggestionUiType.HEADER, 4); - setMaxRecycledViews(OmniboxSuggestionUiType.TILE_NAVSUGGEST, 1); - setMaxRecycledViews(OmniboxSuggestionUiType.PEDAL_SUGGESTION, 3); - setMaxRecycledViews(OmniboxSuggestionUiType.DIVIDER_LINE, 1); - } - - @Override - public ViewHolder getRecycledView(int viewType) { - ViewHolder result = super.getRecycledView(viewType); - if (result == null) { - SuggestionsMetrics.recordSuggestionsViewCreatedType(viewType); - } else { - SuggestionsMetrics.recordSuggestionsViewReusedType(viewType); - } - return result; - } - } /** * Constructs a new list designed for containing omnibox suggestions. * @param context Context used for contained views. */ - public OmniboxSuggestionsDropdown(@NonNull Context context) { + public OmniboxSuggestionsDropdown(@NonNull Context context, RecycledViewPool recycledViewPool) { super(context, null, android.R.attr.dropDownListViewStyle); setFocusable(true); setFocusableInTouchMode(true); - setRecycledViewPool(new HistogramRecordingRecycledViewPool()); + setRecycledViewPool(recycledViewPool); // By default RecyclerViews come with item animators. setItemAnimator(null); @@ -385,7 +351,9 @@ super.onDetachedFromWindow(); mEmbedder.onDetachedFromWindow(); mOmniboxAlignment = OmniboxAlignment.UNSPECIFIED; - getRecycledViewPool().clear(); + if (!OmniboxFeatures.shouldPreWarmRecyclerViewPool()) { + getRecycledViewPool().clear(); + } mAdapter.recordSessionMetrics(); mEmbedder.removeAlignmentObserver(mOmniboxAlignmentObserver); }
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/OmniboxSuggestionsDropdownAdapter.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/OmniboxSuggestionsDropdownAdapter.java index 59c8e85..5766f1a 100644 --- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/OmniboxSuggestionsDropdownAdapter.java +++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/OmniboxSuggestionsDropdownAdapter.java
@@ -110,6 +110,7 @@ } @Override + // extend this protected View createView(ViewGroup parent, int viewType) { // This skips measuring Adapter.CreateViewHolder, which is final, but it capture // the creation of a view holder.
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/OmniboxSuggestionsDropdownUnitTest.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/OmniboxSuggestionsDropdownUnitTest.java index 46b3c4e..694314b7 100644 --- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/OmniboxSuggestionsDropdownUnitTest.java +++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/OmniboxSuggestionsDropdownUnitTest.java
@@ -26,6 +26,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.recyclerview.widget.RecyclerView.LayoutParams; +import androidx.recyclerview.widget.RecyclerView.RecycledViewPool; import androidx.test.core.app.ApplicationProvider; import androidx.test.filters.SmallTest; @@ -68,6 +69,7 @@ private @Mock Runnable mDropdownScrollToTopListener; private @Mock WindowDelegate mWindowDelegate; private @Mock OmniboxSuggestionsDropdownAdapter mAdapter; + private @Mock RecycledViewPool mPool; private Context mContext; @@ -122,7 +124,7 @@ public void setUp() { mContext = new ContextThemeWrapper( ApplicationProvider.getApplicationContext(), R.style.Theme_BrowserUI_DayNight); - mDropdown = new OmniboxSuggestionsDropdown(mContext); + mDropdown = new OmniboxSuggestionsDropdown(mContext, mPool); mDropdown.setAdapter(mAdapter); mListener = mDropdown.getLayoutScrollListener(); } @@ -396,7 +398,7 @@ @SmallTest @LooperMode(Mode.PAUSED) public void testAlignmentProvider_changeDuringlayout() { - mDropdown = Mockito.spy(new OmniboxSuggestionsDropdown(mContext)); + mDropdown = Mockito.spy(new OmniboxSuggestionsDropdown(mContext, mPool)); mDropdown.setAdapter(mAdapter); mDropdown.setEmbedder(mEmbedder); mDropdown.onAttachedToWindow();
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/PreWarmingRecycledViewPool.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/PreWarmingRecycledViewPool.java new file mode 100644 index 0000000..7b292a9 --- /dev/null +++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/PreWarmingRecycledViewPool.java
@@ -0,0 +1,138 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.omnibox.suggestions; + +import android.content.Context; +import android.os.Handler; +import android.widget.FrameLayout; + +import androidx.annotation.VisibleForTesting; +import androidx.recyclerview.widget.RecyclerView.RecycledViewPool; +import androidx.recyclerview.widget.RecyclerView.ViewHolder; + +import org.chromium.base.TraceEvent; +import org.chromium.chrome.browser.omnibox.OmniboxFeatures; + +import java.util.ArrayList; +import java.util.List; + +/** + * RecyclerView pool that: + * 1. Pre-creates a hardcoded set of ViewHolders. + * 2. Records the performance of the view recycling mechanism. + */ +public class PreWarmingRecycledViewPool extends RecycledViewPool { + private static final long STEP_MILLIS = 50; + + private static class ViewTypeAndCount { + public final int viewType; + public final int count; + public ViewTypeAndCount(int viewType, int count) { + this.viewType = viewType; + assert count > 0; + this.count = count; + } + } + + private final ViewTypeAndCount[] mViewsToCreate = new ViewTypeAndCount[] { + new ViewTypeAndCount(OmniboxSuggestionUiType.EDIT_URL_SUGGESTION, 1), + new ViewTypeAndCount(OmniboxSuggestionUiType.TILE_NAVSUGGEST, 1), + new ViewTypeAndCount(OmniboxSuggestionUiType.HEADER, 1), + new ViewTypeAndCount(OmniboxSuggestionUiType.CLIPBOARD_SUGGESTION, 1), + new ViewTypeAndCount(OmniboxSuggestionUiType.DEFAULT, 15), + new ViewTypeAndCount(OmniboxSuggestionUiType.ENTITY_SUGGESTION, 3)}; + + private OmniboxSuggestionsDropdownAdapter mAdapter; + private final Handler mHandler; + private final FrameLayout mDummyParent; + private boolean mStopCreatingViews; + private final List<ViewHolder> mPrewarmedViews = new ArrayList<>(22); + + PreWarmingRecycledViewPool( + OmniboxSuggestionsDropdownAdapter adapter, Context context, Handler handler) { + mAdapter = adapter; + mHandler = handler; + mDummyParent = new FrameLayout(context); + // The list below should include suggestions defined in OmniboxSuggestionUiType + // and specify the maximum anticipated volume of suggestions of each type. + // For readability reasons, keep the order of this list same as the order of + // the types defined in OmniboxSuggestionUiType. + setMaxRecycledViews(OmniboxSuggestionUiType.DEFAULT, 20); + setMaxRecycledViews(OmniboxSuggestionUiType.EDIT_URL_SUGGESTION, 1); + setMaxRecycledViews(OmniboxSuggestionUiType.ANSWER_SUGGESTION, 1); + setMaxRecycledViews(OmniboxSuggestionUiType.ENTITY_SUGGESTION, 8); + + setMaxRecycledViews(OmniboxSuggestionUiType.TAIL_SUGGESTION, 15); + setMaxRecycledViews(OmniboxSuggestionUiType.CLIPBOARD_SUGGESTION, 1); + setMaxRecycledViews(OmniboxSuggestionUiType.HEADER, 4); + setMaxRecycledViews(OmniboxSuggestionUiType.TILE_NAVSUGGEST, 1); + setMaxRecycledViews(OmniboxSuggestionUiType.PEDAL_SUGGESTION, 3); + setMaxRecycledViews(OmniboxSuggestionUiType.DIVIDER_LINE, 1); + } + + public void destroy() { + stopCreatingViews(); + mAdapter = null; + } + + public void onNativeInitialized() { + if (OmniboxFeatures.shouldPreWarmRecyclerViewPool()) { + startCreatingViews(); + } + } + + /** + * Starts creating views. This will immediately post a separate delayed task for every view we + * intend to create with a delay equal to STEP_MILLIS * order_of_view_creation. + * */ + public void startCreatingViews() { + if (mStopCreatingViews) return; + for (var viewTypeAndCount : mViewsToCreate) { + for (int index = 0; index < viewTypeAndCount.count; ++index) { + mHandler.postDelayed(() -> { + createViewHolder(viewTypeAndCount.viewType); + }, STEP_MILLIS * (index + 1)); + } + } + } + + /** + * Stops the task posted by {@link #startCreatingViews()} from creating any more views and + * removes it from the handler. Places any pre-created views into the pool. + */ + @VisibleForTesting + void stopCreatingViews() { + if (mStopCreatingViews) return; + mStopCreatingViews = true; + mHandler.removeCallbacks(null); + putViewsIntoPool(); + } + + private void createViewHolder(@OmniboxSuggestionUiType int viewType) { + if (mAdapter == null || mStopCreatingViews) return; + try (TraceEvent t = TraceEvent.scoped("PreWarmingRecycledViewPool.createNextViewHolder")) { + mPrewarmedViews.add(mAdapter.createViewHolder(mDummyParent, viewType)); + } + } + + private void putViewsIntoPool() { + for (var viewHolder : mPrewarmedViews) { + putRecycledView(viewHolder); + } + mPrewarmedViews.clear(); + } + + @Override + public ViewHolder getRecycledView(int viewType) { + stopCreatingViews(); + ViewHolder result = super.getRecycledView(viewType); + 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/PreWarmingRecycledViewPoolTest.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/PreWarmingRecycledViewPoolTest.java new file mode 100644 index 0000000..9342914 --- /dev/null +++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/PreWarmingRecycledViewPoolTest.java
@@ -0,0 +1,138 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.omnibox.suggestions; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertNotNull; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; + +import android.content.Context; +import android.os.Handler; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView.ViewHolder; +import androidx.test.core.app.ApplicationProvider; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TestRule; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +import org.chromium.base.test.BaseRobolectricTestRunner; +import org.chromium.chrome.browser.flags.ChromeFeatureList; +import org.chromium.chrome.test.util.browser.Features; +import org.chromium.chrome.test.util.browser.Features.DisableFeatures; +import org.chromium.chrome.test.util.browser.Features.EnableFeatures; +import org.chromium.ui.modelutil.MVCListAdapter.ModelList; + +import java.util.Arrays; + +/** + * Unit tests for {@link PreWarmingRecycledViewPool}. + */ +@RunWith(BaseRobolectricTestRunner.class) +public class PreWarmingRecycledViewPoolTest { + public @Rule TestRule mProcessor = new Features.JUnitProcessor(); + public @Rule MockitoRule mMockitoRule = MockitoJUnit.rule(); + + @Mock + private Handler mHandler; + @Mock + private View mView; + + private Context mContext; + private OmniboxSuggestionsDropdownAdapter mAdapter; + private PreWarmingRecycledViewPool mPool; + + @Before + public void setUp() { + mContext = ApplicationProvider.getApplicationContext(); + mAdapter = Mockito.spy(new OmniboxSuggestionsDropdownAdapter(new ModelList()) { + @Override + protected View createView(ViewGroup parent, int viewType) { + return mView; + } + + @Override + @NonNull + public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + return new ViewHolder(mView, null); + } + }); + mPool = new PreWarmingRecycledViewPool(mAdapter, mContext, mHandler); + } + + @EnableFeatures({ChromeFeatureList.OMNIBOX_WARM_RECYCLED_VIEW_POOL}) + @Test + public void testCreateViews() { + doAnswer((invocation -> { + ((Runnable) invocation.getArgument(0)).run(); + return null; + })) + .when(mHandler) + .postDelayed(any(Runnable.class), anyLong()); + mPool.onNativeInitialized(); + mPool.stopCreatingViews(); + + assertEquals(1, mPool.getRecycledViewCount(OmniboxSuggestionUiType.EDIT_URL_SUGGESTION)); + assertEquals(1, mPool.getRecycledViewCount(OmniboxSuggestionUiType.TILE_NAVSUGGEST)); + assertEquals(1, mPool.getRecycledViewCount(OmniboxSuggestionUiType.HEADER)); + assertEquals(1, mPool.getRecycledViewCount(OmniboxSuggestionUiType.CLIPBOARD_SUGGESTION)); + assertEquals(15, mPool.getRecycledViewCount(OmniboxSuggestionUiType.DEFAULT)); + assertEquals(3, mPool.getRecycledViewCount(OmniboxSuggestionUiType.ENTITY_SUGGESTION)); + + View expectedView = mView; + // null out mView so that newly-created ViewHolders will be distinct from pre-warmed ones. + mView = null; + for (var uiType : Arrays.asList(OmniboxSuggestionUiType.EDIT_URL_SUGGESTION, + OmniboxSuggestionUiType.TILE_NAVSUGGEST, OmniboxSuggestionUiType.HEADER, + OmniboxSuggestionUiType.CLIPBOARD_SUGGESTION, OmniboxSuggestionUiType.DEFAULT, + OmniboxSuggestionUiType.ENTITY_SUGGESTION)) { + ViewHolder viewHolder = mPool.getRecycledView(uiType); + assertNotNull(viewHolder); + assertEquals(expectedView, viewHolder.itemView); + } + } + + @DisableFeatures({ChromeFeatureList.OMNIBOX_WARM_RECYCLED_VIEW_POOL}) + @Test + public void testCreateViews_featureDisabled() { + doAnswer((invocation -> { + ((Runnable) invocation.getArgument(0)).run(); + return null; + })) + .when(mHandler) + .postDelayed(any(Runnable.class), anyLong()); + mPool.onNativeInitialized(); + + verifyNoMoreInteractions(mAdapter); + verifyNoMoreInteractions(mHandler); + } + + @EnableFeatures({ChromeFeatureList.OMNIBOX_WARM_RECYCLED_VIEW_POOL}) + @Test + public void testStopCreating() { + mPool.onNativeInitialized(); + verify(mHandler, times(22)).postDelayed(any(Runnable.class), anyLong()); + mPool.getRecycledView(OmniboxSuggestionUiType.DEFAULT); + verify(mHandler).removeCallbacks(null); + + mPool.getRecycledView(OmniboxSuggestionUiType.DEFAULT); + verify(mHandler, times(1)).removeCallbacks(null); + } +}
diff --git a/chrome/browser/ui/ash/projector/projector_navigation_throttle_browsertest.cc b/chrome/browser/ui/ash/projector/projector_navigation_throttle_browsertest.cc index 2f95b65..e4e6892 100644 --- a/chrome/browser/ui/ash/projector/projector_navigation_throttle_browsertest.cc +++ b/chrome/browser/ui/ash/projector/projector_navigation_throttle_browsertest.cc
@@ -400,11 +400,7 @@ // Verify the document language. We must use the deprecated // ExecuteScriptAndExtract*() instead of EvalJs() due to CSP. - std::string lang; - ASSERT_TRUE(content::ExecuteScriptAndExtractString( - tab, "domAutomationController.send(document.documentElement.lang)", - &lang)); - EXPECT_EQ(lang, locale()); + EXPECT_EQ(content::EvalJs(tab, "document.documentElement.lang"), locale()); } INSTANTIATE_TEST_SUITE_P(,
diff --git a/chrome/browser/ui/autofill/payments/card_unmask_authentication_selection_dialog_controller_impl.cc b/chrome/browser/ui/autofill/payments/card_unmask_authentication_selection_dialog_controller_impl.cc index 273cbd5..538a00a 100644 --- a/chrome/browser/ui/autofill/payments/card_unmask_authentication_selection_dialog_controller_impl.cc +++ b/chrome/browser/ui/autofill/payments/card_unmask_authentication_selection_dialog_controller_impl.cc
@@ -95,14 +95,16 @@ if (cancel_unmasking_closure_) std::move(cancel_unmasking_closure_).Run(); } else if (selected_challenge_option_type_ == - CardUnmaskChallengeOptionType::kSmsOtp) { - // If we have an SMS OTP challenge selected and `user_closed_dialog` is - // false, that means that the user accepted the dialog after selecting the - // SMS OTP challenge option, and we have a server response returned since we + CardUnmaskChallengeOptionType::kSmsOtp || + selected_challenge_option_type_ == + CardUnmaskChallengeOptionType::kEmailOtp) { + // If we have an OTP challenge selected and `user_closed_dialog` is false, + // that means that the user accepted the dialog after selecting the OTP + // challenge option, and we have a server response returned since we // immediately send a SelectChallengeOption request to the server and only // close the dialog once a response is returned. The SelectChallengeOption - // request is sent to the payments server to generate an SMS OTP with the - // bank or issuer and send it to the user. + // request is sent to the payments server to generate an OTP with the bank + // or issuer and send it to the user. AutofillMetrics::LogCardUnmaskAuthenticationSelectionDialogResultMetric( server_success ? AutofillMetrics:: @@ -166,10 +168,10 @@ /*server_success=*/false); break; case CardUnmaskChallengeOptionType::kSmsOtp: + case CardUnmaskChallengeOptionType::kEmailOtp: // Show the OTP pending dialog. dialog_view_->UpdateContent(); break; - case CardUnmaskChallengeOptionType::kEmailOtp: case CardUnmaskChallengeOptionType::kUnknownType: NOTREACHED(); break; @@ -204,8 +206,9 @@ switch (challenge_option.type) { case CardUnmaskChallengeOptionType::kSmsOtp: return ui::ImageModel::FromVectorIcon(vector_icons::kSmsIcon); - case CardUnmaskChallengeOptionType::kCvc: case CardUnmaskChallengeOptionType::kEmailOtp: + return ui::ImageModel::FromVectorIcon(vector_icons::kEmailIcon); + case CardUnmaskChallengeOptionType::kCvc: case CardUnmaskChallengeOptionType::kUnknownType: NOTREACHED(); return ui::ImageModel(); @@ -225,6 +228,8 @@ return l10n_util::GetStringUTF16( IDS_AUTOFILL_AUTHENTICATION_MODE_SECURITY_CODE); case CardUnmaskChallengeOptionType::kEmailOtp: + return l10n_util::GetStringUTF16( + IDS_AUTOFILL_AUTHENTICATION_MODE_GET_EMAIL); case CardUnmaskChallengeOptionType::kUnknownType: NOTREACHED(); return std::u16string(); @@ -249,12 +254,12 @@ switch (selected_challenge_option->type) { case CardUnmaskChallengeOptionType::kSmsOtp: + case CardUnmaskChallengeOptionType::kEmailOtp: return l10n_util::GetStringUTF16( IDS_AUTOFILL_CARD_UNMASK_AUTHENTICATION_SELECTION_DIALOG_OK_BUTTON_LABEL_SEND); case CardUnmaskChallengeOptionType::kCvc: return l10n_util::GetStringUTF16( IDS_AUTOFILL_CARD_UNMASK_AUTHENTICATION_SELECTION_DIALOG_OK_BUTTON_LABEL_CONTINUE); - case CardUnmaskChallengeOptionType::kEmailOtp: case CardUnmaskChallengeOptionType::kUnknownType: NOTREACHED(); return std::u16string();
diff --git a/chrome/browser/ui/autofill/payments/card_unmask_authentication_selection_dialog_controller_impl_unittest.cc b/chrome/browser/ui/autofill/payments/card_unmask_authentication_selection_dialog_controller_impl_unittest.cc index cdabeb54..7eb2ba1 100644 --- a/chrome/browser/ui/autofill/payments/card_unmask_authentication_selection_dialog_controller_impl_unittest.cc +++ b/chrome/browser/ui/autofill/payments/card_unmask_authentication_selection_dialog_controller_impl_unittest.cc
@@ -64,19 +64,26 @@ controller()->SetSelectedChallengeOptionsForTesting( test::GetCardUnmaskChallengeOptions( {CardUnmaskChallengeOptionType::kSmsOtp, + CardUnmaskChallengeOptionType::kEmailOtp, CardUnmaskChallengeOptionType::kCvc})); - controller()->SetSelectedChallengeOptionId( - CardUnmaskChallengeOption::ChallengeOptionId( - controller()->GetChallengeOptions()[0].id.value())); - EXPECT_EQ(controller()->GetChallengeOptions()[0].id.value(), - controller()->GetSelectedChallengeOptionIdForTesting().value()); - controller()->OnDialogClosed(/*user_closed_dialog=*/true, - /*server_success=*/false); - histogram_tester.ExpectUniqueSample( - "Autofill.CardUnmaskAuthenticationSelectionDialog.Result", - AutofillMetrics::CardUnmaskAuthenticationSelectionDialogResultMetric:: - kCanceledByUserBeforeSelection, - 1); + int count = 0; + for (CardUnmaskChallengeOption challenge_option : + controller()->GetChallengeOptions()) { + SCOPED_TRACE(testing::Message() << " count=" << count); + controller()->SetSelectedChallengeOptionId( + CardUnmaskChallengeOption::ChallengeOptionId( + challenge_option.id.value())); + EXPECT_EQ(challenge_option.id.value(), + controller()->GetSelectedChallengeOptionIdForTesting().value()); + controller()->OnDialogClosed(/*user_closed_dialog=*/true, + /*server_success=*/false); + count++; + histogram_tester.ExpectUniqueSample( + "Autofill.CardUnmaskAuthenticationSelectionDialog.Result", + AutofillMetrics::CardUnmaskAuthenticationSelectionDialogResultMetric:: + kCanceledByUserBeforeSelection, + count); + } } TEST_F(CardUnmaskAuthenticationSelectionDialogControllerImplTest, @@ -86,45 +93,58 @@ controller()->SetSelectedChallengeOptionsForTesting( test::GetCardUnmaskChallengeOptions( {CardUnmaskChallengeOptionType::kSmsOtp, + CardUnmaskChallengeOptionType::kEmailOtp, CardUnmaskChallengeOptionType::kCvc})); - controller()->SetSelectedChallengeOptionId( - CardUnmaskChallengeOption::ChallengeOptionId( - controller()->GetChallengeOptions()[0].id.value())); - EXPECT_EQ(controller()->GetChallengeOptions()[0].id.value(), - controller()->GetSelectedChallengeOptionIdForTesting().value()); + int count = 0; + for (CardUnmaskChallengeOption challenge_option : + controller()->GetChallengeOptions()) { + SCOPED_TRACE(testing::Message() << " count=" << count); + controller()->SetSelectedChallengeOptionId( + CardUnmaskChallengeOption::ChallengeOptionId( + challenge_option.id.value())); + EXPECT_EQ(challenge_option.id.value(), + controller()->GetSelectedChallengeOptionIdForTesting().value()); - controller()->OnOkButtonClicked(); - controller()->OnDialogClosed(/*user_closed_dialog=*/true, - /*server_success=*/false); - histogram_tester.ExpectUniqueSample( - "Autofill.CardUnmaskAuthenticationSelectionDialog.Result", - AutofillMetrics::CardUnmaskAuthenticationSelectionDialogResultMetric:: - kCanceledByUserAfterSelection, - 1); + controller()->OnOkButtonClicked(); + controller()->OnDialogClosed(/*user_closed_dialog=*/true, + /*server_success=*/false); + count++; + histogram_tester.ExpectUniqueSample( + "Autofill.CardUnmaskAuthenticationSelectionDialog.Result", + AutofillMetrics::CardUnmaskAuthenticationSelectionDialogResultMetric:: + kCanceledByUserAfterSelection, + count); + } } TEST_F(CardUnmaskAuthenticationSelectionDialogControllerImplTest, ServerRequestSucceeded) { base::HistogramTester histogram_tester; + int count = 0; + for (CardUnmaskChallengeOption challenge_option : + controller()->GetChallengeOptions()) { + SCOPED_TRACE(testing::Message() << " count=" << count); + controller()->SetSelectedChallengeOptionsForTesting( + test::GetCardUnmaskChallengeOptions( + {CardUnmaskChallengeOptionType::kSmsOtp, + CardUnmaskChallengeOptionType::kEmailOtp})); - controller()->SetSelectedChallengeOptionsForTesting( - test::GetCardUnmaskChallengeOptions( - {CardUnmaskChallengeOptionType::kSmsOtp, - CardUnmaskChallengeOptionType::kCvc})); - controller()->SetSelectedChallengeOptionId( - CardUnmaskChallengeOption::ChallengeOptionId( - controller()->GetChallengeOptions()[0].id.value())); - EXPECT_EQ(controller()->GetChallengeOptions()[0].id.value(), - controller()->GetSelectedChallengeOptionIdForTesting().value()); + controller()->SetSelectedChallengeOptionId( + CardUnmaskChallengeOption::ChallengeOptionId( + challenge_option.id.value())); + EXPECT_EQ(challenge_option.id.value(), + controller()->GetSelectedChallengeOptionIdForTesting().value()); - controller()->OnOkButtonClicked(); - controller()->OnDialogClosed(/*user_closed_dialog=*/false, - /*server_success=*/true); - histogram_tester.ExpectUniqueSample( - "Autofill.CardUnmaskAuthenticationSelectionDialog.Result", - AutofillMetrics::CardUnmaskAuthenticationSelectionDialogResultMetric:: - kDismissedByServerRequestSuccess, - 1); + controller()->OnOkButtonClicked(); + controller()->OnDialogClosed(/*user_closed_dialog=*/false, + /*server_success=*/true); + count++; + histogram_tester.ExpectUniqueSample( + "Autofill.CardUnmaskAuthenticationSelectionDialog.Result", + AutofillMetrics::CardUnmaskAuthenticationSelectionDialogResultMetric:: + kDismissedByServerRequestSuccess, + count); + } } TEST_F(CardUnmaskAuthenticationSelectionDialogControllerImplTest, @@ -134,22 +154,27 @@ controller()->SetSelectedChallengeOptionsForTesting( test::GetCardUnmaskChallengeOptions( {CardUnmaskChallengeOptionType::kSmsOtp, - CardUnmaskChallengeOptionType::kCvc})); - controller()->SetSelectedChallengeOptionId( - CardUnmaskChallengeOption::ChallengeOptionId( - controller()->GetChallengeOptions()[0].id.value())); - EXPECT_EQ(controller()->GetChallengeOptions()[0].id.value(), - controller()->GetSelectedChallengeOptionIdForTesting().value()); + CardUnmaskChallengeOptionType::kEmailOtp})); + int count = 0; + for (CardUnmaskChallengeOption challenge_option : + controller()->GetChallengeOptions()) { + SCOPED_TRACE(testing::Message() << " count=" << count); + controller()->SetSelectedChallengeOptionId( + CardUnmaskChallengeOption::ChallengeOptionId( + challenge_option.id.value())); + EXPECT_EQ(challenge_option.id.value(), + controller()->GetSelectedChallengeOptionIdForTesting().value()); - controller()->OnOkButtonClicked(); - controller()->OnDialogClosed(/*user_closed_dialog=*/false, - /*server_success=*/false); - - histogram_tester.ExpectUniqueSample( - "Autofill.CardUnmaskAuthenticationSelectionDialog.Result", - AutofillMetrics::CardUnmaskAuthenticationSelectionDialogResultMetric:: - kDismissedByServerRequestFailure, - 1); + controller()->OnOkButtonClicked(); + controller()->OnDialogClosed(/*user_closed_dialog=*/false, + /*server_success=*/false); + count++; + histogram_tester.ExpectUniqueSample( + "Autofill.CardUnmaskAuthenticationSelectionDialog.Result", + AutofillMetrics::CardUnmaskAuthenticationSelectionDialogResultMetric:: + kDismissedByServerRequestFailure, + count); + } } TEST_F(CardUnmaskAuthenticationSelectionDialogControllerImplTest, @@ -184,6 +209,7 @@ controller()->SetSelectedChallengeOptionsForTesting( test::GetCardUnmaskChallengeOptions( {CardUnmaskChallengeOptionType::kSmsOtp, + CardUnmaskChallengeOptionType::kEmailOtp, CardUnmaskChallengeOptionType::kCvc})); for (CardUnmaskChallengeOption challenge_option :
diff --git a/chrome/browser/ui/browser_focus_uitest.cc b/chrome/browser/ui/browser_focus_uitest.cc index 24cbc9d..d5b282a 100644 --- a/chrome/browser/ui/browser_focus_uitest.cc +++ b/chrome/browser/ui/browser_focus_uitest.cc
@@ -89,8 +89,7 @@ void ClickOnView(ViewID vid) { ui_test_utils::ClickOnView(browser(), vid); } void TestFocusTraversal(WebContents* tab, bool reverse) { - const char kGetFocusedElementJS[] = - "window.domAutomationController.send(getFocusedElement());"; + const char kGetFocusedElementJS[] = "getFocusedElement();"; const char* kExpectedIDs[] = {"textEdit", "searchButton", "luckyButton", "googleLink", "gmailLink", "gmapLink"}; SCOPED_TRACE(base::StringPrintf("TestFocusTraversal: reverse=%d", reverse)); @@ -147,10 +146,8 @@ auto observed_details = observer.Wait(); EXPECT_EQ(is_editable_node, observed_details.is_editable_node); - std::string focused_id; - EXPECT_TRUE(content::ExecuteScriptAndExtractString( - tab, kGetFocusedElementJS, &focused_id)); - EXPECT_STREQ(kExpectedIDs[index], focused_id.c_str()); + EXPECT_EQ(kExpectedIDs[index], + content::EvalJs(tab, kGetFocusedElementJS)); } // On the last Tab key press, focus returns to the browser.
diff --git a/chrome/browser/ui/browser_tabrestore_browsertest.cc b/chrome/browser/ui/browser_tabrestore_browsertest.cc index 89481e2..77635f8 100644 --- a/chrome/browser/ui/browser_tabrestore_browsertest.cc +++ b/chrome/browser/ui/browser_tabrestore_browsertest.cc
@@ -39,12 +39,9 @@ void CheckVisbility(TabStripModel* tab_strip_model, int visible_index) { for (int i = 0; i < tab_strip_model->count(); ++i) { content::WebContents* contents = tab_strip_model->GetWebContentsAt(i); - std::string document_visibility_state; - const char kGetStateJS[] = - "window.domAutomationController.send(" - "window.document.visibilityState);"; - EXPECT_TRUE(content::ExecuteScriptAndExtractString( - contents, kGetStateJS, &document_visibility_state)); + const char kGetStateJS[] = "window.document.visibilityState;"; + std::string document_visibility_state = + content::EvalJs(contents, kGetStateJS).ExtractString(); if (i == visible_index) { EXPECT_EQ("visible", document_visibility_state); } else {
diff --git a/chrome/browser/ui/color/chrome_color_id.h b/chrome/browser/ui/color/chrome_color_id.h index 9f9b57b6..da374e0 100644 --- a/chrome/browser/ui/color/chrome_color_id.h +++ b/chrome/browser/ui/color/chrome_color_id.h
@@ -522,6 +522,11 @@ E_CPONLY(kColorReadAnythingDropdownBackgroundDark) \ E_CPONLY(kColorReadAnythingDropdownBackgroundLight) \ E_CPONLY(kColorReadAnythingDropdownBackgroundYellow) \ + E_CPONLY(kColorReadAnythingDropdownSelected) \ + E_CPONLY(kColorReadAnythingDropdownSelectedBlue) \ + E_CPONLY(kColorReadAnythingDropdownSelectedDark) \ + E_CPONLY(kColorReadAnythingDropdownSelectedLight) \ + E_CPONLY(kColorReadAnythingDropdownSelectedYellow) \ #if BUILDFLAG(IS_CHROMEOS) #define CHROME_PLATFORM_SPECIFIC_COLOR_IDS \
diff --git a/chrome/browser/ui/color/chrome_color_mixer.cc b/chrome/browser/ui/color/chrome_color_mixer.cc index c305d302..10f4bcb 100644 --- a/chrome/browser/ui/color/chrome_color_mixer.cc +++ b/chrome/browser/ui/color/chrome_color_mixer.cc
@@ -12,6 +12,7 @@ #include "chrome/browser/themes/theme_properties.h" #include "chrome/browser/ui/color/chrome_color_id.h" #include "chrome/browser/ui/color/chrome_color_provider_utils.h" +#include "chrome_color_id.h" #include "components/omnibox/common/omnibox_features.h" #include "third_party/skia/include/core/SkColor.h" #include "ui/base/ui_base_features.h" @@ -726,24 +727,33 @@ mixer[kColorReadAnythingForeground] = { dark_mode ? kColorReadAnythingForegroundDark : kColorReadAnythingForegroundLight}; - mixer[kColorReadAnythingForegroundBlue] = ui::PickGoogleColor( - kColorReadAnythingForegroundLight, kColorReadAnythingBackgroundBlue, + mixer[kColorReadAnythingForegroundBlue] = ui::PickGoogleColorTwoBackgrounds( + kColorReadAnythingForegroundLight, + kColorReadAnythingDropdownBackgroundBlue, + kColorReadAnythingDropdownSelectedBlue, color_utils::kMinimumReadableContrastRatio); - mixer[kColorReadAnythingForegroundDark] = {gfx::kGoogleGrey200}; - mixer[kColorReadAnythingForegroundLight] = {gfx::kGoogleGrey800}; - mixer[kColorReadAnythingForegroundYellow] = ui::PickGoogleColor( + mixer[kColorReadAnythingForegroundDark] = ui::PickGoogleColorTwoBackgrounds( + gfx::kGoogleGrey200, kColorReadAnythingDropdownBackgroundDark, + kColorReadAnythingDropdownSelectedDark, + color_utils::kMinimumReadableContrastRatio); + mixer[kColorReadAnythingForegroundLight] = ui::PickGoogleColorTwoBackgrounds( + gfx::kGoogleGrey800, kColorReadAnythingBackgroundLight, + kColorReadAnythingDropdownSelectedLight, + color_utils::kMinimumReadableContrastRatio); + mixer[kColorReadAnythingForegroundYellow] = ui::PickGoogleColorTwoBackgrounds( kColorReadAnythingForegroundLight, kColorReadAnythingBackgroundYellow, + kColorReadAnythingDropdownSelectedYellow, color_utils::kMinimumReadableContrastRatio); mixer[kColorReadAnythingSeparator] = {dark_mode ? kColorReadAnythingSeparatorDark : kColorReadAnythingSeparatorLight}; - mixer[kColorReadAnythingSeparatorBlue] = ui::PickGoogleColor( - kColorReadAnythingForegroundLight, kColorReadAnythingBackgroundBlue, - color_utils::kMinimumVisibleContrastRatio); + mixer[kColorReadAnythingSeparatorBlue] = + ui::PickGoogleColor(gfx::kGoogleGrey500, kColorReadAnythingBackgroundBlue, + color_utils::kMinimumVisibleContrastRatio); mixer[kColorReadAnythingSeparatorDark] = {gfx::kGoogleGrey800}; mixer[kColorReadAnythingSeparatorLight] = {gfx::kGoogleGrey300}; mixer[kColorReadAnythingSeparatorYellow] = ui::PickGoogleColor( - kColorReadAnythingForegroundLight, kColorReadAnythingBackgroundYellow, + gfx::kGoogleGrey500, kColorReadAnythingBackgroundYellow, color_utils::kMinimumVisibleContrastRatio); mixer[kColorReadAnythingDropdownBackground] = { dark_mode ? kColorReadAnythingDropdownBackgroundDark @@ -752,7 +762,13 @@ mixer[kColorReadAnythingDropdownBackgroundDark] = {gfx::kGoogleGrey900}; mixer[kColorReadAnythingDropdownBackgroundLight] = {SK_ColorWHITE}; mixer[kColorReadAnythingDropdownBackgroundYellow] = {gfx::kGoogleYellow050}; - + mixer[kColorReadAnythingDropdownSelected] = { + dark_mode ? kColorReadAnythingDropdownSelectedDark + : kColorReadAnythingDropdownSelectedLight}; + mixer[kColorReadAnythingDropdownSelectedBlue] = {gfx::kGoogleBlue200}; + mixer[kColorReadAnythingDropdownSelectedDark] = {gfx::kGoogleGrey800}; + mixer[kColorReadAnythingDropdownSelectedLight] = {gfx::kGoogleGrey200}; + mixer[kColorReadAnythingDropdownSelectedYellow] = {gfx::kGoogleYellow200}; // Apply high contrast recipes if necessary. if (!ShouldApplyHighContrastColors(key)) { return;
diff --git a/chrome/browser/ui/extensions/hosted_app_browsertest.cc b/chrome/browser/ui/extensions/hosted_app_browsertest.cc index d4a43f27..413e44b 100644 --- a/chrome/browser/ui/extensions/hosted_app_browsertest.cc +++ b/chrome/browser/ui/extensions/hosted_app_browsertest.cc
@@ -988,14 +988,10 @@ // Verify that |same_dir| and |diff_dir| have the same origin according to // |window.origin| (even though they have different |same_dir_site| and // |diff_dir_site|). - std::string same_dir_origin; - EXPECT_TRUE(content::ExecuteScriptAndExtractString( - same_dir, "domAutomationController.send(window.origin)", - &same_dir_origin)); - std::string diff_dir_origin; - EXPECT_TRUE(content::ExecuteScriptAndExtractString( - diff_dir, "domAutomationController.send(window.origin)", - &diff_dir_origin)); + std::string same_dir_origin = + content::EvalJs(same_dir, "window.origin").ExtractString(); + std::string diff_dir_origin = + content::EvalJs(diff_dir, "window.origin").ExtractString(); EXPECT_EQ(diff_dir_origin, same_dir_origin); // Verify that (1) all same-site iframes stay in the process, (2) isolated @@ -1021,13 +1017,10 @@ // Verify that |same_dir| and |diff_dir| can script each other. // (they should - they have the same origin). - std::string inner_text_from_other_frame; const std::string r_script = R"( var w = window.open('', 'SameOrigin-SamePath'); - domAutomationController.send(w.document.body.innerText); )"; - ASSERT_TRUE(content::ExecuteScriptAndExtractString( - diff_dir, r_script, &inner_text_from_other_frame)); - EXPECT_EQ("Simple test page.", inner_text_from_other_frame); + w.document.body.innerText; )"; + EXPECT_EQ("Simple test page.", content::EvalJs(diff_dir, r_script)); } // Check that if a hosted app has an iframe, and that iframe navigates to URLs
diff --git a/chrome/browser/ui/find_bar/find_bar_host_browsertest.cc b/chrome/browser/ui/find_bar/find_bar_host_browsertest.cc index afc4619..b70e23d2 100644 --- a/chrome/browser/ui/find_bar/find_bar_host_browsertest.cc +++ b/chrome/browser/ui/find_bar/find_bar_host_browsertest.cc
@@ -664,11 +664,7 @@ EXPECT_EQ(1, ordinal); // Move the selection to link 1, after searching. - std::string result; - ASSERT_TRUE(content::ExecuteScriptAndExtractString( - web_contents, - "window.domAutomationController.send(selectLink1());", - &result)); + ASSERT_TRUE(content::ExecJs(web_contents, "selectLink1();")); // Do a find-next after the selection. This should move forward // from there to the 3rd instance of 'google'. @@ -693,11 +689,7 @@ int ordinal = 0; // Move the selection to the text span. - std::string result; - ASSERT_TRUE(content::ExecuteScriptAndExtractString( - web_contents, - "window.domAutomationController.send(selectSpan());", - &result)); + ASSERT_TRUE(content::ExecJs(web_contents, "selectSpan();")); // Do a find-next after the selection. This should select the 2nd occurrence // of the word 'find'.
diff --git a/chrome/browser/ui/find_bar/find_bar_host_interactive_uitest.cc b/chrome/browser/ui/find_bar/find_bar_host_interactive_uitest.cc index 8466065..3e4410c 100644 --- a/chrome/browser/ui/find_bar/find_bar_host_interactive_uitest.cc +++ b/chrome/browser/ui/find_bar/find_bar_host_interactive_uitest.cc
@@ -49,12 +49,8 @@ } // namespace -[[nodiscard]] bool FocusedOnPage(WebContents* web_contents, - std::string* result) { - return content::ExecuteScriptAndExtractString( - web_contents, - "window.domAutomationController.send(getFocusedElement());", - result); +[[nodiscard]] std::string FocusedOnPage(WebContents* web_contents) { + return content::EvalJs(web_contents, "getFocusedElement();").ExtractString(); } // This tests the FindInPage end-state, in other words: what is focused when you @@ -78,9 +74,7 @@ find_in_page::FindTabHelper::FromWebContents(web_contents); // Verify that nothing has focus. - std::string result; - ASSERT_TRUE(FocusedOnPage(web_contents, &result)); - ASSERT_STREQ("{nothing focused}", result.c_str()); + ASSERT_EQ("{nothing focused}", FocusedOnPage(web_contents)); // Search for a text that exists within a link on the page. int ordinal = 0; @@ -92,8 +86,7 @@ find_tab_helper->StopFinding(find_in_page::SelectionAction::kKeep); // Verify that the link is focused. - ASSERT_TRUE(FocusedOnPage(web_contents, &result)); - EXPECT_STREQ("link1", result.c_str()); + EXPECT_EQ("link1", FocusedOnPage(web_contents)); // Search for a text that exists within a link on the page. EXPECT_EQ(1, FindInPageASCII(web_contents, "Google", @@ -101,15 +94,11 @@ EXPECT_EQ(1, ordinal); // Move the selection to link 1, after searching. - ASSERT_TRUE(content::ExecuteScriptAndExtractString( - web_contents, - "window.domAutomationController.send(selectLink1());", - &result)); + EXPECT_TRUE(content::ExecJs(web_contents, "selectLink1();")); // End the find session. find_tab_helper->StopFinding(find_in_page::SelectionAction::kKeep); // Verify that link2 is not focused. - ASSERT_TRUE(FocusedOnPage(web_contents, &result)); - EXPECT_STREQ("", result.c_str()); + EXPECT_EQ("", FocusedOnPage(web_contents)); }
diff --git a/chrome/browser/ui/fullscreen_keyboard_browsertest_base.cc b/chrome/browser/ui/fullscreen_keyboard_browsertest_base.cc index fce0a61..39f27e2 100644 --- a/chrome/browser/ui/fullscreen_keyboard_browsertest_base.cc +++ b/chrome/browser/ui/fullscreen_keyboard_browsertest_base.cc
@@ -418,9 +418,9 @@ EXPECT_TRUE(ui_test_utils::SendKeyPressSync(GetActiveBrowser(), ui::VKEY_X, false, false, false, false)); expected_result_ += "KeyX ctrl:false shift:false alt:false meta:false"; - std::string result; - EXPECT_TRUE(content::ExecuteScriptAndExtractString( - GetActiveWebContents(), "getKeyEventReport();", &result)); + std::string result = + content::EvalJs(GetActiveWebContents(), "getKeyEventReport();") + .ExtractString(); NormalizeMetaKeyForMacOS(&result); NormalizeMetaKeyForMacOS(&expected_result_); base::TrimWhitespaceASCII(result, base::TRIM_ALL, &result);
diff --git a/chrome/browser/ui/search/third_party_ntp_browsertest.cc b/chrome/browser/ui/search/third_party_ntp_browsertest.cc index 0173cce8..105a4294 100644 --- a/chrome/browser/ui/search/third_party_ntp_browsertest.cc +++ b/chrome/browser/ui/search/third_party_ntp_browsertest.cc
@@ -74,11 +74,8 @@ // Verify that the subframe exists and has the expected origin. content::RenderFrameHost* subframe = ChildFrameAt(contents, 0); ASSERT_TRUE(subframe); - std::string subframe_origin; - ASSERT_TRUE(content::ExecuteScriptAndExtractString( - subframe, "domAutomationController.send(window.origin)", - &subframe_origin)); - EXPECT_EQ("chrome-search://most-visited", subframe_origin); + EXPECT_EQ("chrome-search://most-visited", + content::EvalJs(subframe, "window.origin")); } // Verifies that Chrome won't spawn a separate renderer process for
diff --git a/chrome/browser/ui/signin_reauth_view_controller_browsertest.cc b/chrome/browser/ui/signin_reauth_view_controller_browsertest.cc index 3c53d5b21..945f438c 100644 --- a/chrome/browser/ui/signin_reauth_view_controller_browsertest.cc +++ b/chrome/browser/ui/signin_reauth_view_controller_browsertest.cc
@@ -607,13 +607,11 @@ confirmation_dialog_contents); navigation_observer.Wait(); - std::string dialog_message; - ASSERT_TRUE(content::ExecuteScriptAndExtractString( - confirmation_dialog_contents, - "window.domAutomationController.send(" - "document.querySelector('signin-reauth-app').shadowRoot." - "querySelector('.message-container').innerText)", - &dialog_message)); + std::string dialog_message = + content::EvalJs(confirmation_dialog_contents, + "document.querySelector('signin-reauth-app').shadowRoot." + "querySelector('.message-container').innerText") + .ExtractString(); // The dialog message should specify that the password was already saved // locally. EXPECT_EQ(dialog_message, @@ -632,13 +630,11 @@ confirmation_dialog_contents); navigation_observer.Wait(); - std::string dialog_message; - ASSERT_TRUE(content::ExecuteScriptAndExtractString( - confirmation_dialog_contents, - "window.domAutomationController.send(" - "document.querySelector('signin-reauth-app').shadowRoot." - "querySelector('.message-container').innerText)", - &dialog_message)); + std::string dialog_message = + content::EvalJs(confirmation_dialog_contents, + "document.querySelector('signin-reauth-app').shadowRoot." + "querySelector('.message-container').innerText") + .ExtractString(); // The dialog message should be the regular one. EXPECT_EQ(dialog_message, l10n_util::GetStringUTF8(IDS_ACCOUNT_PASSWORDS_REAUTH_DESC));
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bubble_view.cc b/chrome/browser/ui/views/bookmarks/bookmark_bubble_view.cc index 520d0ca..d3262ef 100644 --- a/chrome/browser/ui/views/bookmarks/bookmark_bubble_view.cc +++ b/chrome/browser/ui/views/bookmarks/bookmark_bubble_view.cc
@@ -75,6 +75,9 @@ void FetchImageForUrl(const GURL& url, Profile* profile) { page_image_service::ImageService* image_service = page_image_service::ImageServiceFactory::GetForBrowserContext(profile); + if (!image_service) { + return; + } page_image_service::mojom::Options options; options.suggest_images = true; options.optimization_guide_images = true;
diff --git a/chrome/browser/ui/views/content_test_utils.cc b/chrome/browser/ui/views/content_test_utils.cc index fe191ca..5bbec078 100644 --- a/chrome/browser/ui/views/content_test_utils.cc +++ b/chrome/browser/ui/views/content_test_utils.cc
@@ -53,9 +53,8 @@ while (result != "a") { GiveItSomeTime(base::Milliseconds(100)); - ASSERT_TRUE(content::ExecuteScriptAndExtractString(contents, R"( - window.domAutomationController.send( - document.getElementById('text-id').value); - )", &result)); + result = + content::EvalJs(contents, "document.getElementById('text-id').value;") + .ExtractString(); } }
diff --git a/chrome/browser/ui/views/device_id/pen_id_browsertest_win.cc b/chrome/browser/ui/views/device_id/pen_id_browsertest_win.cc index 1a930260..bcfa78bb 100644 --- a/chrome/browser/ui/views/device_id/pen_id_browsertest_win.cc +++ b/chrome/browser/ui/views/device_id/pen_id_browsertest_win.cc
@@ -30,6 +30,9 @@ #include "ui/views/win/pen_id_handler.h" #include "ui/views/win/test_support/fake_ipen_device.h" #include "ui/views/win/test_support/fake_ipen_device_statics.h" +#include "ui/views/win/test_support/fake_ipen_pointer_point_statics.h" +#include "ui/views/win/test_support/fake_ipointer_point.h" +#include "ui/views/win/test_support/fake_ipointer_point_properties.h" using views::FakeIPenDevice; using views::FakeIPenDeviceStatics; @@ -40,6 +43,12 @@ constexpr char kMainTestPageUrlPath[] = "/device_id/test.html"; +constexpr int kPointerId1 = 0; +constexpr int kPointerId2 = 1; +constexpr int kPointerId3 = 2; +constexpr int kDeviceId1 = 0; +constexpr int kDeviceId2 = 1; + } // namespace class PenIdBrowserTest : public InProcessBrowserTest { @@ -168,14 +177,8 @@ // (MouseEventCallback) so that when the browser sends the pen event, it // checks for the right device id. IN_PROC_BROWSER_TEST_F(PenIdBrowserTest, PenDeviceTest) { - int kPointerId1 = 0; - int kPointerId2 = 1; - int kPointerId3 = 2; - int kDeviceId1 = 0; - int kDeviceId2 = 1; - views::PenIdHandler::ScopedPenIdStaticsForTesting scoper( - &FakeIPenDeviceStatics::FakeIPenDeviceStaticsComPtr); + &FakeIPenDeviceStatics::FakeIPenDeviceStaticsComPtr, nullptr); const auto fake_pen_device = Microsoft::WRL::Make<FakeIPenDevice>(); FakeIPenDeviceStatics::GetInstance()->SimulatePenEventGenerated( kPointerId1, fake_pen_device); @@ -200,3 +203,38 @@ kDeviceId1, base::BindOnce(&PenIdBrowserTest::SimulatePenPointerDragEvent, base::Unretained(this))); } + +// Perform a pen drag for a pen that has a transducer id. Verify the correct +// device id is propagated in the pointer event. +IN_PROC_BROWSER_TEST_F(PenIdBrowserTest, PointerPointTest) { + views::PenIdHandler::ScopedPenIdStaticsForTesting scoper( + nullptr, + &views::FakeIPenPointerPointStatics::FakeIPenPointerPointStaticsComPtr); + + const auto p1 = Microsoft::WRL::Make<views::FakeIPointerPoint>( + /*getProperties throw error*/ false, + /*has usage error*/ false, + /*get usage error*/ false, + /*tsn*/ 100, + /*tvid*/ 1); + const auto p2 = Microsoft::WRL::Make<views::FakeIPointerPoint>( + /*getProperties throw error*/ false, + /*has usage error*/ false, + /*get usage error*/ false, + /*tsn*/ 200, + /*tvid*/ 1); + + views::FakeIPenPointerPointStatics::GetInstance()->AddPointerPoint( + kPointerId1, p1); + views::FakeIPenPointerPointStatics::GetInstance()->AddPointerPoint( + kPointerId2, p2); + + SimulatePenPointerEventAndStop( + kPointerId1, + base::BindOnce(&PenIdBrowserTest::SimulatePenPointerDragEvent, + base::Unretained(this))); + SimulatePenPointerEventAndStop( + kPointerId2, + base::BindOnce(&PenIdBrowserTest::SimulatePenPointerDragEvent, + base::Unretained(this))); +}
diff --git a/chrome/browser/ui/views/extensions/extensions_menu_main_page_view.cc b/chrome/browser/ui/views/extensions/extensions_menu_main_page_view.cc index e0f7fe2..28647bd7 100644 --- a/chrome/browser/ui/views/extensions/extensions_menu_main_page_view.cc +++ b/chrome/browser/ui/views/extensions/extensions_menu_main_page_view.cc
@@ -266,16 +266,6 @@ GetSiteSettingToggleText(is_site_settings_toggle_on)); } -void ExtensionsMenuMainPageView::UpdateContextMenuButtons( - const ToolbarActionsModel& toolbar_model) { - for (views::View* view : menu_items_->children()) { - ExtensionMenuItemView* menu_item = GetAsMenuItem(view); - bool is_action_pinned = - toolbar_model.IsActionPinned(menu_item->view_controller()->GetId()); - menu_item->UpdateContextMenuButton(is_action_pinned); - } -} - std::vector<ExtensionMenuItemView*> ExtensionsMenuMainPageView::GetMenuItems() const { std::vector<ExtensionMenuItemView*> menu_item_views;
diff --git a/chrome/browser/ui/views/extensions/extensions_menu_main_page_view.h b/chrome/browser/ui/views/extensions/extensions_menu_main_page_view.h index 82747e2..3ced5fd8 100644 --- a/chrome/browser/ui/views/extensions/extensions_menu_main_page_view.h +++ b/chrome/browser/ui/views/extensions/extensions_menu_main_page_view.h
@@ -61,9 +61,6 @@ bool is_site_settings_toggle_visible, bool is_site_settings_toggle_on); - // Updates the context menu button of each menu item. - void UpdateContextMenuButtons(const ToolbarActionsModel& toolbar_model); - void OnToggleButtonPressed(); // Accessors used by tests:
diff --git a/chrome/browser/ui/views/extensions/extensions_menu_view_controller.cc b/chrome/browser/ui/views/extensions/extensions_menu_view_controller.cc index 2e27bf80..d880c38 100644 --- a/chrome/browser/ui/views/extensions/extensions_menu_view_controller.cc +++ b/chrome/browser/ui/views/extensions/extensions_menu_view_controller.cc
@@ -437,7 +437,13 @@ auto* main_page = GetMainPage(current_page_); DCHECK(main_page); - main_page->UpdateContextMenuButtons(*toolbar_model_); + + std::vector<ExtensionMenuItemView*> menu_items = main_page->GetMenuItems(); + for (auto* menu_item : menu_items) { + bool is_action_pinned = + toolbar_model_->IsActionPinned(menu_item->view_controller()->GetId()); + menu_item->UpdateContextMenuButton(is_action_pinned); + } } void ExtensionsMenuViewController::OnUserPermissionsSettingsChanged(
diff --git a/chrome/browser/ui/views/file_system_access/file_system_access_browsertest.cc b/chrome/browser/ui/views/file_system_access/file_system_access_browsertest.cc index 7afc6a62..c49cb3fb 100644 --- a/chrome/browser/ui/views/file_system_access/file_system_access_browsertest.cc +++ b/chrome/browser/ui/views/file_system_access/file_system_access_browsertest.cc
@@ -1237,15 +1237,10 @@ // encountered during evaluation, returns the error's message. std::string GetJsStatementValueAsString(content::WebContents* web_contents, const std::string& statement) { - std::string result; - EXPECT_TRUE(content::ExecuteScriptAndExtractString( - web_contents, - base::StrCat({"Promise.resolve(", statement, ").then(", - " result => domAutomationController.send(result)," - " error => domAutomationController.send(error.message)" - ");"}), - &result)); - return result; + return content::EvalJs(web_contents, + base::StrCat({"Promise.resolve(", statement, + ").catch(error => error.message);"})) + .ExtractString(); } content::WebContents* SetUpAndNavigateToTestWebUI() {
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc index 2577e40..2d021372 100644 --- a/chrome/browser/ui/views/frame/browser_view.cc +++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -1754,13 +1754,27 @@ (!notify_download && bubble_type == EXCLUSIVE_ACCESS_BUBBLE_TYPE_NONE) || (ShouldUseImmersiveFullscreenForUrl(url) && !profiles::IsPublicSession())) { - // |exclusive_access_bubble_.reset()| will trigger callback for current - // bubble with |ExclusiveAccessBubbleHideReason::kInterrupted| if available. - exclusive_access_bubble_.reset(); if (bubble_first_hide_callback) { std::move(bubble_first_hide_callback) .Run(ExclusiveAccessBubbleHideReason::kNotShown); } + + // If we intend to close the bubble but it has already been deleted no + // action is needed. + if (!exclusive_access_bubble_) { + return; + } + + // `HideImmediately()` will trigger a callback for the current bubble with + // `ExclusiveAccessBubbleHideReason::kInterrupted` if available. + exclusive_access_bubble_->HideImmediately(); + + // Perform the destroy async. State updates in the exclusive access bubble + // view may call back into this method. This otherwise results in premature + // deletion of the bubble view and UAFs. See crbug.com/1426521. + base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( + FROM_HERE, base::BindOnce(&BrowserView::DestroyAnyExclusiveAccessBubble, + GetAsWeakPtr())); return; } @@ -4511,6 +4525,14 @@ body_text_replacements, user_education::FeaturePromoController::BubbleCloseCallback close_callback) { + // Trying to show a promo before the browser is initialized can result in a + // failure to retrieve accelerators, which can cause issues for screen reader + // users. + if (!initialized_) { + LOG(ERROR) << "Attempting to show IPH " << iph_feature.name + << " before browser initialization; IPH will not be shown."; + return false; + } return feature_promo_controller_ && feature_promo_controller_->MaybeShowPromo( iph_feature, body_text_replacements, std::move(close_callback));
diff --git a/chrome/browser/ui/views/payments/payment_request_browsertest_base.cc b/chrome/browser/ui/views/payments/payment_request_browsertest_base.cc index e31f906..cc68557 100644 --- a/chrome/browser/ui/views/payments/payment_request_browsertest_base.cc +++ b/chrome/browser/ui/views/payments/payment_request_browsertest_base.cc
@@ -321,13 +321,9 @@ void PaymentRequestBrowserTestBase::ExpectBodyContains( const std::vector<std::string>& expected_strings) { content::WebContents* web_contents = GetActiveWebContents(); - const std::string extract_contents_js = - "(function() { " - "window.domAutomationController.send(window.document.body.textContent); " - "})()"; - std::string contents; - EXPECT_TRUE(content::ExecuteScriptAndExtractString( - web_contents, extract_contents_js, &contents)); + const std::string extract_contents_js = "window.document.body.textContent;"; + std::string contents = + content::EvalJs(web_contents, extract_contents_js).ExtractString(); for (const std::string& expected_string : expected_strings) { EXPECT_NE(std::string::npos, contents.find(expected_string)) << "String \"" << expected_string
diff --git a/chrome/browser/ui/views/permissions/one_time_permission_interactive_ui_test.cc b/chrome/browser/ui/views/permissions/one_time_permission_interactive_ui_test.cc index b1500eb..8caa656 100644 --- a/chrome/browser/ui/views/permissions/one_time_permission_interactive_ui_test.cc +++ b/chrome/browser/ui/views/permissions/one_time_permission_interactive_ui_test.cc
@@ -47,10 +47,7 @@ std::string RunScript(content::RenderFrameHost* render_frame_host, const std::string& script) { - std::string result; - EXPECT_TRUE(content::ExecuteScriptAndExtractString(render_frame_host, script, - &result)); - return result; + return content::EvalJs(render_frame_host, script).ExtractString(); } class IndicatorObserver : public MediaStreamCaptureIndicator::Observer { @@ -171,7 +168,6 @@ void WatchPositionAndExpectGrantedPermission( permissions::PermissionRequestManager::AutoResponseType auto_response, bool expect_prompt) { - std::string result; content::WebContents* contents = current_browser()->tab_strip_model()->GetActiveWebContents(); SetFrameForScriptExecutionToCurrent(contents); @@ -180,8 +176,9 @@ permissions::PermissionRequestObserver observer(contents); if (expect_prompt) { - EXPECT_TRUE(content::ExecuteScriptAndExtractString( - contents, "geoStartWithAsyncResponse();", &result)); + std::string result = + content::EvalJs(contents, "geoStartWithAsyncResponse();") + .ExtractString(); EXPECT_TRUE( result == "request-callback-success" || // First request. result ==
diff --git a/chrome/browser/ui/views/side_panel/extensions/extension_side_panel_browsertest.cc b/chrome/browser/ui/views/side_panel/extensions/extension_side_panel_browsertest.cc index 71aea5f6..e85b58e 100644 --- a/chrome/browser/ui/views/side_panel/extensions/extension_side_panel_browsertest.cc +++ b/chrome/browser/ui/views/side_panel/extensions/extension_side_panel_browsertest.cc
@@ -182,14 +182,11 @@ extensions::ExtensionSidePanelManager::GetOrCreateForBrowser(browser()) ->GetExtensionCoordinatorForTesting(extension_id); - std::string result; - static constexpr char kScript[] = - "domAutomationController.send(document.sidePanelTemp);"; + static constexpr char kScript[] = "document.sidePanelTemp;"; - EXPECT_TRUE(content::ExecuteScriptAndExtractString( - extension_coordinator->GetHostWebContentsForTesting(), kScript, - &result)); - return result; + return content::EvalJs( + extension_coordinator->GetHostWebContentsForTesting(), kScript) + .ExtractString(); } // Runs a script in the extension's side panel WebContents to set the value of
diff --git a/chrome/browser/ui/views/side_panel/read_anything/read_anything_container_view.cc b/chrome/browser/ui/views/side_panel/read_anything/read_anything_container_view.cc index 0c82155..16d4e829 100644 --- a/chrome/browser/ui/views/side_panel/read_anything/read_anything_container_view.cc +++ b/chrome/browser/ui/views/side_panel/read_anything/read_anything_container_view.cc
@@ -82,6 +82,7 @@ ui::ColorId background_color_id, ui::ColorId separator_color_id, ui::ColorId dropdown_color_id, + ui::ColorId selection_color_id, read_anything::mojom::LineSpacing line_spacing, read_anything::mojom::LetterSpacing letter_spacing) { separator_->SetColorId(separator_color_id); @@ -100,7 +101,7 @@ base::UmaHistogramExactLinear(string_constants::kFontScaleHistogramName, GetNormalizedFontScale(font_scale), maximum_font_scale_logging + 1); - ReadAnythingColorsModel::ReadAnythingColor color = + ReadAnythingColorsModel::ColorInfo::ReadAnythingColor color = coordinator_->GetModel()->color_logging_value(); base::UmaHistogramEnumeration(string_constants::kColorHistogramName, color); read_anything::mojom::LineSpacing line_spacing =
diff --git a/chrome/browser/ui/views/side_panel/read_anything/read_anything_container_view.h b/chrome/browser/ui/views/side_panel/read_anything/read_anything_container_view.h index 55173ceb..ab8937e 100644 --- a/chrome/browser/ui/views/side_panel/read_anything/read_anything_container_view.h +++ b/chrome/browser/ui/views/side_panel/read_anything/read_anything_container_view.h
@@ -47,6 +47,7 @@ ui::ColorId background_color_id, ui::ColorId separator_color_id, ui::ColorId dropdown_color_id, + ui::ColorId selection_color_id, read_anything::mojom::LineSpacing line_spacing, read_anything::mojom::LetterSpacing letter_spacing) override;
diff --git a/chrome/browser/ui/views/side_panel/read_anything/read_anything_controller_unittest.cc b/chrome/browser/ui/views/side_panel/read_anything/read_anything_controller_unittest.cc index 572aef5..a98863e6 100644 --- a/chrome/browser/ui/views/side_panel/read_anything/read_anything_controller_unittest.cc +++ b/chrome/browser/ui/views/side_panel/read_anything/read_anything_controller_unittest.cc
@@ -39,6 +39,7 @@ ui::ColorId background_color_id, ui::ColorId separator_color_id, ui::ColorId dropdown_color_id, + ui::ColorId selection_color_id, read_anything::mojom::LineSpacing line_spacing, read_anything::mojom::LetterSpacing letter_spacing), (override));
diff --git a/chrome/browser/ui/views/side_panel/read_anything/read_anything_font_combobox.cc b/chrome/browser/ui/views/side_panel/read_anything/read_anything_font_combobox.cc index a4da2a2d..d5ca9e6 100644 --- a/chrome/browser/ui/views/side_panel/read_anything/read_anything_font_combobox.cc +++ b/chrome/browser/ui/views/side_panel/read_anything/read_anything_font_combobox.cc
@@ -71,9 +71,12 @@ void ReadAnythingFontCombobox::SetDropdownColorIds( absl::optional<ui::ColorId> background_color, - absl::optional<ui::ColorId> foreground_color) { + absl::optional<ui::ColorId> foreground_color, + absl::optional<ui::ColorId> selected_color) { delegate_->GetFontComboboxModel()->SetForegroundColorId(foreground_color); delegate_->GetFontComboboxModel()->SetBackgroundColorId(background_color); + delegate_->GetFontComboboxModel()->SetSelectedBackgroundColorId( + selected_color); } BEGIN_METADATA(ReadAnythingFontCombobox, views::Combobox)
diff --git a/chrome/browser/ui/views/side_panel/read_anything/read_anything_font_combobox.h b/chrome/browser/ui/views/side_panel/read_anything/read_anything_font_combobox.h index c3a7805..cc73ddb 100644 --- a/chrome/browser/ui/views/side_panel/read_anything/read_anything_font_combobox.h +++ b/chrome/browser/ui/views/side_panel/read_anything/read_anything_font_combobox.h
@@ -28,8 +28,11 @@ ReadAnythingFontCombobox& operator=(const ReadAnythingFontCombobox&) = delete; ~ReadAnythingFontCombobox() override; + // TODO(b/1266555): Remove absl::optional from color setters here and + // elsewhere as they are only needed for the getters. void SetDropdownColorIds(absl::optional<ui::ColorId> foreground_color, - absl::optional<ui::ColorId> background_color); + absl::optional<ui::ColorId> background_color, + absl::optional<ui::ColorId> selected_color); // views::Combobox: gfx::Size GetMinimumSize() const override;
diff --git a/chrome/browser/ui/views/side_panel/read_anything/read_anything_menu_button.cc b/chrome/browser/ui/views/side_panel/read_anything/read_anything_menu_button.cc index 8eccf03..01561fba 100644 --- a/chrome/browser/ui/views/side_panel/read_anything/read_anything_menu_button.cc +++ b/chrome/browser/ui/views/side_panel/read_anything/read_anything_menu_button.cc
@@ -72,9 +72,11 @@ } void ReadAnythingMenuButton::SetDropdownColorIds(ui::ColorId background_color, - ui::ColorId foreground_color) { + ui::ColorId foreground_color, + ui::ColorId selected_color) { menu_model_->SetSubmenuBackgroundColorId(background_color); menu_model_->SetForegroundColorId(foreground_color); + menu_model_->SetSelectedBackgroundColorId(selected_color); } BEGIN_METADATA(ReadAnythingMenuButton, MenuButton)
diff --git a/chrome/browser/ui/views/side_panel/read_anything/read_anything_menu_button.h b/chrome/browser/ui/views/side_panel/read_anything/read_anything_menu_button.h index 92a2518..b889539 100644 --- a/chrome/browser/ui/views/side_panel/read_anything/read_anything_menu_button.h +++ b/chrome/browser/ui/views/side_panel/read_anything/read_anything_menu_button.h
@@ -33,7 +33,8 @@ int icon_size, ui::ColorId icon_color); void SetDropdownColorIds(ui::ColorId background_color, - ui::ColorId foreground_color); + ui::ColorId foreground_color, + ui::ColorId selected_color); private: void ButtonPressed();
diff --git a/chrome/browser/ui/views/side_panel/read_anything/read_anything_menu_model.cc b/chrome/browser/ui/views/side_panel/read_anything/read_anything_menu_model.cc index a5c581be..86c41aaa 100644 --- a/chrome/browser/ui/views/side_panel/read_anything/read_anything_menu_model.cc +++ b/chrome/browser/ui/views/side_panel/read_anything/read_anything_menu_model.cc
@@ -45,3 +45,8 @@ size_t index) { return submenu_background_color_id_; } + +absl::optional<ui::ColorId> ReadAnythingMenuModel::GetSelectedBackgroundColorId( + size_t index) { + return selected_color_id_; +}
diff --git a/chrome/browser/ui/views/side_panel/read_anything/read_anything_menu_model.h b/chrome/browser/ui/views/side_panel/read_anything/read_anything_menu_model.h index a467cc7..112b9ea 100644 --- a/chrome/browser/ui/views/side_panel/read_anything/read_anything_menu_model.h +++ b/chrome/browser/ui/views/side_panel/read_anything/read_anything_menu_model.h
@@ -33,6 +33,8 @@ absl::optional<ui::ColorId> GetForegroundColorId(size_t index) override; absl::optional<ui::ColorId> GetSubmenuBackgroundColorId( size_t index) override; + absl::optional<ui::ColorId> GetSelectedBackgroundColorId( + size_t index) override; void SetForegroundColorId(absl::optional<ui::ColorId> foreground_color) { foreground_color_id_ = foreground_color; @@ -43,11 +45,17 @@ submenu_background_color_id_ = background_color; } + void SetSelectedBackgroundColorId( + absl::optional<ui::ColorId> selected_color) { + selected_color_id_ = selected_color; + } + private: absl::optional<size_t> selected_index_ = absl::nullopt; base::RepeatingClosure callback_; absl::optional<ui::ColorId> foreground_color_id_; absl::optional<ui::ColorId> submenu_background_color_id_; + absl::optional<ui::ColorId> selected_color_id_; }; #endif // CHROME_BROWSER_UI_VIEWS_SIDE_PANEL_READ_ANYTHING_READ_ANYTHING_MENU_MODEL_H_
diff --git a/chrome/browser/ui/views/side_panel/read_anything/read_anything_model.cc b/chrome/browser/ui/views/side_panel/read_anything/read_anything_model.cc index b626f6b..015bcf6 100644 --- a/chrome/browser/ui/views/side_panel/read_anything/read_anything_model.cc +++ b/chrome/browser/ui/views/side_panel/read_anything/read_anything_model.cc
@@ -77,6 +77,7 @@ background_color_id_ = initial_colors.background_color_id; separator_color_id_ = initial_colors.separator_color_id; dropdown_color_id_ = initial_colors.dropdown_color_id; + selected_dropdown_color_id_ = initial_colors.selected_dropdown_color_id; line_spacing_ = line_spacing_model_->GetLineSpacingAt( line_spacing_model_->GetSelectedIndex().value()); @@ -115,6 +116,7 @@ background_color_id_ = new_colors.background_color_id; separator_color_id_ = new_colors.separator_color_id; dropdown_color_id_ = new_colors.dropdown_color_id; + selected_dropdown_color_id_ = new_colors.selected_dropdown_color_id; NotifyThemeChanged(); } @@ -195,10 +197,10 @@ void ReadAnythingModel::NotifyThemeChanged() { for (Observer& obs : observers_) { - obs.OnReadAnythingThemeChanged(font_name_, font_scale_, - foreground_color_id_, background_color_id_, - separator_color_id_, dropdown_color_id_, - line_spacing_, letter_spacing_); + obs.OnReadAnythingThemeChanged( + font_name_, font_scale_, foreground_color_id_, background_color_id_, + separator_color_id_, dropdown_color_id_, selected_dropdown_color_id_, + line_spacing_, letter_spacing_); } } @@ -286,11 +288,40 @@ return background_color_id_; } +absl::optional<ui::ColorId> +ReadAnythingFontModel::GetDropdownSelectedBackgroundColorIdAt( + size_t index) const { + return selected_color_id_; +} + ReadAnythingFontModel::~ReadAnythingFontModel() = default; /////////////////////////////////////////////////////////////////////////////// // ReadAnythingColorsModel /////////////////////////////////////////////////////////////////////////////// +ReadAnythingColorsModel::ColorInfo::ColorInfo( + std::u16string name, + int icon_asset, + ui::ColorId foreground_color_id, + ui::ColorId background_color_id, + ui::ColorId separator_color_id, + ui::ColorId dropdown_color_id, + ui::ColorId selected_dropdown_color_id, + ColorInfo::ReadAnythingColor logging_value) + : name(name), + icon_asset(icon_asset), + foreground_color_id(foreground_color_id), + background_color_id(background_color_id), + separator_color_id(separator_color_id), + dropdown_color_id(dropdown_color_id), + selected_dropdown_color_id(selected_dropdown_color_id), + logging_value(logging_value) {} +ReadAnythingColorsModel::ColorInfo::ColorInfo(const ColorInfo& other) = default; +ReadAnythingColorsModel::ColorInfo::ColorInfo(ColorInfo&&) = default; +ReadAnythingColorsModel::ColorInfo& +ReadAnythingColorsModel::ColorInfo::operator=(const ColorInfo&) = default; +ReadAnythingColorsModel::ColorInfo& +ReadAnythingColorsModel::ColorInfo::operator=(ColorInfo&&) = default; ReadAnythingColorsModel::ReadAnythingColorsModel() { // Define the possible sets of colors available to the user. @@ -301,7 +332,8 @@ kColorReadAnythingBackground, kColorReadAnythingSeparator, kColorReadAnythingDropdownBackground, - ReadAnythingColor::kDefault}; + kColorReadAnythingDropdownSelected, + ColorInfo::ReadAnythingColor::kDefault}; ColorInfo kLightColors = { l10n_util::GetStringUTF16(IDS_READING_MODE_LIGHT_COLOR_LABEL), @@ -310,7 +342,8 @@ kColorReadAnythingBackgroundLight, kColorReadAnythingSeparatorLight, kColorReadAnythingDropdownBackgroundLight, - ReadAnythingColor::kLight}; + kColorReadAnythingDropdownSelectedLight, + ColorInfo::ReadAnythingColor::kLight}; ColorInfo kDarkColors = { l10n_util::GetStringUTF16(IDS_READING_MODE_DARK_COLOR_LABEL), @@ -319,7 +352,8 @@ kColorReadAnythingBackgroundDark, kColorReadAnythingSeparatorDark, kColorReadAnythingDropdownBackgroundDark, - ReadAnythingColor::kDark}; + kColorReadAnythingDropdownSelectedDark, + ColorInfo::ReadAnythingColor::kDark}; ColorInfo kYellowColors = { l10n_util::GetStringUTF16(IDS_READING_MODE_YELLOW_COLOR_LABEL), @@ -328,7 +362,8 @@ kColorReadAnythingBackgroundYellow, kColorReadAnythingSeparatorYellow, kColorReadAnythingDropdownBackgroundYellow, - ReadAnythingColor::kYellow}; + kColorReadAnythingDropdownSelectedYellow, + ColorInfo::ReadAnythingColor::kYellow}; ColorInfo kBlueColors = { l10n_util::GetStringUTF16(IDS_READING_MODE_BLUE_COLOR_LABEL), @@ -337,7 +372,8 @@ kColorReadAnythingBackgroundBlue, kColorReadAnythingSeparatorBlue, kColorReadAnythingDropdownBackgroundBlue, - ReadAnythingColor::kBlue}; + kColorReadAnythingDropdownSelectedBlue, + ColorInfo::ReadAnythingColor::kBlue}; colors_choices_.emplace_back(kDefaultColors); colors_choices_.emplace_back(kLightColors);
diff --git a/chrome/browser/ui/views/side_panel/read_anything/read_anything_model.h b/chrome/browser/ui/views/side_panel/read_anything/read_anything_model.h index 3fab14a..e6c001a9 100644 --- a/chrome/browser/ui/views/side_panel/read_anything/read_anything_model.h +++ b/chrome/browser/ui/views/side_panel/read_anything/read_anything_model.h
@@ -50,6 +50,8 @@ size_t index) const override; absl::optional<ui::ColorId> GetDropdownBackgroundColorIdAt( size_t index) const override; + absl::optional<ui::ColorId> GetDropdownSelectedBackgroundColorIdAt( + size_t index) const override; void SetForegroundColorId(absl::optional<ui::ColorId> foreground_color) { foreground_color_id_ = foreground_color; @@ -59,6 +61,11 @@ background_color_id_ = background_color; } + void SetSelectedBackgroundColorId( + absl::optional<ui::ColorId> selected_color) { + selected_color_id_ = selected_color; + } + // Used by tests only. absl::optional<size_t> GetDefaultIndexForTesting(); @@ -77,6 +84,7 @@ absl::optional<ui::ColorId> foreground_color_id_; absl::optional<ui::ColorId> background_color_id_; + absl::optional<ui::ColorId> selected_color_id_; }; /////////////////////////////////////////////////////////////////////////////// @@ -88,25 +96,33 @@ // class ReadAnythingColorsModel : public ReadAnythingMenuModel { public: - ReadAnythingColorsModel(); - ReadAnythingColorsModel(const ReadAnythingColorsModel&) = delete; - ReadAnythingColorsModel& operator=(const ReadAnythingColorsModel&) = delete; - ~ReadAnythingColorsModel() override; - - // Enum for logging the user-chosen color. - // These values are persisted to logs. Entries should not be renumbered and - // numeric values should never be reused. - enum class ReadAnythingColor { - kDefault = 0, - kLight = 1, - kDark = 2, - kYellow = 3, - kBlue = 4, - kMaxValue = kBlue, - }; - // Simple struct to hold the various colors to keep code cleaner. struct ColorInfo { + // Enum for logging the user-chosen color. + // These values are persisted to logs. Entries should not be renumbered and + // numeric values should never be reused. + enum class ReadAnythingColor { + kDefault = 0, + kLight = 1, + kDark = 2, + kYellow = 3, + kBlue = 4, + kMaxValue = kBlue, + }; + + ColorInfo(std::u16string name, + int icon_asset, + ui::ColorId foreground_color_id, + ui::ColorId background_color_id, + ui::ColorId separator_color_id, + ui::ColorId dropdown_color_id, + ui::ColorId selected_color_id, + ColorInfo::ReadAnythingColor logging_value); + ColorInfo(const ColorInfo& other); + ColorInfo(ColorInfo&&); + ColorInfo& operator=(const ColorInfo&); + ColorInfo& operator=(ColorInfo&&); + // The name of the colors, e.g. Default, Light, Dark. std::u16string name; @@ -126,10 +142,19 @@ // The color of the dropdown menu, used for the combobox menu model. ui::ColorId dropdown_color_id; + // The selected / hover color of the dropdown menu, used for the combobox + // menu model. + ui::ColorId selected_dropdown_color_id; + // The enum value used to log this theme. - ReadAnythingColorsModel::ReadAnythingColor logging_value; + ColorInfo::ReadAnythingColor logging_value; }; + ReadAnythingColorsModel(); + ReadAnythingColorsModel(const ReadAnythingColorsModel&) = delete; + ReadAnythingColorsModel& operator=(const ReadAnythingColorsModel&) = delete; + ~ReadAnythingColorsModel() override; + bool IsValidIndex(size_t index) override; ColorInfo& GetColorsAt(size_t index); ui::ImageModel GetDropDownIconAt(size_t index) const; @@ -237,6 +262,7 @@ ui::ColorId background_color_id, ui::ColorId separator_color_id, ui::ColorId dropdown_color_id, + ui::ColorId selected_color_id, read_anything::mojom::LineSpacing line_spacing, read_anything::mojom::LetterSpacing letter_spacing) = 0; #if BUILDFLAG(ENABLE_SCREEN_AI_SERVICE) @@ -289,7 +315,7 @@ read_anything::mojom::LetterSpacing letter_spacing() { return letter_spacing_; } - ReadAnythingColorsModel::ReadAnythingColor color_logging_value() { + ReadAnythingColorsModel::ColorInfo::ReadAnythingColor color_logging_value() { return colors_model_->GetColorsAt(colors_combobox_index_).logging_value; } @@ -306,6 +332,7 @@ // Additional theme colors. ui::ColorId separator_color_id_ = kColorReadAnythingSeparator; ui::ColorId dropdown_color_id_ = kColorReadAnythingDropdownBackground; + ui::ColorId selected_dropdown_color_id_ = kColorReadAnythingDropdownSelected; // A scale multiplier for font size (internal use only, not shown to user). float font_scale_ = kReadAnythingDefaultFontScale;
diff --git a/chrome/browser/ui/views/side_panel/read_anything/read_anything_model_unittest.cc b/chrome/browser/ui/views/side_panel/read_anything/read_anything_model_unittest.cc index f8087b2..a737b787 100644 --- a/chrome/browser/ui/views/side_panel/read_anything/read_anything_model_unittest.cc +++ b/chrome/browser/ui/views/side_panel/read_anything/read_anything_model_unittest.cc
@@ -40,6 +40,7 @@ ui::ColorId background_color_id, ui::ColorId separator_color_id, ui::ColorId dropdown_color_id, + ui::ColorId selected_color_id, read_anything::mojom::LineSpacing line_spacing, read_anything::mojom::LetterSpacing letter_spacing), (override)); @@ -81,13 +82,13 @@ EXPECT_CALL(model_observer_1_, AccessibilityEventReceived(_)).Times(0); EXPECT_CALL(model_observer_1_, OnActiveAXTreeIDChanged(_, _)).Times(0); EXPECT_CALL(model_observer_1_, - OnReadAnythingThemeChanged(_, _, _, _, _, _, _, _)) + OnReadAnythingThemeChanged(_, _, _, _, _, _, _, _, _)) .Times(1); EXPECT_CALL(model_observer_2_, AccessibilityEventReceived(_)).Times(0); EXPECT_CALL(model_observer_2_, OnActiveAXTreeIDChanged(_, _)).Times(0); EXPECT_CALL(model_observer_2_, - OnReadAnythingThemeChanged(_, _, _, _, _, _, _, _)) + OnReadAnythingThemeChanged(_, _, _, _, _, _, _, _, _)) .Times(1); model_->AddObserver(&model_observer_2_); @@ -100,19 +101,19 @@ EXPECT_CALL(model_observer_1_, AccessibilityEventReceived(_)).Times(0); EXPECT_CALL(model_observer_1_, OnActiveAXTreeIDChanged(_, _)).Times(0); EXPECT_CALL(model_observer_1_, - OnReadAnythingThemeChanged(_, _, _, _, _, _, _, _)) + OnReadAnythingThemeChanged(_, _, _, _, _, _, _, _, _)) .Times(1); EXPECT_CALL(model_observer_2_, AccessibilityEventReceived(_)).Times(0); EXPECT_CALL(model_observer_2_, OnActiveAXTreeIDChanged(_, _)).Times(0); EXPECT_CALL(model_observer_2_, - OnReadAnythingThemeChanged(_, _, _, _, _, _, _, _)) + OnReadAnythingThemeChanged(_, _, _, _, _, _, _, _, _)) .Times(0); EXPECT_CALL(model_observer_3_, AccessibilityEventReceived(_)).Times(0); EXPECT_CALL(model_observer_3_, OnActiveAXTreeIDChanged(_, _)).Times(0); EXPECT_CALL(model_observer_3_, - OnReadAnythingThemeChanged(_, _, _, _, _, _, _, _)) + OnReadAnythingThemeChanged(_, _, _, _, _, _, _, _, _)) .Times(1); model_->RemoveObserver(&model_observer_2_); @@ -123,7 +124,7 @@ model_->AddObserver(&model_observer_1_); EXPECT_CALL(model_observer_1_, - OnReadAnythingThemeChanged(_, _, _, _, _, _, _, _)) + OnReadAnythingThemeChanged(_, _, _, _, _, _, _, _, _)) .Times(1); model_->SetSelectedFontByIndex(2); @@ -160,7 +161,7 @@ model_->AddObserver(&model_observer_1_); EXPECT_CALL(model_observer_1_, - OnReadAnythingThemeChanged(_, _, _, _, _, _, _, _)) + OnReadAnythingThemeChanged(_, _, _, _, _, _, _, _, _)) .Times(1); model_->DecreaseTextSize(); @@ -172,7 +173,7 @@ model_->AddObserver(&model_observer_1_); EXPECT_CALL(model_observer_1_, - OnReadAnythingThemeChanged(_, _, _, _, _, _, _, _)) + OnReadAnythingThemeChanged(_, _, _, _, _, _, _, _, _)) .Times(1); model_->IncreaseTextSize(); @@ -184,7 +185,7 @@ model_->AddObserver(&model_observer_1_); EXPECT_CALL(model_observer_1_, - OnReadAnythingThemeChanged(_, _, _, _, _, _, _, _)) + OnReadAnythingThemeChanged(_, _, _, _, _, _, _, _, _)) .Times(1); model_->SetSelectedColorsByIndex(2); @@ -194,7 +195,7 @@ model_->AddObserver(&model_observer_1_); EXPECT_CALL(model_observer_1_, - OnReadAnythingThemeChanged(_, _, _, _, _, _, _, _)) + OnReadAnythingThemeChanged(_, _, _, _, _, _, _, _, _)) .Times(1); model_->SetSelectedLineSpacingByIndex(2); @@ -204,7 +205,7 @@ model_->AddObserver(&model_observer_1_); EXPECT_CALL(model_observer_1_, - OnReadAnythingThemeChanged(_, _, _, _, _, _, _, _)) + OnReadAnythingThemeChanged(_, _, _, _, _, _, _, _, _)) .Times(1); model_->SetSelectedLetterSpacingByIndex(2); @@ -214,7 +215,7 @@ model_->AddObserver(&model_observer_1_); EXPECT_CALL(model_observer_1_, - OnReadAnythingThemeChanged(_, _, _, _, _, _, _, _)) + OnReadAnythingThemeChanged(_, _, _, _, _, _, _, _, _)) .Times(1); model_->OnSystemThemeChanged(); @@ -266,6 +267,8 @@ TEST_F(ReadAnythingModelTest, FontModelHasDefaultNullOptColors) { EXPECT_FALSE(GetFontModel()->GetDropdownForegroundColorIdAt(0).has_value()); EXPECT_FALSE(GetFontModel()->GetDropdownBackgroundColorIdAt(0).has_value()); + EXPECT_FALSE( + GetFontModel()->GetDropdownSelectedBackgroundColorIdAt(0).has_value()); } TEST_F(ReadAnythingModelTest, FontModelSetsDropdownAndForegroundColors) { @@ -274,11 +277,15 @@ GetFontModel()->SetForegroundColorId(color_info.foreground_color_id); GetFontModel()->SetBackgroundColorId(color_info.dropdown_color_id); + GetFontModel()->SetSelectedBackgroundColorId( + color_info.selected_dropdown_color_id); EXPECT_EQ(color_info.foreground_color_id, GetFontModel()->GetDropdownForegroundColorIdAt(0).value()); EXPECT_EQ(color_info.dropdown_color_id, GetFontModel()->GetDropdownBackgroundColorIdAt(0).value()); + EXPECT_EQ(color_info.selected_dropdown_color_id, + GetFontModel()->GetDropdownSelectedBackgroundColorIdAt(0).value()); } #endif // !defined(ADDRESS_SANITIZER)
diff --git a/chrome/browser/ui/views/side_panel/read_anything/read_anything_toolbar_view.cc b/chrome/browser/ui/views/side_panel/read_anything/read_anything_toolbar_view.cc index b8fb2033..9067c9f 100644 --- a/chrome/browser/ui/views/side_panel/read_anything/read_anything_toolbar_view.cc +++ b/chrome/browser/ui/views/side_panel/read_anything/read_anything_toolbar_view.cc
@@ -162,6 +162,7 @@ ui::ColorId background_color_id, ui::ColorId separator_color_id, ui::ColorId dropdown_color_id, + ui::ColorId selected_dropdown_color_id, read_anything::mojom::LineSpacing line_spacing, read_anything::mojom::LetterSpacing letter_spacing) { if (font_scale > kReadAnythingMinimumFontScale) { @@ -201,12 +202,14 @@ foreground_color_id); // Update the background colors for the dropdowns. - colors_button_->SetDropdownColorIds(dropdown_color_id, foreground_color_id); - letter_spacing_button_->SetDropdownColorIds(dropdown_color_id, - foreground_color_id); - line_spacing_button_->SetDropdownColorIds(dropdown_color_id, - foreground_color_id); - font_combobox_->SetDropdownColorIds(dropdown_color_id, foreground_color_id); + colors_button_->SetDropdownColorIds(dropdown_color_id, foreground_color_id, + selected_dropdown_color_id); + letter_spacing_button_->SetDropdownColorIds( + dropdown_color_id, foreground_color_id, selected_dropdown_color_id); + line_spacing_button_->SetDropdownColorIds( + dropdown_color_id, foreground_color_id, selected_dropdown_color_id); + font_combobox_->SetDropdownColorIds(dropdown_color_id, foreground_color_id, + selected_dropdown_color_id); for (views::Separator* separator : separators_) { separator->SetColorId(separator_color_id);
diff --git a/chrome/browser/ui/views/side_panel/read_anything/read_anything_toolbar_view.h b/chrome/browser/ui/views/side_panel/read_anything/read_anything_toolbar_view.h index 8d1158c8..0cc0c69 100644 --- a/chrome/browser/ui/views/side_panel/read_anything/read_anything_toolbar_view.h +++ b/chrome/browser/ui/views/side_panel/read_anything/read_anything_toolbar_view.h
@@ -63,6 +63,7 @@ ui::ColorId background_color_id, ui::ColorId separator_color_id, ui::ColorId dropdown_color_id, + ui::ColorId selected_dropdown_color_id, read_anything::mojom::LineSpacing line_spacing, read_anything::mojom::LetterSpacing letter_spacing) override;
diff --git a/chrome/browser/ui/views/side_panel/read_anything/read_anything_toolbar_view_browsertest.cc b/chrome/browser/ui/views/side_panel/read_anything/read_anything_toolbar_view_browsertest.cc index 134aed7..3a664e0 100644 --- a/chrome/browser/ui/views/side_panel/read_anything/read_anything_toolbar_view_browsertest.cc +++ b/chrome/browser/ui/views/side_panel/read_anything/read_anything_toolbar_view_browsertest.cc
@@ -96,11 +96,13 @@ ui::ColorId background_color_id, ui::ColorId separator_color_id, ui::ColorId dropdown_color_id, + ui::ColorId selected_color_id, read_anything::mojom::LineSpacing line_spacing, read_anything::mojom::LetterSpacing letter_spacing) { toolbar_view_->OnReadAnythingThemeChanged( font_name, font_scale, foreground_color_id, background_color_id, - separator_color_id, dropdown_color_id, line_spacing, letter_spacing); + separator_color_id, dropdown_color_id, selected_color_id, line_spacing, + letter_spacing); } views::Button::ButtonState GetDecreaseSizeButtonState() { @@ -125,7 +127,7 @@ OnReadAnythingThemeChanged( "", kReadAnythingMinimumFontScale, kColorReadAnythingForeground, kColorReadAnythingForeground, kColorReadAnythingForeground, - kColorReadAnythingForeground, + kColorReadAnythingForeground, kColorReadAnythingForeground, read_anything::mojom::LineSpacing::kStandard, read_anything::mojom::LetterSpacing::kStandard); @@ -152,7 +154,7 @@ OnReadAnythingThemeChanged( "", kReadAnythingMaximumFontScale, kColorReadAnythingForeground, kColorReadAnythingForeground, kColorReadAnythingForeground, - kColorReadAnythingForeground, + kColorReadAnythingForeground, kColorReadAnythingForeground, read_anything::mojom::LineSpacing::kStandard, read_anything::mojom::LetterSpacing::kStandard);
diff --git a/chrome/browser/ui/views/toolbar/toolbar_view.cc b/chrome/browser/ui/views/toolbar/toolbar_view.cc index 8801c49..c438f39 100644 --- a/chrome/browser/ui/views/toolbar/toolbar_view.cc +++ b/chrome/browser/ui/views/toolbar/toolbar_view.cc
@@ -105,6 +105,7 @@ #include "ui/gfx/paint_vector_icon.h" #include "ui/gfx/scoped_canvas.h" #include "ui/views/accessibility/view_accessibility.h" +#include "ui/views/background.h" #include "ui/views/cascading_property.h" #include "ui/views/layout/fill_layout.h" #include "ui/views/layout/flex_layout.h" @@ -212,18 +213,51 @@ // Make sure the toolbar shows by default. size_animation_.Reset(1); + std::unique_ptr<DownloadToolbarButtonView> download_button; + if (download::IsDownloadBubbleEnabled(browser_->profile())) { + download_button = + std::make_unique<DownloadToolbarButtonView>(browser_view_); + } + if (display_mode_ != DisplayMode::NORMAL) { location_bar_ = AddChildView(std::move(location_bar)); location_bar_->Init(); + } - if (display_mode_ == DisplayMode::CUSTOM_TAB) { - custom_tab_bar_ = - AddChildView(std::make_unique<CustomTabBarView>(browser_view_, this)); - } - + if (display_mode_ == DisplayMode::CUSTOM_TAB) { + custom_tab_bar_ = + AddChildView(std::make_unique<CustomTabBarView>(browser_view_, this)); SetLayoutManager(std::make_unique<views::FillLayout>()); initialized_ = true; return; + } else if (display_mode_ == DisplayMode::LOCATION) { + // Add the download button for popups. + if (download_button) { + download_button_ = AddChildView(std::move(download_button)); + download_button_->SetPreferredSize( + gfx::Size(location_bar_->GetPreferredSize().height(), + location_bar_->GetPreferredSize().height())); + download_button_->SetFocusBehavior(FocusBehavior::ALWAYS); + // Hide the icon by default; it will show up when there's a download. + download_button_->Hide(); + } + SetBackground( + views::CreateThemedSolidBackground(kColorLocationBarBackground)); + SetLayoutManager(std::make_unique<views::FlexLayout>()) + ->SetOrientation(views::LayoutOrientation::kHorizontal) + .SetCrossAxisAlignment(views::LayoutAlignment::kCenter) + .SetDefault(views::kFlexBehaviorKey, + views::FlexSpecification( + views::LayoutOrientation::kHorizontal, + views::MinimumFlexSizeRule::kPreferredSnapToZero)) + .SetFlexAllocationOrder(views::FlexAllocationOrder::kReverse); + location_bar_->SetProperty( + views::kFlexBehaviorKey, + views::FlexSpecification(views::LayoutOrientation::kHorizontal, + views::MinimumFlexSizeRule::kScaleToZero, + views::MaximumFlexSizeRule::kUnbounded)); + initialized_ = true; + return; } const auto callback = [](Browser* browser, int command, @@ -270,12 +304,6 @@ browser_view_, MediaToolbarButtonContextualMenu::Create(browser_)); } - std::unique_ptr<DownloadToolbarButtonView> download_button; - if (download::IsDownloadBubbleEnabled(browser_->profile())) { - download_button = - std::make_unique<DownloadToolbarButtonView>(browser_view_); - } - std::unique_ptr<send_tab_to_self::SendTabToSelfToolbarIconView> send_tab_to_self_button; if (!browser_->profile()->IsOffTheRecord()) { @@ -661,16 +689,12 @@ return; } - if (display_mode_ == DisplayMode::LOCATION) { - location_bar_->SetBounds(0, 0, width(), - location_bar_->GetPreferredSize().height()); - return; - } + if (display_mode_ == DisplayMode::NORMAL) { + LayoutCommon(); - LayoutCommon(); - - if (features::IsChromeRefresh2023()) { - UpdateClipPath(); + if (features::IsChromeRefresh2023()) { + UpdateClipPath(); + } } // Call super implementation to ensure layout manager and child layouts
diff --git a/chrome/browser/ui/views/web_apps/web_app_integration_test_driver.cc b/chrome/browser/ui/views/web_apps/web_app_integration_test_driver.cc index 5034e682..3eb5371d 100644 --- a/chrome/browser/ui/views/web_apps/web_app_integration_test_driver.cc +++ b/chrome/browser/ui/views/web_apps/web_app_integration_test_driver.cc
@@ -76,12 +76,12 @@ #include "chrome/browser/web_applications/commands/run_on_os_login_command.h" #include "chrome/browser/web_applications/manifest_update_manager.h" #include "chrome/browser/web_applications/mojom/user_display_mode.mojom.h" -#include "chrome/browser/web_applications/os_integration/os_integration_test_override.h" #include "chrome/browser/web_applications/os_integration/web_app_file_handler_registration.h" #include "chrome/browser/web_applications/os_integration/web_app_shortcut.h" #include "chrome/browser/web_applications/policy/web_app_policy_constants.h" #include "chrome/browser/web_applications/policy/web_app_policy_manager.h" #include "chrome/browser/web_applications/test/app_registry_cache_waiter.h" +#include "chrome/browser/web_applications/test/os_integration_test_override_impl.h" #include "chrome/browser/web_applications/test/web_app_icon_test_utils.h" #include "chrome/browser/web_applications/test/web_app_install_test_utils.h" #include "chrome/browser/web_applications/test/web_app_test_observers.h" @@ -807,7 +807,7 @@ void WebAppIntegrationTestDriver::SetUpOnMainThread() { override_registration_ = - OsIntegrationTestOverride::OverrideForTesting(base::GetHomeDir()); + OsIntegrationTestOverrideImpl::OverrideForTesting(base::GetHomeDir()); // Only support manifest updates on non-sync tests, as the current // infrastructure here only supports listening on one profile.
diff --git a/chrome/browser/ui/views/web_apps/web_app_integration_test_driver.h b/chrome/browser/ui/views/web_apps/web_app_integration_test_driver.h index a33f10f3..ef65cb5f 100644 --- a/chrome/browser/ui/views/web_apps/web_app_integration_test_driver.h +++ b/chrome/browser/ui/views/web_apps/web_app_integration_test_driver.h
@@ -20,7 +20,7 @@ #include "chrome/browser/ui/browser_dialogs.h" #include "chrome/browser/ui/views/frame/browser_view.h" #include "chrome/browser/web_applications/os_integration/os_integration_manager.h" -#include "chrome/browser/web_applications/os_integration/os_integration_test_override.h" +#include "chrome/browser/web_applications/test/os_integration_test_override_impl.h" #include "chrome/browser/web_applications/test/web_app_test_observers.h" #include "chrome/browser/web_applications/web_app_callback_app_identity.h" #include "chrome/browser/web_applications/web_app_id.h" @@ -503,7 +503,7 @@ base::ScopedObservation<web_app::WebAppInstallManager, web_app::WebAppInstallManagerObserver> observation_{this}; - std::unique_ptr<OsIntegrationTestOverride::BlockingRegistration> + std::unique_ptr<OsIntegrationTestOverrideImpl::BlockingRegistration> override_registration_; std::unique_ptr<base::RunLoop> window_controls_overlay_callback_for_testing_ =
diff --git a/chrome/browser/ui/web_applications/web_app_browsertest.cc b/chrome/browser/ui/web_applications/web_app_browsertest.cc index 041119d..e05c972 100644 --- a/chrome/browser/ui/web_applications/web_app_browsertest.cc +++ b/chrome/browser/ui/web_applications/web_app_browsertest.cc
@@ -61,8 +61,8 @@ #include "chrome/browser/web_applications/commands/run_on_os_login_command.h" #include "chrome/browser/web_applications/external_install_options.h" #include "chrome/browser/web_applications/mojom/user_display_mode.mojom.h" -#include "chrome/browser/web_applications/os_integration/os_integration_test_override.h" #include "chrome/browser/web_applications/os_integration/web_app_shortcut.h" +#include "chrome/browser/web_applications/test/os_integration_test_override_impl.h" #include "chrome/browser/web_applications/test/web_app_install_test_utils.h" #include "chrome/browser/web_applications/test/web_app_test_observers.h" #include "chrome/browser/web_applications/test/web_app_test_utils.h" @@ -1311,8 +1311,8 @@ os_hooks_suppress_.reset(); base::ScopedAllowBlockingForTesting allow_blocking; - std::unique_ptr<OsIntegrationTestOverride::BlockingRegistration> - registration = OsIntegrationTestOverride::OverrideForTesting(); + std::unique_ptr<OsIntegrationTestOverrideImpl::BlockingRegistration> + registration = OsIntegrationTestOverrideImpl::OverrideForTesting(); NavigateToURLAndWait( browser(), @@ -1381,8 +1381,8 @@ os_hooks_suppress_.reset(); base::ScopedAllowBlockingForTesting allow_blocking; - std::unique_ptr<OsIntegrationTestOverride::BlockingRegistration> - registration = OsIntegrationTestOverride::OverrideForTesting(); + std::unique_ptr<OsIntegrationTestOverrideImpl::BlockingRegistration> + registration = OsIntegrationTestOverrideImpl::OverrideForTesting(); NavigateToURLAndWait( browser(), https_server()->GetURL( @@ -1462,8 +1462,8 @@ os_hooks_suppress_.reset(); base::ScopedAllowBlockingForTesting allow_blocking; - std::unique_ptr<OsIntegrationTestOverride::BlockingRegistration> - registration = OsIntegrationTestOverride::OverrideForTesting(); + std::unique_ptr<OsIntegrationTestOverrideImpl::BlockingRegistration> + registration = OsIntegrationTestOverrideImpl::OverrideForTesting(); NavigateToURLAndWait( browser(), https_server()->GetURL("/banners/" @@ -1527,8 +1527,8 @@ base::ScopedAllowBlockingForTesting allow_blocking; - std::unique_ptr<OsIntegrationTestOverride::BlockingRegistration> - registration = OsIntegrationTestOverride::OverrideForTesting(); + std::unique_ptr<OsIntegrationTestOverrideImpl::BlockingRegistration> + registration = OsIntegrationTestOverrideImpl::OverrideForTesting(); auto* provider = WebAppProvider::GetForTest(profile()); @@ -1593,8 +1593,8 @@ base::ScopedAllowBlockingForTesting allow_blocking; - std::unique_ptr<OsIntegrationTestOverride::BlockingRegistration> - registration = OsIntegrationTestOverride::OverrideForTesting(); + std::unique_ptr<OsIntegrationTestOverrideImpl::BlockingRegistration> + registration = OsIntegrationTestOverrideImpl::OverrideForTesting(); auto* provider = WebAppProvider::GetForTest(profile()); const AppId& app_id = InstallPWA(pwa_url); @@ -1611,11 +1611,11 @@ run_loop.Quit(); })); run_loop.Run(); - EXPECT_TRUE(GetOsIntegrationTestOverride()->IsRunOnOsLoginEnabled( + EXPECT_TRUE(OsIntegrationTestOverrideImpl::Get()->IsRunOnOsLoginEnabled( profile(), app_id, provider->registrar_unsafe().GetAppShortName(app_id))); test::UninstallAllWebApps(profile()); - EXPECT_FALSE(GetOsIntegrationTestOverride()->IsRunOnOsLoginEnabled( + EXPECT_FALSE(OsIntegrationTestOverrideImpl::Get()->IsRunOnOsLoginEnabled( profile(), app_id, provider->registrar_unsafe().GetAppShortName(app_id))); EXPECT_THAT(tester.GetAllSamples("WebApp.RunOnOsLogin.Unregistration.Result"), BucketsAre(base::Bucket(true, 1))); @@ -1659,9 +1659,9 @@ IN_PROC_BROWSER_TEST_P(WebAppBrowserTestUpdateShortcutResult, UpdateShortcut) { os_hooks_suppress_.reset(); base::ScopedAllowBlockingForTesting allow_blocking; - std::unique_ptr<OsIntegrationTestOverride::BlockingRegistration> + std::unique_ptr<OsIntegrationTestOverrideImpl::BlockingRegistration> blocking_registration = - OsIntegrationTestOverride::OverrideForTesting(base::GetHomeDir()); + OsIntegrationTestOverrideImpl::OverrideForTesting(base::GetHomeDir()); NavigateToURLAndWait(browser(), GetInstallableAppURL()); @@ -2236,9 +2236,9 @@ base::ScopedAllowBlockingForTesting allow_blocking; base::HistogramTester tester; - std::unique_ptr<OsIntegrationTestOverride::BlockingRegistration> + std::unique_ptr<OsIntegrationTestOverrideImpl::BlockingRegistration> registration = - OsIntegrationTestOverride::OverrideForTesting(base::GetHomeDir()); + OsIntegrationTestOverrideImpl::OverrideForTesting(base::GetHomeDir()); std::vector<std::string> expected_extensions{"bar", "baz", "foo", "foobar"}; ASSERT_TRUE(embedded_test_server()->Start()); @@ -2336,9 +2336,9 @@ os_hooks_suppress_.reset(); base::ScopedAllowBlockingForTesting allow_blocking; - std::unique_ptr<OsIntegrationTestOverride::BlockingRegistration> + std::unique_ptr<OsIntegrationTestOverrideImpl::BlockingRegistration> registration = - OsIntegrationTestOverride::OverrideForTesting(base::GetHomeDir()); + OsIntegrationTestOverrideImpl::OverrideForTesting(base::GetHomeDir()); std::vector<std::string> expected_extensions{"bar", "baz", "foo", "foobar"}; ASSERT_TRUE(embedded_test_server()->Start());
diff --git a/chrome/browser/ui/webui/ash/add_supervision/add_supervision_ui_browsertest.cc b/chrome/browser/ui/webui/ash/add_supervision/add_supervision_ui_browsertest.cc index 97993b66..f67f819 100644 --- a/chrome/browser/ui/webui/ash/add_supervision/add_supervision_ui_browsertest.cc +++ b/chrome/browser/ui/webui/ash/add_supervision/add_supervision_ui_browsertest.cc
@@ -4,6 +4,7 @@ #include <string> +#include "base/strings/strcat.h" #include "base/test/metrics/histogram_tester.h" #include "base/test/metrics/user_action_tester.h" #include "chrome/browser/ui/browser.h" @@ -93,14 +94,14 @@ EXPECT_TRUE(content::WaitForLoadStop(contents())); // Get the URL from the embedded webview. - std::string webview_url; - ASSERT_TRUE(content::ExecuteScriptAndExtractString( - contents(), - std::string("domAutomationController.send(") + - std::string(kGetAddSupervisionUIElementJS) + - ".shadowRoot.querySelector('#webview').getAttribute('src')" + - std::string(");"), - &webview_url)); + std::string webview_url = + content::EvalJs( + contents(), + base::StrCat( + {kGetAddSupervisionUIElementJS, + ".shadowRoot.querySelector('#webview').getAttribute('src')", + ";"})) + .ExtractString(); GURL webview_gurl(webview_url); ASSERT_TRUE(webview_gurl.has_query());
diff --git a/chrome/browser/ui/webui/ash/set_time_ui.cc b/chrome/browser/ui/webui/ash/set_time_ui.cc index 5aa326a..fb1c21b 100644 --- a/chrome/browser/ui/webui/ash/set_time_ui.cc +++ b/chrome/browser/ui/webui/ash/set_time_ui.cc
@@ -27,6 +27,7 @@ #include "chrome/grit/generated_resources.h" #include "chromeos/ash/components/dbus/system_clock/system_clock_client.h" #include "chromeos/ash/components/settings/timezone_settings.h" +#include "chromeos/constants/chromeos_features.h" #include "components/strings/grit/components_strings.h" #include "components/user_manager/user_manager.h" #include "content/public/browser/web_contents.h" @@ -36,6 +37,7 @@ #include "services/network/public/mojom/content_security_policy.mojom.h" #include "ui/base/webui/web_ui_util.h" #include "ui/resources/grit/webui_resources.h" +#include "ui/webui/color_change_listener/color_change_handler.h" #include "ui/webui/mojo_web_ui_controller.h" namespace ash { @@ -191,16 +193,25 @@ source->AddLocalizedStrings(values); + source->AddResourcePath("set_time.js", IDR_SET_TIME_JS); source->AddResourcePath("set_time_browser_proxy.js", IDR_SET_TIME_BROWSER_PROXY_JS); source->AddResourcePath("set_time_dialog.html.js", IDR_SET_TIME_DIALOG_HTML_JS); source->AddResourcePath("set_time_dialog.js", IDR_SET_TIME_DIALOG_JS); source->SetDefaultResource(IDR_SET_TIME_HTML); + + source->AddBoolean("isJellyEnabled", chromeos::features::IsJellyEnabled()); } SetTimeUI::~SetTimeUI() = default; +void SetTimeUI::BindInterface( + mojo::PendingReceiver<color_change_listener::mojom::PageHandler> receiver) { + color_provider_handler_ = std::make_unique<ui::ColorChangeHandler>( + web_ui()->GetWebContents(), std::move(receiver)); +} + WEB_UI_CONTROLLER_TYPE_IMPL(SetTimeUI) } // namespace ash
diff --git a/chrome/browser/ui/webui/ash/set_time_ui.h b/chrome/browser/ui/webui/ash/set_time_ui.h index 5af3785..7a8d8190 100644 --- a/chrome/browser/ui/webui/ash/set_time_ui.h +++ b/chrome/browser/ui/webui/ash/set_time_ui.h
@@ -8,8 +8,14 @@ #include "chrome/common/webui_url_constants.h" #include "content/public/browser/webui_config.h" #include "content/public/common/url_constants.h" +#include "mojo/public/cpp/bindings/pending_receiver.h" #include "ui/web_dialogs/web_dialog_ui.h" #include "ui/webui/mojo_web_ui_controller.h" +#include "ui/webui/resources/cr_components/color_change_listener/color_change_listener.mojom.h" + +namespace ui { +class ColorChangeHandler; +} // namespace ui namespace ash { @@ -33,7 +39,15 @@ ~SetTimeUI() override; + void BindInterface( + mojo::PendingReceiver<color_change_listener::mojom::PageHandler> + receiver); + private: + // The color change handler notifies the WebUI when the color provider + // changes the color palette + std::unique_ptr<ui::ColorChangeHandler> color_provider_handler_; + WEB_UI_CONTROLLER_TYPE_DECL(); };
diff --git a/chrome/browser/ui/webui/extensions/extension_settings_browsertest.cc b/chrome/browser/ui/webui/extensions/extension_settings_browsertest.cc index 062d7b2..f251348 100644 --- a/chrome/browser/ui/webui/extensions/extension_settings_browsertest.cc +++ b/chrome/browser/ui/webui/extensions/extension_settings_browsertest.cc
@@ -157,16 +157,15 @@ browser()->tab_strip_model()->GetActiveWebContents()); // Verify the contents of the view-source tab. - std::string actual_source_text; std::string view_source_extraction_script = R"( output = ""; document.querySelectorAll(".line-content").forEach(function(elem) { output += elem.innerText; }); - domAutomationController.send(output); )"; - EXPECT_TRUE(content::ExecuteScriptAndExtractString( - view_source_contents, view_source_extraction_script, - &actual_source_text)); + output; )"; + std::string actual_source_text = + content::EvalJs(view_source_contents, view_source_extraction_script) + .ExtractString(); base::FilePath source_path = test_data_dir().AppendASCII("options_page_in_view/options.html"); std::string expected_source_text;
diff --git a/chrome/browser/ui/webui/management/management_ui_browsertest.cc b/chrome/browser/ui/webui/management/management_ui_browsertest.cc index be8dbab..4e79f3a 100644 --- a/chrome/browser/ui/webui/management/management_ui_browsertest.cc +++ b/chrome/browser/ui/webui/management/management_ui_browsertest.cc
@@ -71,13 +71,12 @@ "window.ManagementBrowserProxyImpl.getInstance()" " .getContextualManagedData()" " .then(managed_result => " - " domAutomationController.send(JSON.stringify(managed_result)));"; + " JSON.stringify(managed_result));"; content::WebContents* contents = browser()->tab_strip_model()->GetActiveWebContents(); - std::string unmanaged_json; - ASSERT_TRUE(content::ExecuteScriptAndExtractString(contents, javascript, - &unmanaged_json)); + std::string unmanaged_json = + content::EvalJs(contents, javascript).ExtractString(); absl::optional<base::Value> unmanaged_value_ptr = base::JSONReader::Read(unmanaged_json); @@ -109,10 +108,8 @@ kOnPremReportingExtensionBetaId); contents = browser()->tab_strip_model()->GetActiveWebContents(); - std::string managed_json; - - ASSERT_TRUE(content::ExecuteScriptAndExtractString(contents, javascript, - &managed_json)); + std::string managed_json = + content::EvalJs(contents, javascript).ExtractString(); absl::optional<base::Value> managed_value_ptr = base::JSONReader::Read(managed_json);
diff --git a/chrome/browser/ui/webui/policy/policy_ui_browsertest.cc b/chrome/browser/ui/webui/policy/policy_ui_browsertest.cc index f3a187f6..d693c431 100644 --- a/chrome/browser/ui/webui/policy/policy_ui_browsertest.cc +++ b/chrome/browser/ui/webui/policy/policy_ui_browsertest.cc
@@ -351,10 +351,9 @@ " policies.push(values);" " }" "}" - "domAutomationController.send(JSON.stringify(policies));"; - std::string json; - ASSERT_TRUE(content::ExecuteScriptAndExtractString(web_contents(), javascript, - &json)); + "JSON.stringify(policies);"; + std::string json = + content::EvalJs(web_contents(), javascript).ExtractString(); absl::optional<base::Value> value_ptr = base::JSONReader::Read(json); ASSERT_TRUE(value_ptr); ASSERT_TRUE(value_ptr->is_list()); @@ -377,11 +376,9 @@ } void PolicyUITest::VerifyReportButton(bool visible) { - const std::string kJavaScript = - "domAutomationController.send(getReportButtonVisibility());"; - std::string ret; - ASSERT_TRUE(content::ExecuteScriptAndExtractString(web_contents(), - kJavaScript, &ret)); + const std::string kJavaScript = "getReportButtonVisibility();"; + std::string ret = + content::EvalJs(web_contents(), kJavaScript).ExtractString(); EXPECT_EQ(visible, ret != "none"); } @@ -628,8 +625,9 @@ // Wait for the status box to appear in case page just loaded. const statusSection = document.getElementById('status-section'); if (statusSection.hidden) { - window.requestIdleCallback(readStatus); - return; + return new Promise(resolve => { + window.requestIdleCallback(resolve); + }).then(readStatus); } const policies = getPolicyFieldsets(); @@ -644,16 +642,16 @@ } statuses[legend.trim()] = entries; } - domAutomationController.send(JSON.stringify(statuses)); - } - window.requestIdleCallback(readStatus); + return JSON.stringify(statuses); + }; + return new Promise(resolve => { + window.requestIdleCallback(resolve); + }).then(readStatus); })(); )JS"; content::WebContents* contents = chrome_test_utils::GetActiveWebContents(this); - std::string json; - if (!content::ExecuteScriptAndExtractString(contents, javascript, &json)) - return false; + std::string json = content::EvalJs(contents, javascript).ExtractString(); absl::optional<base::Value> statuses = base::JSONReader::Read(json); if (!statuses.has_value() || !statuses->is_dict()) return false; @@ -987,7 +985,7 @@ // Used to retrieve the contents of the policy precedence rows. const std::string kJavaScript = "var precedence_row = getPrecedenceRowValue();" - "domAutomationController.send(precedence_row.textContent);"; + "precedence_row.textContent;"; }; // Verify that the precedence order displayed in the Policy Precedence table is @@ -1018,9 +1016,8 @@ // Retrieve the contents of the policy precedence rows. ASSERT_TRUE( content::NavigateToURL(web_contents(), GURL(chrome::kChromeUIPolicyURL))); - std::string precedence_row_value; - ASSERT_TRUE(content::ExecuteScriptAndExtractString( - web_contents(), kJavaScript, &precedence_row_value)); + std::string precedence_row_value = + content::EvalJs(web_contents(), kJavaScript).ExtractString(); ValidatePrecedenceValue(precedence_row_value); }
diff --git a/chrome/browser/ui/webui/settings/ash/os_settings_ui.cc b/chrome/browser/ui/webui/settings/ash/os_settings_ui.cc index 7cb3f61..0012546 100644 --- a/chrome/browser/ui/webui/settings/ash/os_settings_ui.cc +++ b/chrome/browser/ui/webui/settings/ash/os_settings_ui.cc
@@ -52,6 +52,11 @@ #include "ui/gfx/native_widget_types.h" #include "ui/webui/color_change_listener/color_change_handler.h" +#if !BUILDFLAG(OPTIMIZE_WEBUI) +#include "chrome/grit/settings_shared_resources.h" +#include "chrome/grit/settings_shared_resources_map.h" +#endif + namespace { class AppManagementDelegate : public AppManagementPageHandler::Delegate { @@ -98,6 +103,12 @@ html_source, base::make_span(kOsSettingsResources, kOsSettingsResourcesSize), IDR_OS_SETTINGS_OS_SETTINGS_V3_HTML); + +#if !BUILDFLAG(OPTIMIZE_WEBUI) + html_source->AddResourcePaths( + base::make_span(kSettingsSharedResources, kSettingsSharedResourcesSize)); +#endif + html_source->DisableTrustedTypesCSP(); html_source->OverrideContentSecurityPolicy( network::mojom::CSPDirectiveName::WorkerSrc,
diff --git a/chrome/browser/ui/webui/settings/settings_ui.cc b/chrome/browser/ui/webui/settings/settings_ui.cc index 4f05153d..c51f52a 100644 --- a/chrome/browser/ui/webui/settings/settings_ui.cc +++ b/chrome/browser/ui/webui/settings/settings_ui.cc
@@ -94,6 +94,11 @@ #include "services/network/public/cpp/features.h" #include "ui/base/interaction/element_identifier.h" +#if !BUILDFLAG(OPTIMIZE_WEBUI) +#include "chrome/grit/settings_shared_resources.h" +#include "chrome/grit/settings_shared_resources_map.h" +#endif + #if BUILDFLAG(IS_WIN) #include "chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_controller_win.h" #include "chrome/browser/safe_browsing/chrome_cleaner/srt_field_trial_win.h" @@ -451,6 +456,11 @@ html_source, base::make_span(kSettingsResources, kSettingsResourcesSize), IDR_SETTINGS_SETTINGS_HTML); +#if !BUILDFLAG(OPTIMIZE_WEBUI) + html_source->AddResourcePaths( + base::make_span(kSettingsSharedResources, kSettingsSharedResourcesSize)); +#endif + AddLocalizedStrings(html_source, profile, web_ui->GetWebContents()); ManagedUIHandler::Initialize(web_ui, html_source);
diff --git a/chrome/browser/ui/webui/side_panel/read_anything/read_anything_page_handler.cc b/chrome/browser/ui/webui/side_panel/read_anything/read_anything_page_handler.cc index 66035f47..0e2fe44 100644 --- a/chrome/browser/ui/webui/side_panel/read_anything/read_anything_page_handler.cc +++ b/chrome/browser/ui/webui/side_panel/read_anything/read_anything_page_handler.cc
@@ -88,6 +88,7 @@ ui::ColorId background_color_id, ui::ColorId separator_color_id, ui::ColorId dropdown_color_id, + ui::ColorId selected_dropdown_color_id, read_anything::mojom::LineSpacing line_spacing, read_anything::mojom::LetterSpacing letter_spacing) { content::WebContents* web_contents = web_ui_->GetWebContents();
diff --git a/chrome/browser/ui/webui/side_panel/read_anything/read_anything_page_handler.h b/chrome/browser/ui/webui/side_panel/read_anything/read_anything_page_handler.h index 5f9ceda..8c0c0816 100644 --- a/chrome/browser/ui/webui/side_panel/read_anything/read_anything_page_handler.h +++ b/chrome/browser/ui/webui/side_panel/read_anything/read_anything_page_handler.h
@@ -73,6 +73,7 @@ ui::ColorId background_color_id, ui::ColorId separator_color_id, ui::ColorId dropdown_color_id, + ui::ColorId selected_dropdown_color_id, read_anything::mojom::LineSpacing line_spacing, read_anything::mojom::LetterSpacing letter_spacing) override; #if BUILDFLAG(ENABLE_SCREEN_AI_SERVICE)
diff --git a/chrome/browser/ui/webui/signin/login_ui_test_utils.cc b/chrome/browser/ui/webui/signin/login_ui_test_utils.cc index ed63ec10..684e5794 100644 --- a/chrome/browser/ui/webui/signin/login_ui_test_utils.cc +++ b/chrome/browser/ui/webui/signin/login_ui_test_utils.cc
@@ -266,21 +266,18 @@ bool IsElementReady(content::WebContents* web_contents, const std::string& element_selector) { - std::string message; std::string find_element_js = base::StringPrintf( "if (document.readyState != 'complete') {" - " window.domAutomationController.send('DocumentNotReady');" + " 'DocumentNotReady';" "} else if (%s == null) {" - " window.domAutomationController.send('NotFound');" + " 'NotFound';" "} else if (%s.hidden) {" - " window.domAutomationController.send('Hidden');" + " 'Hidden';" "} else {" - " window.domAutomationController.send('Ok');" + " 'Ok';" "}", element_selector.c_str(), element_selector.c_str()); - EXPECT_TRUE(content::ExecuteScriptAndExtractString( - web_contents, find_element_js, &message)); - return message == "Ok"; + return content::EvalJs(web_contents, find_element_js).ExtractString() == "Ok"; } #endif // !BUILDFLAG(IS_CHROMEOS_ASH) @@ -418,19 +415,19 @@ }; void WaitUntilUIReady(Browser* browser) { - std::string message; - ASSERT_TRUE(content::ExecuteScriptAndExtractString( - browser->tab_strip_model()->GetActiveWebContents(), - "var handler = function() {" - " window.domAutomationController.send('ready');" - "};" - "if (!document.querySelector('inline-login-app').loading_)" - " handler();" - "else" - " document.querySelector('inline-login-app').authExtHost_" - " .addEventListener('ready', handler);", - &message)); - ASSERT_EQ("ready", message); + ASSERT_EQ("ready", + content::EvalJs( + browser->tab_strip_model()->GetActiveWebContents(), + "new Promise(resolve => {" + " var handler = function() {" + " resolve('ready');" + " };" + " if (!document.querySelector('inline-login-app').loading_)" + " handler();" + " else" + " document.querySelector('inline-login-app').authExtHost_" + " .addEventListener('ready', handler);" + "});")); } void SigninInNewGaiaFlow(content::WebContents* web_contents,
diff --git a/chrome/browser/ui/webui/version/version_ui.cc b/chrome/browser/ui/webui/version/version_ui.cc index d0b6ded..b6b96d2 100644 --- a/chrome/browser/ui/webui/version/version_ui.cc +++ b/chrome/browser/ui/webui/version/version_ui.cc
@@ -17,6 +17,7 @@ #include "base/time/time.h" #include "build/build_config.h" #include "build/chromeos_buildflags.h" +#include "chrome/browser/browser_process_impl.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/webui/version/version_handler.h" #include "chrome/browser/ui/webui/webui_util.h" @@ -29,7 +30,9 @@ #include "components/grit/components_scaled_resources.h" #include "components/strings/grit/components_chromium_strings.h" #include "components/strings/grit/components_strings.h" +#include "components/variations/service/variations_service.h" #include "components/version_info/version_info.h" +#include "components/version_ui/version_handler_helper.h" #include "components/version_ui/version_ui_constants.h" #include "content/public/browser/url_data_source.h" #include "content/public/browser/web_ui.h" @@ -85,6 +88,7 @@ {version_ui::kProfilePathName, IDS_VERSION_UI_PROFILE_PATH}, {version_ui::kVariationsName, IDS_VERSION_UI_VARIATIONS}, {version_ui::kVariationsCmdName, IDS_VERSION_UI_VARIATIONS_CMD}, + {version_ui::kVariationsSeedName, IDS_VERSION_UI_VARIATIONS_SEED_NAME}, #if BUILDFLAG(IS_CHROMEOS_ASH) {version_ui::kARC, IDS_ARC_LABEL}, {version_ui::kPlatform, IDS_PLATFORM_LABEL}, @@ -292,6 +296,13 @@ version_utils::win::GetCohortVersionInfo()); #endif // BUILDFLAG(IS_WIN) + html_source->AddString( + version_ui::kVariationsSeed, + g_browser_process->variations_service() + ? version_ui::SeedTypeToUiString( + g_browser_process->variations_service()->GetSeedType()) + : std::string()); + html_source->AddString(version_ui::kSanitizer, version_info::GetSanitizerList()); }
diff --git a/chrome/browser/web_applications/BUILD.gn b/chrome/browser/web_applications/BUILD.gn index 6d15bea6..1ccfad9 100644 --- a/chrome/browser/web_applications/BUILD.gn +++ b/chrome/browser/web_applications/BUILD.gn
@@ -526,6 +526,8 @@ "test/mock_file_utils_wrapper.h", "test/mock_os_integration_manager.cc", "test/mock_os_integration_manager.h", + "test/os_integration_test_override_impl.cc", + "test/os_integration_test_override_impl.h", "test/service_worker_registration_waiter.cc", "test/service_worker_registration_waiter.h", "test/signed_web_bundle_utils.cc",
diff --git a/chrome/browser/web_applications/commands/install_from_manifest_command_browsertest.cc b/chrome/browser/web_applications/commands/install_from_manifest_command_browsertest.cc index fd0a80f2..e126fd05 100644 --- a/chrome/browser/web_applications/commands/install_from_manifest_command_browsertest.cc +++ b/chrome/browser/web_applications/commands/install_from_manifest_command_browsertest.cc
@@ -12,7 +12,7 @@ #include "build/build_config.h" #include "chrome/browser/ui/web_applications/web_app_controller_browsertest.h" #include "chrome/browser/web_applications/commands/install_from_manifest_command.h" -#include "chrome/browser/web_applications/os_integration/os_integration_test_override.h" +#include "chrome/browser/web_applications/test/os_integration_test_override_impl.h" #include "chrome/browser/web_applications/test/web_app_icon_test_utils.h" #include "chrome/browser/web_applications/test/web_app_install_test_utils.h" #include "chrome/browser/web_applications/web_app_command_manager.h" @@ -38,7 +38,7 @@ { base::ScopedAllowBlockingForTesting allow_blocking; test_override_ = - OsIntegrationTestOverride::OverrideForTesting(base::GetHomeDir()); + OsIntegrationTestOverrideImpl::OverrideForTesting(base::GetHomeDir()); } } @@ -69,7 +69,7 @@ base::flat_set<std::string> GetHostAllowlist() { return {"127.0.0.1"}; } private: - std::unique_ptr<OsIntegrationTestOverride::BlockingRegistration> + std::unique_ptr<OsIntegrationTestOverrideImpl::BlockingRegistration> test_override_; };
diff --git a/chrome/browser/web_applications/commands/os_integration_synchronize_command_unittest.cc b/chrome/browser/web_applications/commands/os_integration_synchronize_command_unittest.cc index f303c8be..c3d8741c 100644 --- a/chrome/browser/web_applications/commands/os_integration_synchronize_command_unittest.cc +++ b/chrome/browser/web_applications/commands/os_integration_synchronize_command_unittest.cc
@@ -11,12 +11,12 @@ #include "base/test/test_future.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/web_applications/os_integration/os_integration_manager.h" -#include "chrome/browser/web_applications/os_integration/os_integration_test_override.h" #include "chrome/browser/web_applications/os_integration/web_app_file_handler_manager.h" #include "chrome/browser/web_applications/os_integration/web_app_protocol_handler_manager.h" #include "chrome/browser/web_applications/os_integration/web_app_shortcut_manager.h" #include "chrome/browser/web_applications/proto/web_app_os_integration_state.pb.h" #include "chrome/browser/web_applications/test/fake_web_app_provider.h" +#include "chrome/browser/web_applications/test/os_integration_test_override_impl.h" #include "chrome/browser/web_applications/test/web_app_install_test_utils.h" #include "chrome/browser/web_applications/test/web_app_test.h" #include "chrome/browser/web_applications/test/web_app_test_utils.h" @@ -59,7 +59,7 @@ { base::ScopedAllowBlockingForTesting allow_blocking; test_override_ = - OsIntegrationTestOverride::OverrideForTesting(base::GetHomeDir()); + OsIntegrationTestOverrideImpl::OverrideForTesting(base::GetHomeDir()); } provider_ = FakeWebAppProvider::Get(profile()); @@ -120,7 +120,7 @@ private: raw_ptr<FakeWebAppProvider> provider_; base::test::ScopedFeatureList scoped_feature_list_; - std::unique_ptr<OsIntegrationTestOverride::BlockingRegistration> + std::unique_ptr<OsIntegrationTestOverrideImpl::BlockingRegistration> test_override_; };
diff --git a/chrome/browser/web_applications/commands/update_protocol_handler_approval_command_browsertest.cc b/chrome/browser/web_applications/commands/update_protocol_handler_approval_command_browsertest.cc index b6cb3ab..5c8506b5 100644 --- a/chrome/browser/web_applications/commands/update_protocol_handler_approval_command_browsertest.cc +++ b/chrome/browser/web_applications/commands/update_protocol_handler_approval_command_browsertest.cc
@@ -9,7 +9,7 @@ #include "build/build_config.h" #include "build/chromeos_buildflags.h" #include "chrome/browser/ui/web_applications/web_app_controller_browsertest.h" -#include "chrome/browser/web_applications/os_integration/os_integration_test_override.h" +#include "chrome/browser/web_applications/test/os_integration_test_override_impl.h" #include "chrome/browser/web_applications/test/web_app_install_test_utils.h" #include "chrome/browser/web_applications/test/web_app_test_utils.h" #include "chrome/browser/web_applications/web_app_command_scheduler.h" @@ -46,7 +46,7 @@ { base::ScopedAllowBlockingForTesting allow_blocking; test_override_ = - OsIntegrationTestOverride::OverrideForTesting(base::GetHomeDir()); + OsIntegrationTestOverrideImpl::OverrideForTesting(base::GetHomeDir()); } WebAppControllerBrowserTest::SetUpOnMainThread(); } @@ -128,7 +128,7 @@ private: base::test::ScopedFeatureList scoped_feature_list_; - std::unique_ptr<OsIntegrationTestOverride::BlockingRegistration> + std::unique_ptr<OsIntegrationTestOverrideImpl::BlockingRegistration> test_override_; }; @@ -154,9 +154,10 @@ if (AreProtocolsRegisteredWithOs()) { // Installation registers the protocol handlers. - EXPECT_THAT(GetOsIntegrationTestOverride()->protocol_scheme_registrations(), - testing::ElementsAre(std::make_tuple( - app_id, std::vector({protocol_handler.protocol})))); + EXPECT_THAT( + OsIntegrationTestOverrideImpl::Get()->protocol_scheme_registrations(), + testing::ElementsAre( + std::make_tuple(app_id, std::vector({protocol_handler.protocol})))); } } @@ -190,9 +191,10 @@ if (AreProtocolsRegisteredWithOs()) { // Since they were already registered, no work needed to register them // again. - EXPECT_THAT(GetOsIntegrationTestOverride()->protocol_scheme_registrations(), - testing::ElementsAre(std::make_tuple( - app_id, std::vector({protocol_handler.protocol})))); + EXPECT_THAT( + OsIntegrationTestOverrideImpl::Get()->protocol_scheme_registrations(), + testing::ElementsAre( + std::make_tuple(app_id, std::vector({protocol_handler.protocol})))); } } @@ -231,9 +233,10 @@ if (AreProtocolsRegisteredWithOs()) { // Since they were already registered, no work needed to register them // again. - EXPECT_THAT(GetOsIntegrationTestOverride()->protocol_scheme_registrations(), - testing::ElementsAre(std::make_tuple( - app_id, std::vector({protocol_handler.protocol})))); + EXPECT_THAT( + OsIntegrationTestOverrideImpl::Get()->protocol_scheme_registrations(), + testing::ElementsAre( + std::make_tuple(app_id, std::vector({protocol_handler.protocol})))); } } @@ -266,7 +269,7 @@ if (AreProtocolsRegisteredWithOs()) { // They should be registered on first install, then removed on disallow. EXPECT_THAT( - GetOsIntegrationTestOverride()->protocol_scheme_registrations(), + OsIntegrationTestOverrideImpl::Get()->protocol_scheme_registrations(), testing::ElementsAre( std::make_tuple(app_id, std::vector({protocol_handler.protocol})), std::make_tuple(app_id, std::vector<std::string>()))); @@ -309,7 +312,7 @@ // the 2nd command run with the same inputs, this should not change because // OS integration does not re-run again. EXPECT_THAT( - GetOsIntegrationTestOverride()->protocol_scheme_registrations(), + OsIntegrationTestOverrideImpl::Get()->protocol_scheme_registrations(), testing::ElementsAre( std::make_tuple(app_id, std::vector({protocol_handler.protocol})), std::make_tuple(app_id, std::vector<std::string>()))); @@ -353,7 +356,7 @@ if (AreProtocolsRegisteredWithOs()) { // They should be registered on first install, then removed on disallow. EXPECT_THAT( - GetOsIntegrationTestOverride()->protocol_scheme_registrations(), + OsIntegrationTestOverrideImpl::Get()->protocol_scheme_registrations(), testing::ElementsAre( std::make_tuple(app_id, std::vector({protocol_handler.protocol})), std::make_tuple(app_id, std::vector<std::string>()))); @@ -398,7 +401,7 @@ if (AreProtocolsRegisteredWithOs()) { EXPECT_THAT( - GetOsIntegrationTestOverride()->protocol_scheme_registrations(), + OsIntegrationTestOverrideImpl::Get()->protocol_scheme_registrations(), testing::ElementsAre( std::make_tuple(app_id, std::vector({protocol_handler.protocol})), std::make_tuple(app_id, std::vector<std::string>()), @@ -447,7 +450,7 @@ // added back when removed from the disallowed list. if (AreProtocolsRegisteredWithOs()) { EXPECT_THAT( - GetOsIntegrationTestOverride()->protocol_scheme_registrations(), + OsIntegrationTestOverrideImpl::Get()->protocol_scheme_registrations(), testing::ElementsAre( std::make_tuple(app_id, std::vector({protocol_handler.protocol})), std::make_tuple(app_id, std::vector<std::string>()), @@ -495,9 +498,10 @@ // They should be registered on first install and not modified on addition or // removal from the allowed list. if (AreProtocolsRegisteredWithOs()) { - EXPECT_THAT(GetOsIntegrationTestOverride()->protocol_scheme_registrations(), - testing::ElementsAre(std::make_tuple( - app_id, std::vector({protocol_handler.protocol})))); + EXPECT_THAT( + OsIntegrationTestOverrideImpl::Get()->protocol_scheme_registrations(), + testing::ElementsAre( + std::make_tuple(app_id, std::vector({protocol_handler.protocol})))); } }
diff --git a/chrome/browser/web_applications/os_integration/file_handling_sub_manager_unittest.cc b/chrome/browser/web_applications/os_integration/file_handling_sub_manager_unittest.cc index d148786..1b5bdb5 100644 --- a/chrome/browser/web_applications/os_integration/file_handling_sub_manager_unittest.cc +++ b/chrome/browser/web_applications/os_integration/file_handling_sub_manager_unittest.cc
@@ -14,10 +14,10 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/browser/web_applications/os_integration/file_handling_sub_manager.h" #include "chrome/browser/web_applications/os_integration/os_integration_manager.h" -#include "chrome/browser/web_applications/os_integration/os_integration_test_override.h" #include "chrome/browser/web_applications/os_integration/web_app_file_handler_registration.h" #include "chrome/browser/web_applications/proto/web_app_os_integration_state.pb.h" #include "chrome/browser/web_applications/test/fake_web_app_provider.h" +#include "chrome/browser/web_applications/test/os_integration_test_override_impl.h" #include "chrome/browser/web_applications/test/web_app_install_test_utils.h" #include "chrome/browser/web_applications/test/web_app_test.h" #include "chrome/browser/web_applications/test/web_app_test_utils.h" @@ -48,7 +48,7 @@ { base::ScopedAllowBlockingForTesting allow_blocking; test_override_ = - OsIntegrationTestOverride::OverrideForTesting(base::GetHomeDir()); + OsIntegrationTestOverrideImpl::OverrideForTesting(base::GetHomeDir()); } InitScopedFeatureList(scoped_feature_list_); @@ -107,7 +107,7 @@ protected: WebAppProvider& provider() { return *provider_; } - scoped_refptr<OsIntegrationTestOverride> test_override() { + scoped_refptr<OsIntegrationTestOverrideImpl> test_override() { return test_override_->test_override; } @@ -126,7 +126,7 @@ raw_ptr<FakeWebAppProvider> provider_; base::test::ScopedFeatureList scoped_feature_list_; - std::unique_ptr<OsIntegrationTestOverride::BlockingRegistration> + std::unique_ptr<OsIntegrationTestOverrideImpl::BlockingRegistration> test_override_; };
diff --git a/chrome/browser/web_applications/os_integration/os_integration_test_override.cc b/chrome/browser/web_applications/os_integration/os_integration_test_override.cc index 2bfe513..082f9a7 100644 --- a/chrome/browser/web_applications/os_integration/os_integration_test_override.cc +++ b/chrome/browser/web_applications/os_integration/os_integration_test_override.cc
@@ -4,88 +4,25 @@ #include "chrome/browser/web_applications/os_integration/os_integration_test_override.h" -#include <codecvt> -#include <map> -#include <memory> #include <ostream> #include <string> -#include <tuple> #include <vector> -#include "base/containers/contains.h" -#include "base/containers/span.h" -#include "base/files/file_enumerator.h" +#include "base/check_is_test.h" #include "base/files/file_path.h" -#include "base/files/file_util.h" -#include "base/files/scoped_temp_dir.h" -#include "base/functional/callback_helpers.h" #include "base/memory/ref_counted.h" +#include "base/memory/scoped_refptr.h" #include "base/no_destructor.h" -#include "base/run_loop.h" -#include "base/strings/string_util.h" -#include "base/synchronization/lock.h" -#include "base/threading/thread_restrictions.h" -#include "base/types/expected.h" #include "build/build_config.h" -#include "chrome/browser/profiles/profile.h" -#include "chrome/browser/web_applications/os_integration/web_app_file_handler_registration.h" -#include "chrome/browser/web_applications/web_app.h" -#include "chrome/browser/web_applications/web_app_icon_generator.h" -#include "chrome/browser/web_applications/web_app_icon_manager.h" #include "chrome/browser/web_applications/web_app_id.h" -#include "chrome/browser/web_applications/web_app_install_info.h" -#include "chrome/browser/web_applications/web_app_provider.h" -#include "third_party/abseil-cpp/absl/types/optional.h" -#include "third_party/skia/include/core/SkBitmap.h" -#include "third_party/skia/include/core/SkColor.h" - -#if BUILDFLAG(IS_MAC) -#include <ImageIO/ImageIO.h> - -#include "base/files/scoped_temp_dir.h" -#include "base/mac/foundation_util.h" -#include "base/mac/scoped_cftyperef.h" -#include "chrome/browser/shell_integration.h" -#include "chrome/browser/web_applications/app_shim_registry_mac.h" -#include "net/base/filename_util.h" -#import "skia/ext/skia_utils_mac.h" -#endif - -#if BUILDFLAG(IS_WIN) -#include <windows.h> - -#include <shellapi.h> -#include "base/command_line.h" -#include "base/containers/contains.h" -#include "base/containers/flat_map.h" -#include "base/containers/flat_set.h" -#include "base/strings/strcat.h" -#include "base/strings/string_split.h" -#include "base/strings/stringprintf.h" -#include "base/strings/utf_string_conversions.h" -#include "base/win/registry.h" -#include "base/win/scoped_gdi_object.h" -#include "base/win/shortcut.h" -#include "base/win/windows_types.h" -#include "chrome/browser/web_applications/os_integration/web_app_handler_registration_utils_win.h" -#include "chrome/browser/web_applications/os_integration/web_app_uninstallation_via_os_settings_registration.h" -#include "chrome/browser/web_applications/web_app_helpers.h" -#include "chrome/browser/win/jumplist_updater.h" -#include "chrome/common/chrome_switches.h" -#include "chrome/install_static/install_util.h" -#include "chrome/installer/util/shell_util.h" -#include "third_party/re2/src/re2/re2.h" -#include "ui/gfx/icon_util.h" -#endif namespace web_app { - namespace { struct OsIntegrationTestOverrideState { base::Lock lock; - raw_ptr<OsIntegrationTestOverride> global_os_integration_test_override - GUARDED_BY(lock) = nullptr; + scoped_refptr<OsIntegrationTestOverride> global_os_integration_test_override + GUARDED_BY(lock); }; OsIntegrationTestOverrideState& @@ -94,703 +31,34 @@ g_os_integration_test_override; return *g_os_integration_test_override.get(); } - -std::string GetAllFilesInDir(const base::FilePath& file_path) { - std::vector<std::string> files_as_strs; - base::FileEnumerator files(file_path, true, base::FileEnumerator::FILES); - for (base::FilePath current = files.Next(); !current.empty(); - current = files.Next()) { - files_as_strs.push_back(current.AsUTF8Unsafe()); - } - return base::JoinString(base::make_span(files_as_strs), "\n "); -} - -#if BUILDFLAG(IS_WIN) -base::FilePath GetShortcutProfile(base::FilePath shortcut_path) { - base::FilePath shortcut_profile; - std::wstring cmd_line_string; - if (base::win::ResolveShortcut(shortcut_path, nullptr, &cmd_line_string)) { - base::CommandLine shortcut_cmd_line = - base::CommandLine::FromString(L"program " + cmd_line_string); - shortcut_profile = - shortcut_cmd_line.GetSwitchValuePath(switches::kProfileDirectory); - } - return shortcut_profile; -} - -std::vector<std::wstring> GetFileExtensionsForProgId( - const std::wstring& file_handler_prog_id) { - const std::wstring prog_id_path = - base::StrCat({ShellUtil::kRegClasses, L"\\", file_handler_prog_id}); - - // Get list of handled file extensions from value FileExtensions at - // HKEY_CURRENT_USER\Software\Classes\<file_handler_prog_id>. - base::win::RegKey file_extensions_key(HKEY_CURRENT_USER, prog_id_path.c_str(), - KEY_QUERY_VALUE); - std::wstring handled_file_extensions; - LONG result = file_extensions_key.ReadValue(L"FileExtensions", - &handled_file_extensions); - CHECK_EQ(result, ERROR_SUCCESS); - - return base::SplitString(handled_file_extensions, std::wstring(L";"), - base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); -} -#endif - -#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) -// Performs a blocking read of app icons from the disk. -SkColor IconManagerReadIconTopLeftColorForSize(WebAppIconManager& icon_manager, - const AppId& app_id, - SquareSizePx size_px) { - SkColor result = SK_ColorTRANSPARENT; - if (!icon_manager.HasIcons(app_id, IconPurpose::ANY, {size_px})) { - return result; - } - base::RunLoop run_loop; - icon_manager.ReadIcons( - app_id, IconPurpose::ANY, {size_px}, - base::BindOnce( - [](base::RunLoop* run_loop, SkColor* result, SquareSizePx size_px, - std::map<SquareSizePx, SkBitmap> icon_bitmaps) { - CHECK(base::Contains(icon_bitmaps, size_px)); - *result = icon_bitmaps.at(size_px).getColor(0, 0); - run_loop->Quit(); - }, - &run_loop, &result, size_px)); - run_loop.Run(); - return result; -} -#endif - } // namespace -OsIntegrationTestOverride::BlockingRegistration::BlockingRegistration() = - default; -OsIntegrationTestOverride::BlockingRegistration::~BlockingRegistration() { - base::ScopedAllowBlockingForTesting blocking; - base::RunLoop wait_until_destruction_loop; - // Lock the global state. - { - auto& global_state = GetMutableOsIntegrationTestOverrideStateForTesting(); - base::AutoLock state_lock(global_state.lock); - CHECK_EQ(global_state.global_os_integration_test_override, - test_override.get()); +// static +const scoped_refptr<OsIntegrationTestOverride>& +OsIntegrationTestOverride::Get() { + auto& state = GetMutableOsIntegrationTestOverrideStateForTesting(); + base::AutoLock state_lock(state.lock); + return state.global_os_integration_test_override; +} - // Set the destruction closure for the scoped override object. - CHECK(!test_override->on_destruction_) - << "Cannot have multiple registrations at the same time."; - test_override->on_destruction_.ReplaceClosure( - wait_until_destruction_loop.QuitClosure()); +OsIntegrationTestOverride::OsIntegrationTestOverride() = default; +OsIntegrationTestOverride::~OsIntegrationTestOverride() = default; - // Unregister the override so new handles cannot be acquired. - global_state.global_os_integration_test_override = nullptr; - } - - // Release the override & wait until all references are released. - // Note: The `test_override` MUST be released before waiting on the run - // loop, as then it will hang forever. - test_override.reset(); - wait_until_destruction_loop.Run(); +OsIntegrationTestOverrideImpl* +OsIntegrationTestOverride::AsOsIntegrationTestOverrideImpl() { + CHECK_IS_TEST(); + return nullptr; } // static -std::unique_ptr<OsIntegrationTestOverride::BlockingRegistration> -OsIntegrationTestOverride::OverrideForTesting(const base::FilePath& base_path) { +void OsIntegrationTestOverride::SetForTesting( + scoped_refptr<OsIntegrationTestOverride> override) { + CHECK_IS_TEST(); auto& state = GetMutableOsIntegrationTestOverrideStateForTesting(); base::AutoLock state_lock(state.lock); - CHECK(!state.global_os_integration_test_override) - << "Cannot have multiple registrations at the same time."; - auto test_override = - base::WrapRefCounted(new OsIntegrationTestOverride(base_path)); - state.global_os_integration_test_override = test_override.get(); - - std::unique_ptr<BlockingRegistration> registration = - std::make_unique<BlockingRegistration>(); - registration->test_override = test_override; - return registration; -} - -bool OsIntegrationTestOverride::IsRunOnOsLoginEnabled( - Profile* profile, - const AppId& app_id, - const std::string& app_name) { -#if BUILDFLAG(IS_LINUX) - std::string shortcut_filename = - "chrome-" + app_id + "-" + profile->GetBaseName().value() + ".desktop"; - return base::PathExists(startup().Append(shortcut_filename)); -#elif BUILDFLAG(IS_WIN) - base::FilePath startup_shortcut_path = - GetShortcutPath(profile, startup(), app_id, app_name); - return base::PathExists(startup_shortcut_path); -#elif BUILDFLAG(IS_MAC) - std::string shortcut_filename = app_name + ".app"; - base::FilePath app_shortcut_path = - chrome_apps_folder().Append(shortcut_filename); - return startup_enabled_[app_shortcut_path]; -#else - NOTREACHED() << "Not implemented on ChromeOS/Fuchsia "; - return true; -#endif -} - -bool OsIntegrationTestOverride::IsFileExtensionHandled( - Profile* profile, - const AppId& app_id, - std::string app_name, - std::string file_extension) { - base::ScopedAllowBlockingForTesting allow_blocking; - bool is_file_handled = false; -#if BUILDFLAG(IS_WIN) - const std::wstring prog_id = GetProgIdForApp(profile->GetPath(), app_id); - const std::vector<std::wstring> file_handler_prog_ids = - ShellUtil::GetFileHandlerProgIdsForAppId(prog_id); - const std::wstring extension = base::UTF8ToWide(file_extension); - base::win::RegKey key; - for (const auto& file_handler_prog_id : file_handler_prog_ids) { - const std::vector<std::wstring> supported_file_extensions = - GetFileExtensionsForProgId(file_handler_prog_id); - if (base::Contains(supported_file_extensions, extension)) { - const std::wstring reg_key = std::wstring(ShellUtil::kRegClasses) + - base::FilePath::kSeparators[0] + extension + - base::FilePath::kSeparators[0] + - ShellUtil::kRegOpenWithProgids; - LONG result = key.Open(HKEY_CURRENT_USER, reg_key.data(), KEY_READ); - CHECK_EQ(ERROR_SUCCESS, result); - return key.HasValue(file_handler_prog_id.data()); - } - } -#elif BUILDFLAG(IS_MAC) - const base::FilePath test_file_path = - chrome_apps_folder().AppendASCII("test" + file_extension); - const base::File test_file( - test_file_path, base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE); - const GURL test_file_url = net::FilePathToFileURL(test_file_path); - base::FilePath app_path = - GetShortcutPath(profile, chrome_apps_folder(), app_id, app_name); - is_file_handled = - shell_integration::CanApplicationHandleURL(app_path, test_file_url); - base::DeleteFile(test_file_path); -#elif BUILDFLAG(IS_LINUX) - base::FilePath user_applications_dir = - applications_dir().Append("applications"); - bool database_update_called = false; - for (const LinuxFileRegistration& command : linux_file_registration()) { - if (base::Contains(command.xdg_command, app_id) && - base::Contains(command.xdg_command, - profile->GetPath().BaseName().value())) { - if (base::StartsWith(command.xdg_command, "xdg-mime install")) { - is_file_handled = base::Contains(command.file_contents, - "\"*" + file_extension + "\""); - } else { - CHECK(base::StartsWith(command.xdg_command, "xdg-mime uninstall")) - << command.xdg_command; - is_file_handled = false; - } - } - - // Verify if the mimeinfo.cache is also updated. See - // web_app_file_handler_registration_linux.cc for more information. - if (base::StartsWith(command.xdg_command, "update-desktop-database")) { - database_update_called = - base::Contains(command.xdg_command, user_applications_dir.value()); - } - } - is_file_handled = is_file_handled && database_update_called; -#endif - return is_file_handled; -} - -absl::optional<SkColor> OsIntegrationTestOverride::GetShortcutIconTopLeftColor( - Profile* profile, - base::FilePath shortcut_dir, - const AppId& app_id, - const std::string& app_name, - SquareSizePx size_px) { -#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) - base::FilePath shortcut_path = - GetShortcutPath(profile, shortcut_dir, app_id, app_name); - if (!base::PathExists(shortcut_path)) { - return absl::nullopt; - } - return GetIconTopLeftColorFromShortcutFile(shortcut_path); -#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) - WebAppProvider* provider = WebAppProvider::GetForLocalAppsUnchecked(profile); - if (!provider) { - return absl::nullopt; - } - return IconManagerReadIconTopLeftColorForSize(provider->icon_manager(), - app_id, size_px); -#else - NOTREACHED() << "Not implemented on Fuchsia"; - return absl::nullopt; -#endif -} - -#if BUILDFLAG(IS_WIN) -void OsIntegrationTestOverride::AddShortcutsMenuJumpListEntryForApp( - const std::wstring& app_user_model_id, - const std::vector<scoped_refptr<ShellLinkItem>>& shell_link_items) { - jump_list_entry_map_[app_user_model_id] = shell_link_items; - shortcut_menu_apps_registered_.emplace(app_user_model_id); -} - -void OsIntegrationTestOverride::DeleteShortcutsMenuJumpListEntryForApp( - const std::wstring& app_user_model_id) { - jump_list_entry_map_.erase(app_user_model_id); - shortcut_menu_apps_registered_.erase(app_user_model_id); -} - -int OsIntegrationTestOverride::GetCountOfShortcutIconsCreated( - const std::wstring& app_user_model_id) { - CHECK(IsShortcutsMenuRegisteredForApp(app_user_model_id)); - return jump_list_entry_map_[app_user_model_id].size(); -} - -std::vector<SkColor> OsIntegrationTestOverride::GetIconColorsForShortcutsMenu( - const std::wstring& app_user_model_id) { - CHECK(IsShortcutsMenuRegisteredForApp(app_user_model_id)); - std::vector<SkColor> icon_colors; - for (auto& shell_link_item : jump_list_entry_map_[app_user_model_id]) { - icon_colors.emplace_back( - ReadColorFromShortcutMenuIcoFile(shell_link_item->icon_path())); - } - return icon_colors; -} - -bool OsIntegrationTestOverride::IsShortcutsMenuRegisteredForApp( - const std::wstring& app_user_model_id) { - return base::Contains(jump_list_entry_map_, app_user_model_id); -} - -base::expected<bool, std::string> -OsIntegrationTestOverride::IsUninstallRegisteredWithOs( - const AppId& app_id, - const std::string& app_name, - Profile* profile) { - constexpr wchar_t kUninstallRegistryKey[] = - L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall"; - - base::win::RegKey uninstall_reg_key; - LONG result = uninstall_reg_key.Open(HKEY_CURRENT_USER, kUninstallRegistryKey, - KEY_READ); - - if (result == ERROR_FILE_NOT_FOUND) { - return base::unexpected( - "Cannot find the uninstall registry key. If a testing hive is being " - "used, then this key needs to be created there on initialization."); - } - - if (result != ERROR_SUCCESS) { - return base::unexpected( - base::StringPrintf("Cannot open the registry key: %ld", result)); - } - - const std::wstring key = - GetUninstallStringKeyForTesting(profile->GetPath(), app_id); - - base::win::RegKey uninstall_reg_entry_key; - result = uninstall_reg_entry_key.Open(uninstall_reg_key.Handle(), key.c_str(), - KEY_READ); - if (result == ERROR_FILE_NOT_FOUND) { - return base::ok(false); - } - - if (result != ERROR_SUCCESS) { - return base::unexpected( - base::StringPrintf("Error opening uninstall key for app: %ld", result)); - } - - std::wstring display_icon_path; - std::wstring display_name; - std::wstring display_version; - std::wstring application_version; - std::wstring publisher; - std::wstring uninstall_string; - DWORD no_repair; - DWORD no_modify; - bool read_success = true; - read_success &= uninstall_reg_entry_key.ReadValue( - L"DisplayIcon", &display_icon_path) == ERROR_SUCCESS; - read_success &= uninstall_reg_entry_key.ReadValue( - L"DisplayName", &display_name) == ERROR_SUCCESS; - read_success &= uninstall_reg_entry_key.ReadValue( - L"DisplayVersion", &display_version) == ERROR_SUCCESS; - read_success &= - uninstall_reg_entry_key.ReadValue(L"ApplicationVersion", - &application_version) == ERROR_SUCCESS; - read_success &= uninstall_reg_entry_key.ReadValue(L"Publisher", &publisher) == - ERROR_SUCCESS; - read_success &= uninstall_reg_entry_key.ReadValue( - L"UninstallString", &uninstall_string) == ERROR_SUCCESS; - read_success &= uninstall_reg_entry_key.ReadValueDW( - L"NoRepair", &no_repair) == ERROR_SUCCESS; - read_success &= uninstall_reg_entry_key.ReadValueDW( - L"NoModify", &no_modify) == ERROR_SUCCESS; - if (!read_success) { - return base::unexpected("Error reading registry values"); - } - - if (display_version != L"1.0" || application_version != L"1.0" || - no_repair != 1 || no_modify != 1 || - publisher != install_static::GetChromeInstallSubDirectory()) { - return base::unexpected("Incorrect static registry data."); - } - - base::FilePath web_app_icon_dir = GetOsIntegrationResourcesDirectoryForApp( - profile->GetPath(), app_id, GURL()); - base::FilePath expected_icon_path = - internals::GetIconFilePath(web_app_icon_dir, base::UTF8ToUTF16(app_name)); - if (expected_icon_path.value() != display_icon_path) { - return base::unexpected(base::StrCat( - {"Invalid icon path ", base::WideToUTF8(display_icon_path), - ", expected ", base::WideToUTF8(expected_icon_path.value())})); - } - if (base::UTF8ToWide(app_name) != display_name) { - return base::unexpected( - base::StrCat({"Invalid display name ", base::WideToUTF8(display_name), - ", expected ", app_name})); - } - std::wstring expected_uninstall_substr = - base::StrCat({L"--uninstall-app-id=", base::UTF8ToWide(app_id)}); - if (!base::Contains(uninstall_string, expected_uninstall_substr)) { - return base::unexpected(base::StrCat({"Could not find uninstall flag: ", - base::WideToUTF8(uninstall_string)})); - } - - return true; -} -#endif - -bool OsIntegrationTestOverride::AreShortcutsMenuRegistered() { - return !shortcut_menu_apps_registered_.empty(); -} - -base::FilePath OsIntegrationTestOverride::GetShortcutPath( - Profile* profile, - base::FilePath shortcut_dir, - const AppId& app_id, - const std::string& app_name) { -#if BUILDFLAG(IS_WIN) - base::FileEnumerator enumerator(shortcut_dir, false, - base::FileEnumerator::FILES); - while (!enumerator.Next().empty()) { - const std::wstring shortcut_filename = - enumerator.GetInfo().GetName().value(); - const std::string narrowed_filename = - base::WideToUTF8(enumerator.GetInfo().GetName().value()); - if (re2::RE2::FullMatch(narrowed_filename, app_name + "(.*).lnk")) { - base::FilePath shortcut_path = shortcut_dir.Append(shortcut_filename); - if (GetShortcutProfile(shortcut_path) == profile->GetBaseName()) { - return shortcut_path; - } - } - } -#elif BUILDFLAG(IS_MAC) - std::string shortcut_filename = app_name + ".app"; - base::FilePath shortcut_path = shortcut_dir.Append(shortcut_filename); - // Exits early if the app id is empty because the verification won't work. - // TODO(crbug.com/1289865): Figure a way to find the profile that has the app - // installed without using app ID. - if (app_id.empty()) { - return shortcut_path; - } - - AppShimRegistry* registry = AppShimRegistry::Get(); - std::set<base::FilePath> app_installed_profiles = - registry->GetInstalledProfilesForApp(app_id); - if (app_installed_profiles.find(profile->GetPath()) != - app_installed_profiles.end()) { - return shortcut_path; - } -#elif BUILDFLAG(IS_LINUX) - std::string shortcut_filename = - "chrome-" + app_id + "-" + profile->GetBaseName().value() + ".desktop"; - base::FilePath shortcut_path = shortcut_dir.Append(shortcut_filename); - if (base::PathExists(shortcut_path)) { - return shortcut_path; - } -#endif - return base::FilePath(); -} - -bool OsIntegrationTestOverride::IsShortcutCreated(Profile* profile, - const AppId& app_id, - const std::string& app_name) { -#if BUILDFLAG(IS_WIN) - base::FilePath desktop_shortcut_path = - GetShortcutPath(profile, desktop(), app_id, app_name); - base::FilePath application_menu_shortcut_path = - GetShortcutPath(profile, application_menu(), app_id, app_name); - return (base::PathExists(desktop_shortcut_path) && - base::PathExists(application_menu_shortcut_path)); -#elif BUILDFLAG(IS_MAC) - base::FilePath app_shortcut_path = - GetShortcutPath(profile, chrome_apps_folder(), app_id, app_name); - return base::PathExists(app_shortcut_path); -#elif BUILDFLAG(IS_LINUX) - base::FilePath desktop_shortcut_path = - GetShortcutPath(profile, desktop(), app_id, app_name); - return base::PathExists(desktop_shortcut_path); -#else - NOTREACHED() << "Not implemented on ChromeOS/Fuchsia "; - return true; -#endif -} - -bool OsIntegrationTestOverride::SimulateDeleteShortcutsByUser( - Profile* profile, - const AppId& app_id, - const std::string& app_name) { -#if BUILDFLAG(IS_WIN) - base::FilePath desktop_shortcut_path = - GetShortcutPath(profile, desktop(), app_id, app_name); - CHECK(base::PathExists(desktop_shortcut_path)); - base::FilePath app_menu_shortcut_path = - GetShortcutPath(profile, application_menu(), app_id, app_name); - CHECK(base::PathExists(app_menu_shortcut_path)); - return base::DeleteFile(desktop_shortcut_path) && - base::DeleteFile(app_menu_shortcut_path); -#elif BUILDFLAG(IS_MAC) - base::FilePath app_folder_shortcut_path = - GetShortcutPath(profile, chrome_apps_folder(), app_id, app_name); - CHECK(base::PathExists(app_folder_shortcut_path)); - return base::DeletePathRecursively(app_folder_shortcut_path); -#elif BUILDFLAG(IS_LINUX) - base::FilePath desktop_shortcut_path = - GetShortcutPath(profile, desktop(), app_id, app_name); - LOG(INFO) << desktop_shortcut_path; - CHECK(base::PathExists(desktop_shortcut_path)); - return base::DeleteFile(desktop_shortcut_path); -#else - NOTREACHED() << "Not implemented on ChromeOS/Fuchsia "; - return true; -#endif -} - -bool OsIntegrationTestOverride::ForceDeleteAllShortcuts() { -#if BUILDFLAG(IS_WIN) - return DeleteDesktopDirOnWin() && DeleteApplicationMenuDirOnWin(); -#elif BUILDFLAG(IS_MAC) - return DeleteChromeAppsDir(); -#elif BUILDFLAG(IS_LINUX) - return DeleteDesktopDirOnLinux(); -#else - NOTREACHED() << "Not implemented on ChromeOS/Fuchsia "; - return true; -#endif -} - -#if BUILDFLAG(IS_WIN) -bool OsIntegrationTestOverride::DeleteDesktopDirOnWin() { - if (desktop_.IsValid()) { - return desktop_.Delete(); - } else { - return false; - } -} - -bool OsIntegrationTestOverride::DeleteApplicationMenuDirOnWin() { - if (application_menu_.IsValid()) { - return application_menu_.Delete(); - } else { - return false; - } -} - -#elif BUILDFLAG(IS_MAC) -bool OsIntegrationTestOverride::DeleteChromeAppsDir() { - if (chrome_apps_folder_.IsValid()) { - return chrome_apps_folder_.Delete(); - } else { - return false; - } -} - -void OsIntegrationTestOverride::EnableOrDisablePathOnLogin( - const base::FilePath& file_path, - bool enable_on_login) { - startup_enabled_[file_path] = enable_on_login; -} - -#elif BUILDFLAG(IS_LINUX) -bool OsIntegrationTestOverride::DeleteDesktopDirOnLinux() { - if (desktop_.IsValid()) { - return desktop_.Delete(); - } else { - return false; - } -} -#endif - -void OsIntegrationTestOverride::RegisterProtocolSchemes( - const AppId& app_id, - std::vector<std::string> protocols) { - protocol_scheme_registrations_.emplace_back(app_id, std::move(protocols)); -} - -OsIntegrationTestOverride::OsIntegrationTestOverride( - const base::FilePath& base_path) { - // Initialize all directories used. The success & the CHECK are separated to - // ensure that these function calls occur on release builds. - if (!base_path.empty()) { -#if BUILDFLAG(IS_WIN) - bool success = desktop_.CreateUniqueTempDirUnderPath(base_path); - CHECK(success); - success = application_menu_.CreateUniqueTempDirUnderPath(base_path); - CHECK(success); - success = quick_launch_.CreateUniqueTempDirUnderPath(base_path); - CHECK(success); - success = startup_.CreateUniqueTempDirUnderPath(base_path); - CHECK(success); -#elif BUILDFLAG(IS_MAC) - bool success = chrome_apps_folder_.CreateUniqueTempDirUnderPath(base_path); - CHECK(success); -#elif BUILDFLAG(IS_LINUX) - bool success = desktop_.CreateUniqueTempDirUnderPath(base_path); - CHECK(success); - success = startup_.CreateUniqueTempDirUnderPath(base_path); - CHECK(success); - success = applications_dir_.CreateUniqueTempDirUnderPath(base_path); - CHECK(success); -#endif - } else { -#if BUILDFLAG(IS_WIN) - bool success = desktop_.CreateUniqueTempDir(); - CHECK(success); - success = application_menu_.CreateUniqueTempDir(); - CHECK(success); - success = quick_launch_.CreateUniqueTempDir(); - CHECK(success); - success = startup_.CreateUniqueTempDir(); - CHECK(success); -#elif BUILDFLAG(IS_MAC) - bool success = chrome_apps_folder_.CreateUniqueTempDir(); - CHECK(success); -#elif BUILDFLAG(IS_LINUX) - bool success = desktop_.CreateUniqueTempDir(); - CHECK(success); - success = startup_.CreateUniqueTempDir(); - CHECK(success); - success = applications_dir_.CreateUniqueTempDir(); - CHECK(success); -#endif - } - -#if BUILDFLAG(IS_LINUX) - auto callback = base::BindRepeating([](base::FilePath filename_in, - std::string xdg_command, - std::string file_contents) { - auto test_override = GetOsIntegrationTestOverride(); - CHECK(test_override); - LinuxFileRegistration file_registration = LinuxFileRegistration(); - file_registration.file_name = filename_in; - file_registration.xdg_command = xdg_command; - file_registration.file_contents = file_contents; - test_override->linux_file_registration_.push_back(file_registration); - return true; - }); - SetUpdateMimeInfoDatabaseOnLinuxCallbackForTesting(std::move(callback)); -#endif -} - -OsIntegrationTestOverride::~OsIntegrationTestOverride() { - std::vector<base::ScopedTempDir*> directories; -#if BUILDFLAG(IS_WIN) - directories = {&desktop_, &application_menu_, &quick_launch_, &startup_}; -#elif BUILDFLAG(IS_MAC) - directories = {&chrome_apps_folder_}; - // Checks and cleans up possible hidden files in directories. - std::vector<std::string> hidden_files{"Icon\r", ".localized"}; - for (base::ScopedTempDir* dir : directories) { - if (dir->IsValid()) { - for (auto& f : hidden_files) { - base::FilePath path = dir->GetPath().Append(f); - if (base::PathExists(path)) { - base::DeletePathRecursively(path); - } - } - } - } -#elif BUILDFLAG(IS_LINUX) - // Reset the file handling callback. - SetUpdateMimeInfoDatabaseOnLinuxCallbackForTesting( - UpdateMimeInfoDatabaseOnLinuxCallback()); - directories = {&desktop_, &applications_dir_}; -#endif - for (base::ScopedTempDir* dir : directories) { - if (!dir->IsValid()) { - continue; - } - CHECK(base::IsDirectoryEmpty(dir->GetPath())) - << "Directory not empty: " << dir->GetPath().AsUTF8Unsafe() - << ". Please uninstall all webapps that have been installed while " - "shortcuts were overriden. Contents:\n" - << GetAllFilesInDir(dir->GetPath()); - } -} - -#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) -SkColor OsIntegrationTestOverride::GetIconTopLeftColorFromShortcutFile( - const base::FilePath& shortcut_path) { - CHECK(base::PathExists(shortcut_path)); -#if BUILDFLAG(IS_MAC) - base::FilePath icon_path = - shortcut_path.AppendASCII("Contents/Resources/app.icns"); - base::ScopedCFTypeRef<CFDictionaryRef> empty_dict( - CFDictionaryCreate(nullptr, nullptr, nullptr, 0, nullptr, nullptr)); - base::ScopedCFTypeRef<CFURLRef> url = base::mac::FilePathToCFURL(icon_path); - base::ScopedCFTypeRef<CGImageSourceRef> source( - CGImageSourceCreateWithURL(url, nullptr)); - if (!source) { - return 0; - } - // Get the first icon in the .icns file (index 0) - base::ScopedCFTypeRef<CGImageRef> cg_image( - CGImageSourceCreateImageAtIndex(source, 0, empty_dict)); - if (!cg_image) { - return 0; - } - SkBitmap bitmap = skia::CGImageToSkBitmap(cg_image); - if (bitmap.empty()) { - return 0; - } - return bitmap.getColor(0, 0); -#elif BUILDFLAG(IS_WIN) - SHFILEINFO file_info = {0}; - if (SHGetFileInfo(shortcut_path.value().c_str(), FILE_ATTRIBUTE_NORMAL, - &file_info, sizeof(file_info), - SHGFI_ICON | 0 | SHGFI_USEFILEATTRIBUTES)) { - const SkBitmap bitmap = IconUtil::CreateSkBitmapFromHICON(file_info.hIcon); - if (bitmap.empty()) { - return 0; - } - return bitmap.getColor(0, 0); - } else { - return 0; - } -#endif -} -#endif - -#if BUILDFLAG(IS_WIN) -SkColor OsIntegrationTestOverride::ReadColorFromShortcutMenuIcoFile( - const base::FilePath& file_path) { - HICON icon = static_cast<HICON>( - LoadImage(NULL, file_path.value().c_str(), IMAGE_ICON, 32, 32, - LR_LOADTRANSPARENT | LR_LOADFROMFILE)); - base::win::ScopedHICON scoped_icon(icon); - SkBitmap output_image = - IconUtil::CreateSkBitmapFromHICON(scoped_icon.get(), gfx::Size(32, 32)); - SkColor color = output_image.getColor(output_image.dimensions().width() / 2, - output_image.dimensions().height() / 2); - return color; -} -#endif - -scoped_refptr<OsIntegrationTestOverride> GetOsIntegrationTestOverride() { - auto& state = GetMutableOsIntegrationTestOverrideStateForTesting(); - base::AutoLock state_lock(state.lock); - return base::WrapRefCounted(state.global_os_integration_test_override.get()); + CHECK(!(override && state.global_os_integration_test_override)) + << "Cannot set a test override when one already exists"; + state.global_os_integration_test_override = std::move(override); } } // namespace web_app
diff --git a/chrome/browser/web_applications/os_integration/os_integration_test_override.h b/chrome/browser/web_applications/os_integration/os_integration_test_override.h index 2f6d3377..157e094 100644 --- a/chrome/browser/web_applications/os_integration/os_integration_test_override.h +++ b/chrome/browser/web_applications/os_integration/os_integration_test_override.h
@@ -5,30 +5,14 @@ #ifndef CHROME_BROWSER_WEB_APPLICATIONS_OS_INTEGRATION_OS_INTEGRATION_TEST_OVERRIDE_H_ #define CHROME_BROWSER_WEB_APPLICATIONS_OS_INTEGRATION_OS_INTEGRATION_TEST_OVERRIDE_H_ -#include <map> -#include <memory> #include <string> -#include <tuple> #include <vector> -#include "base/containers/flat_set.h" #include "base/files/file_path.h" -#include "base/files/scoped_temp_dir.h" -#include "base/functional/callback_helpers.h" #include "base/memory/ref_counted.h" -#include "base/types/expected.h" +#include "base/memory/scoped_refptr.h" #include "build/build_config.h" -#include "chrome/browser/web_applications/web_app_icon_generator.h" #include "chrome/browser/web_applications/web_app_id.h" -#include "chrome/browser/web_applications/web_app_install_info.h" -#include "third_party/abseil-cpp/absl/types/optional.h" -#include "third_party/skia/include/core/SkColor.h" - -#if BUILDFLAG(IS_WIN) -#include "base/containers/flat_map.h" -#endif - -class Profile; #if BUILDFLAG(IS_WIN) class ShellLinkItem; @@ -36,13 +20,7 @@ namespace web_app { -#if BUILDFLAG(IS_LINUX) -struct LinuxFileRegistration { - base::FilePath file_name; - std::string xdg_command; - std::string file_contents; -}; -#endif +class OsIntegrationTestOverrideImpl; // This class is used to help test OS integration code and operations running on // trybots. Among other complexities, trybots are often running multiple tests @@ -61,10 +39,12 @@ // verified in a test, then populate metadata in this object about the // final OS call for tests to check. // - If the OS integration CANNOT be fully tested on a trybot (it doesn't work -// or -// messes up the environment), then the presence of this object disables the -// os integration, and information is populated about the final OS call in +// or messes up the environment), then the presence of this object disables +// the os integration, and information is populated about the final OS call in // this class. +// - Note: Using utilities like `RegistryOverrideManager` and +// `ScopedPathOverride` are preferred to having the production code explicitly +// check for the presence of this class & getting information from it. // // This class is used across multiple different sequenced task runners: // - Created on the UI thread. @@ -72,212 +52,68 @@ // - Accessed by the UI thread. // It is up to the user to ensure thread safety of this class through // ordering guarantees. +// +// This base class is built in the non-testing target, allowing production code +// to check for it's existence and iteract with it. The actual implementation is +// in `OsIntegrationTestOverrideImpl`, which testing-only and can thus use +// test-only features. That implementation has further methods for tests to +// check the OS integration state. class OsIntegrationTestOverride : public base::RefCountedThreadSafe<OsIntegrationTestOverride> { public: - using AppProtocolList = - std::vector<std::tuple<AppId, std::vector<std::string>>>; -#if BUILDFLAG(IS_WIN) - using JumpListEntryMap = - base::flat_map<std::wstring, std::vector<scoped_refptr<ShellLinkItem>>>; -#endif - // Destroying this class blocks the thread until all users of - // GetOsIntegrationTestOverride() have completed. - struct BlockingRegistration { - BlockingRegistration(); - ~BlockingRegistration(); + // This will return a nullptr in production code or tests that have not + // created a `OsIntegrationTestOverrideImpl::BlockingRegistration` through + // `OsIntegrationTestOverrideImpl::OverrideForTesting`. + static const scoped_refptr<OsIntegrationTestOverride>& Get(); - scoped_refptr<OsIntegrationTestOverride> test_override; - }; - + OsIntegrationTestOverride(OsIntegrationTestOverride&&) = delete; OsIntegrationTestOverride(const OsIntegrationTestOverride&) = delete; - // Overrides applicable directories for shortcut integration and returns an - // object that: - // 1) Contains the directories. - // 2) Keeps the override active until the object is destroyed. - // 3) DCHECK-fails on destruction if any of the shortcut directories / os - // hooks are NOT cleanup by the test. This ensures that trybots don't have - // old test artifacts on them that can make future tests flaky. - // All installs that occur during the lifetime of the - // OsIntegrationTestOverride MUST be uninstalled before it is - // destroyed. - // The returned value, on destruction, will block until all usages of the - // GetOsIntegrationTestOverride() are destroyed. - static std::unique_ptr<BlockingRegistration> OverrideForTesting( - const base::FilePath& base_path = base::FilePath()); - - // Looks into shortcuts stored for OS integration and returns if run on OS - // login mode is enabled based on the location. This should only be run on - // Windows, Mac and Linux. - bool IsRunOnOsLoginEnabled(Profile* profile, - const AppId& app_id, - const std::string& app_name); - - bool IsFileExtensionHandled(Profile* profile, - const AppId& app_id, - std::string app_name, - std::string file_extension); - - // Reads the icon color for a specific shortcut that has been created. - // For Mac and Win, the shortcut_dir field is mandatory. For all other OSes, - // this can be an empty base::FilePath(). - // For ChromeOS and Linux, the size_px field is mandatory to prevent erroneous - // results. For all other OSes, the field can be skipped. The default value of - // size_px is usually filled up with kLauncherIconSize (see - // chrome/browser/web_applications/web_app_icon_generator.h for more - // information), which is 128. - absl::optional<SkColor> GetShortcutIconTopLeftColor( - Profile* profile, - base::FilePath shortcut_dir, - const AppId& app_id, - const std::string& app_name, - SquareSizePx size_px = icon_size::k128); + // Safe downcasting to the testing implementation. + virtual OsIntegrationTestOverrideImpl* AsOsIntegrationTestOverrideImpl(); #if BUILDFLAG(IS_WIN) // These should not be called from tests, these are automatically // called from production code in testing to set // up OS integration data for shortcuts menu registration and // unregistration. - void AddShortcutsMenuJumpListEntryForApp( + virtual void AddShortcutsMenuJumpListEntryForApp( const std::wstring& app_user_model_id, - const std::vector<scoped_refptr<ShellLinkItem>>& shell_link_items); - void DeleteShortcutsMenuJumpListEntryForApp( - const std::wstring& app_user_model_id); + const std::vector<scoped_refptr<ShellLinkItem>>& shell_link_items) = 0; + virtual void DeleteShortcutsMenuJumpListEntryForApp( + const std::wstring& app_user_model_id) = 0; - std::vector<SkColor> GetIconColorsForShortcutsMenu( - const std::wstring& app_user_model_id); - int GetCountOfShortcutIconsCreated(const std::wstring& app_user_model_id); - bool IsShortcutsMenuRegisteredForApp(const std::wstring& app_user_model_id); - - // Returns true if the given app_id/name/profile is registered with the OS in - // the uninstall menu, and false if it isn't. The unexpected value is a string - // description of the error. - base::expected<bool, std::string> IsUninstallRegisteredWithOs( - const AppId& app_id, - const std::string& app_name, - Profile* profile); -#endif - - bool AreShortcutsMenuRegistered(); - - // Gets the current shortcut path based on a shortcut directory, app_id and - // app_name. This should only be run on Windows, Mac and Linux. - base::FilePath GetShortcutPath(Profile* profile, - base::FilePath shortcut_dir, - const AppId& app_id, - const std::string& app_name); - - // Looks into the current shortcut paths to determine if a shortcut has - // been created or not. This should only be run on Windows, Mac and Linux. - // TODO(crbug.com/1425967): Add PList parsing logic for Mac shortcut checking. - bool IsShortcutCreated(Profile* profile, - const AppId& app_id, - const std::string& app_name); - - // Delete shortcuts stored in the test override for a specific app. This - // should only be run on Windows, Mac and Linux. - bool SimulateDeleteShortcutsByUser(Profile* profile, - const AppId& app_id, - const std::string& app_name); - - // Used to clear all shortcut override paths during tests. This should only be - // run on Windows, Mac and Linux. - bool ForceDeleteAllShortcuts(); - -#if BUILDFLAG(IS_WIN) - bool DeleteDesktopDirOnWin(); - bool DeleteApplicationMenuDirOnWin(); - const base::FilePath& desktop() { return desktop_.GetPath(); } - const base::FilePath& application_menu() { - return application_menu_.GetPath(); - } - const base::FilePath& quick_launch() { return quick_launch_.GetPath(); } - const base::FilePath& startup() { return startup_.GetPath(); } + virtual const base::FilePath& desktop() = 0; + virtual const base::FilePath& application_menu() = 0; + virtual const base::FilePath& quick_launch() = 0; + virtual const base::FilePath& startup() = 0; #elif BUILDFLAG(IS_MAC) - bool DeleteChromeAppsDir(); - bool IsChromeAppsValid() { return chrome_apps_folder_.IsValid(); } - const base::FilePath& chrome_apps_folder() { - return chrome_apps_folder_.GetPath(); - } - void EnableOrDisablePathOnLogin(const base::FilePath& file_path, - bool enable_on_login); + virtual bool IsChromeAppsValid() = 0; + virtual const base::FilePath& chrome_apps_folder() = 0; + virtual void EnableOrDisablePathOnLogin(const base::FilePath& file_path, + bool enable_on_login) = 0; #elif BUILDFLAG(IS_LINUX) - bool DeleteDesktopDirOnLinux(); - const base::FilePath& desktop() { return desktop_.GetPath(); } - const base::FilePath& startup() { return startup_.GetPath(); } - const base::FilePath& applications_dir() { - return applications_dir_.GetPath(); - } - const std::vector<LinuxFileRegistration>& linux_file_registration() { - return linux_file_registration_; - } + virtual const base::FilePath& desktop() = 0; + virtual const base::FilePath& startup() = 0; + virtual const base::FilePath& applications_dir() = 0; #endif // Creates a tuple of app_id to protocols and adds it to the vector // of registered protocols. There can be multiple entries for the same // app_id. - void RegisterProtocolSchemes(const AppId& app_id, - std::vector<std::string> protocols); - const AppProtocolList& protocol_scheme_registrations() { - return protocol_scheme_registrations_; - } + virtual void RegisterProtocolSchemes(const AppId& app_id, + std::vector<std::string> protocols) = 0; - private: + protected: friend class base::RefCountedThreadSafe<OsIntegrationTestOverride>; + friend class OsIntegrationTestOverrideImpl; - explicit OsIntegrationTestOverride(const base::FilePath& base_path); - ~OsIntegrationTestOverride(); + static void SetForTesting(scoped_refptr<OsIntegrationTestOverride> override); -#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) - // Reads an icon file (.ico/.png/.icns) and returns the color at the - // top left position (0,0). - SkColor GetIconTopLeftColorFromShortcutFile( - const base::FilePath& shortcut_path); -#endif - -#if BUILDFLAG(IS_WIN) - SkColor ReadColorFromShortcutMenuIcoFile(const base::FilePath& file_path); -#endif - -#if BUILDFLAG(IS_WIN) - base::ScopedTempDir desktop_; - base::ScopedTempDir application_menu_; - base::ScopedTempDir quick_launch_; - base::ScopedTempDir startup_; - - // Records all ShellLinkItems for a given AppUserModelId for handling - // shortcuts menu registration. - JumpListEntryMap jump_list_entry_map_; - -#elif BUILDFLAG(IS_MAC) - base::ScopedTempDir chrome_apps_folder_; - std::map<base::FilePath, bool> startup_enabled_; - -#elif BUILDFLAG(IS_LINUX) - base::ScopedTempDir desktop_; - base::ScopedTempDir startup_; - base::ScopedTempDir applications_dir_; - std::vector<LinuxFileRegistration> linux_file_registration_; -#endif - - // Records all registration events for a given app id & protocol list. Due to - // simplification on the OS-side, unregistrations are not recorded, and - // instead this list can be checked for an empty registration. - AppProtocolList protocol_scheme_registrations_; - - base::flat_set<std::wstring> shortcut_menu_apps_registered_; - - // |on_destruction_| has it's closure set only once (when BlockingRegistration - // is destroyed) and executed when OsIntegrationTestOverride is destroyed. - // The destructor of BlockingRegistration explicitly sets this closure with a - // global lock, then destroys the object, then waits on the closure, so it is - // thread-compatible. - base::ScopedClosureRunner on_destruction_; + OsIntegrationTestOverride(); + virtual ~OsIntegrationTestOverride() = 0; }; -scoped_refptr<OsIntegrationTestOverride> GetOsIntegrationTestOverride(); - } // namespace web_app #endif // CHROME_BROWSER_WEB_APPLICATIONS_OS_INTEGRATION_OS_INTEGRATION_TEST_OVERRIDE_H_
diff --git a/chrome/browser/web_applications/os_integration/protocol_handling_sub_manager_unittest.cc b/chrome/browser/web_applications/os_integration/protocol_handling_sub_manager_unittest.cc index b7df7ed..edd1ebbd 100644 --- a/chrome/browser/web_applications/os_integration/protocol_handling_sub_manager_unittest.cc +++ b/chrome/browser/web_applications/os_integration/protocol_handling_sub_manager_unittest.cc
@@ -14,12 +14,12 @@ #include "build/chromeos_buildflags.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/web_applications/os_integration/os_integration_manager.h" -#include "chrome/browser/web_applications/os_integration/os_integration_test_override.h" #include "chrome/browser/web_applications/os_integration/web_app_file_handler_manager.h" #include "chrome/browser/web_applications/os_integration/web_app_protocol_handler_manager.h" #include "chrome/browser/web_applications/os_integration/web_app_shortcut_manager.h" #include "chrome/browser/web_applications/proto/web_app_os_integration_state.pb.h" #include "chrome/browser/web_applications/test/fake_web_app_provider.h" +#include "chrome/browser/web_applications/test/os_integration_test_override_impl.h" #include "chrome/browser/web_applications/test/web_app_install_test_utils.h" #include "chrome/browser/web_applications/test/web_app_test.h" #include "chrome/browser/web_applications/test/web_app_test_utils.h" @@ -60,7 +60,7 @@ { base::ScopedAllowBlockingForTesting allow_blocking; test_override_ = - OsIntegrationTestOverride::OverrideForTesting(base::GetHomeDir()); + OsIntegrationTestOverrideImpl::OverrideForTesting(base::GetHomeDir()); } provider_ = FakeWebAppProvider::Get(profile()); @@ -119,7 +119,7 @@ private: raw_ptr<FakeWebAppProvider> provider_; - std::unique_ptr<OsIntegrationTestOverride::BlockingRegistration> + std::unique_ptr<OsIntegrationTestOverrideImpl::BlockingRegistration> test_override_; }; @@ -318,7 +318,7 @@ if (AreProtocolsRegisteredWithOs()) { // Installation registers the protocol handlers. EXPECT_THAT( - GetOsIntegrationTestOverride()->protocol_scheme_registrations(), + OsIntegrationTestOverrideImpl::Get()->protocol_scheme_registrations(), testing::ElementsAre(std::make_tuple( app_id, std::vector({protocol_handler.protocol})))); } @@ -348,10 +348,11 @@ // TODO(crbug.com/1404819): Update tests to verify protocol handling // unregistration as part of update. // There should only be a single value for registration, as unregistration - // is a no-op for GetOsIntegrationTestOverride(). - ASSERT_THAT(GetOsIntegrationTestOverride()->protocol_scheme_registrations(), - testing::ElementsAre(std::make_tuple( - app_id, std::vector({protocol_handler.protocol})))); + // is a no-op for OsIntegrationTestOverrideImpl::Get(). + ASSERT_THAT( + OsIntegrationTestOverrideImpl::Get()->protocol_scheme_registrations(), + testing::ElementsAre( + std::make_tuple(app_id, std::vector({protocol_handler.protocol})))); } } @@ -402,7 +403,7 @@ // TODO(crbug.com/1404819): Update tests to verify protocol handling // unregistration as part of update. ASSERT_THAT( - GetOsIntegrationTestOverride()->protocol_scheme_registrations(), + OsIntegrationTestOverrideImpl::Get()->protocol_scheme_registrations(), testing::ElementsAre( std::make_tuple( app_id, std::vector({protocol_handler_approved.protocol, @@ -453,7 +454,7 @@ #endif if (AreProtocolsRegisteredWithOs()) { ASSERT_THAT( - GetOsIntegrationTestOverride()->protocol_scheme_registrations(), + OsIntegrationTestOverrideImpl::Get()->protocol_scheme_registrations(), testing::ElementsAre(std::make_tuple( app_id, std::vector({protocol_handler.protocol})))); } @@ -487,11 +488,11 @@ // These values are set by the ShortcutHandlingSubManager. #if BUILDFLAG(IS_WIN) ASSERT_THAT( - GetOsIntegrationTestOverride()->protocol_scheme_registrations(), + OsIntegrationTestOverrideImpl::Get()->protocol_scheme_registrations(), testing::IsEmpty()); #else ASSERT_THAT( - GetOsIntegrationTestOverride()->protocol_scheme_registrations(), + OsIntegrationTestOverrideImpl::Get()->protocol_scheme_registrations(), testing::ElementsAre( std::make_tuple(app_id1, std::vector<std::string>()), std::make_tuple(app_id1, std::vector<std::string>())));
diff --git a/chrome/browser/web_applications/os_integration/run_on_os_login_sub_manager_unittest.cc b/chrome/browser/web_applications/os_integration/run_on_os_login_sub_manager_unittest.cc index 55840535..0da213e 100644 --- a/chrome/browser/web_applications/os_integration/run_on_os_login_sub_manager_unittest.cc +++ b/chrome/browser/web_applications/os_integration/run_on_os_login_sub_manager_unittest.cc
@@ -13,10 +13,10 @@ #include "build/buildflag.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/web_applications/os_integration/os_integration_manager.h" -#include "chrome/browser/web_applications/os_integration/os_integration_test_override.h" #include "chrome/browser/web_applications/policy/web_app_policy_manager.h" #include "chrome/browser/web_applications/proto/web_app_os_integration_state.pb.h" #include "chrome/browser/web_applications/test/fake_web_app_provider.h" +#include "chrome/browser/web_applications/test/os_integration_test_override_impl.h" #include "chrome/browser/web_applications/test/web_app_install_test_utils.h" #include "chrome/browser/web_applications/test/web_app_test.h" #include "chrome/browser/web_applications/test/web_app_test_utils.h" @@ -47,7 +47,7 @@ { base::ScopedAllowBlockingForTesting allow_blocking; test_override_ = - OsIntegrationTestOverride::OverrideForTesting(base::GetHomeDir()); + OsIntegrationTestOverrideImpl::OverrideForTesting(base::GetHomeDir()); } provider_ = FakeWebAppProvider::Get(profile()); @@ -114,7 +114,7 @@ private: raw_ptr<FakeWebAppProvider> provider_; - std::unique_ptr<OsIntegrationTestOverride::BlockingRegistration> + std::unique_ptr<OsIntegrationTestOverrideImpl::BlockingRegistration> test_override_; }; @@ -342,7 +342,7 @@ // OS integration should be triggered. if (AreOsIntegrationSubManagersEnabled()) { if (IsRunOnOsLoginExecuteEnabled()) { - ASSERT_FALSE(GetOsIntegrationTestOverride()->IsRunOnOsLoginEnabled( + ASSERT_FALSE(OsIntegrationTestOverrideImpl::Get()->IsRunOnOsLoginEnabled( profile(), app_id, app_name)); } } else { @@ -365,7 +365,7 @@ const proto::WebAppOsIntegrationState& os_integration_state = state.value(); if (AreOsIntegrationSubManagersEnabled()) { if (IsRunOnOsLoginExecuteEnabled()) { - ASSERT_TRUE(GetOsIntegrationTestOverride()->IsRunOnOsLoginEnabled( + ASSERT_TRUE(OsIntegrationTestOverrideImpl::Get()->IsRunOnOsLoginEnabled( profile(), app_id, app_name)); } } else { @@ -397,7 +397,7 @@ const proto::WebAppOsIntegrationState& os_integration_state = state.value(); if (AreOsIntegrationSubManagersEnabled()) { if (IsRunOnOsLoginExecuteEnabled()) { - ASSERT_FALSE(GetOsIntegrationTestOverride()->IsRunOnOsLoginEnabled( + ASSERT_FALSE(OsIntegrationTestOverrideImpl::Get()->IsRunOnOsLoginEnabled( profile(), app_id, app_name)); } } else { @@ -430,7 +430,7 @@ const proto::WebAppOsIntegrationState& os_integration_state = state.value(); if (AreOsIntegrationSubManagersEnabled()) { if (IsRunOnOsLoginExecuteEnabled()) { - ASSERT_TRUE(GetOsIntegrationTestOverride()->IsRunOnOsLoginEnabled( + ASSERT_TRUE(OsIntegrationTestOverrideImpl::Get()->IsRunOnOsLoginEnabled( profile(), app_id, app_name)); } } else { @@ -452,7 +452,7 @@ const proto::WebAppOsIntegrationState& os_integration_state = state.value(); if (AreOsIntegrationSubManagersEnabled()) { if (IsRunOnOsLoginExecuteEnabled()) { - ASSERT_TRUE(GetOsIntegrationTestOverride()->IsRunOnOsLoginEnabled( + ASSERT_TRUE(OsIntegrationTestOverrideImpl::Get()->IsRunOnOsLoginEnabled( profile(), app_id, app_name)); } } else { @@ -471,7 +471,7 @@ updated_state.value(); if (AreOsIntegrationSubManagersEnabled()) { if (IsRunOnOsLoginExecuteEnabled()) { - ASSERT_FALSE(GetOsIntegrationTestOverride()->IsRunOnOsLoginEnabled( + ASSERT_FALSE(OsIntegrationTestOverrideImpl::Get()->IsRunOnOsLoginEnabled( profile(), app_id, app_name)); } } else { @@ -493,7 +493,7 @@ const proto::WebAppOsIntegrationState& os_integration_state = state.value(); if (AreOsIntegrationSubManagersEnabled()) { if (IsRunOnOsLoginExecuteEnabled()) { - ASSERT_TRUE(GetOsIntegrationTestOverride()->IsRunOnOsLoginEnabled( + ASSERT_TRUE(OsIntegrationTestOverrideImpl::Get()->IsRunOnOsLoginEnabled( profile(), app_id, app_name)); } } else { @@ -503,7 +503,7 @@ test::UninstallAllWebApps(profile()); if (AreOsIntegrationSubManagersEnabled()) { if (IsRunOnOsLoginExecuteEnabled()) { - ASSERT_FALSE(GetOsIntegrationTestOverride()->IsRunOnOsLoginEnabled( + ASSERT_FALSE(OsIntegrationTestOverrideImpl::Get()->IsRunOnOsLoginEnabled( profile(), app_id, app_name)); } }
diff --git a/chrome/browser/web_applications/os_integration/shortcut_menu_handling_sub_manager_unittest.cc b/chrome/browser/web_applications/os_integration/shortcut_menu_handling_sub_manager_unittest.cc index 7ecf3ea..d3e9e0c 100644 --- a/chrome/browser/web_applications/os_integration/shortcut_menu_handling_sub_manager_unittest.cc +++ b/chrome/browser/web_applications/os_integration/shortcut_menu_handling_sub_manager_unittest.cc
@@ -15,9 +15,9 @@ #include "base/test/test_future.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/web_applications/os_integration/os_integration_manager.h" -#include "chrome/browser/web_applications/os_integration/os_integration_test_override.h" #include "chrome/browser/web_applications/proto/web_app_os_integration_state.pb.h" #include "chrome/browser/web_applications/test/fake_web_app_provider.h" +#include "chrome/browser/web_applications/test/os_integration_test_override_impl.h" #include "chrome/browser/web_applications/test/web_app_icon_test_utils.h" #include "chrome/browser/web_applications/test/web_app_install_test_utils.h" #include "chrome/browser/web_applications/test/web_app_test.h" @@ -56,7 +56,7 @@ { base::ScopedAllowBlockingForTesting allow_blocking; test_override_ = - OsIntegrationTestOverride::OverrideForTesting(base::GetHomeDir()); + OsIntegrationTestOverrideImpl::OverrideForTesting(base::GetHomeDir()); } provider_ = FakeWebAppProvider::Get(profile()); @@ -184,7 +184,7 @@ private: raw_ptr<FakeWebAppProvider> provider_; - std::unique_ptr<OsIntegrationTestOverride::BlockingRegistration> + std::unique_ptr<OsIntegrationTestOverrideImpl::BlockingRegistration> test_override_; }; @@ -406,16 +406,20 @@ #if BUILDFLAG(IS_WIN) const std::wstring app_user_model_id = web_app::GenerateAppUserModelId(profile()->GetPath(), app_id); - ASSERT_TRUE(GetOsIntegrationTestOverride()->IsShortcutsMenuRegisteredForApp( - app_user_model_id)); - EXPECT_THAT(GetOsIntegrationTestOverride()->GetCountOfShortcutIconsCreated( - app_user_model_id), - testing::Eq(num_menu_items)); - EXPECT_THAT(GetOsIntegrationTestOverride()->GetIconColorsForShortcutsMenu( - app_user_model_id), - testing::ElementsAreArray(colors)); + ASSERT_TRUE( + OsIntegrationTestOverrideImpl::Get()->IsShortcutsMenuRegisteredForApp( + app_user_model_id)); + EXPECT_THAT( + OsIntegrationTestOverrideImpl::Get()->GetCountOfShortcutIconsCreated( + app_user_model_id), + testing::Eq(num_menu_items)); + EXPECT_THAT( + OsIntegrationTestOverrideImpl::Get()->GetIconColorsForShortcutsMenu( + app_user_model_id), + testing::ElementsAreArray(colors)); #else - ASSERT_FALSE(GetOsIntegrationTestOverride()->AreShortcutsMenuRegistered()); + ASSERT_FALSE( + OsIntegrationTestOverrideImpl::Get()->AreShortcutsMenuRegistered()); #endif } else { ASSERT_FALSE(os_integration_state.has_shortcut_menus()); @@ -445,16 +449,20 @@ #if BUILDFLAG(IS_WIN) const std::wstring app_user_model_id = web_app::GenerateAppUserModelId(profile()->GetPath(), app_id); - ASSERT_TRUE(GetOsIntegrationTestOverride()->IsShortcutsMenuRegisteredForApp( - app_user_model_id)); - EXPECT_THAT(GetOsIntegrationTestOverride()->GetCountOfShortcutIconsCreated( - app_user_model_id), - testing::Eq(num_menu_items)); - EXPECT_THAT(GetOsIntegrationTestOverride()->GetIconColorsForShortcutsMenu( - app_user_model_id), - testing::ElementsAreArray(colors)); + ASSERT_TRUE( + OsIntegrationTestOverrideImpl::Get()->IsShortcutsMenuRegisteredForApp( + app_user_model_id)); + EXPECT_THAT( + OsIntegrationTestOverrideImpl::Get()->GetCountOfShortcutIconsCreated( + app_user_model_id), + testing::Eq(num_menu_items)); + EXPECT_THAT( + OsIntegrationTestOverrideImpl::Get()->GetIconColorsForShortcutsMenu( + app_user_model_id), + testing::ElementsAreArray(colors)); #else - ASSERT_FALSE(GetOsIntegrationTestOverride()->AreShortcutsMenuRegistered()); + ASSERT_FALSE( + OsIntegrationTestOverrideImpl::Get()->AreShortcutsMenuRegistered()); #endif } else { ASSERT_FALSE(os_integration_state.has_shortcut_menus()); @@ -468,10 +476,11 @@ web_app::GenerateAppUserModelId(profile()->GetPath(), app_id); ASSERT_TRUE(os_integration_state.has_shortcut_menus()); ASSERT_FALSE( - GetOsIntegrationTestOverride()->IsShortcutsMenuRegisteredForApp( + OsIntegrationTestOverrideImpl::Get()->IsShortcutsMenuRegisteredForApp( app_user_model_id)); #else - ASSERT_FALSE(GetOsIntegrationTestOverride()->AreShortcutsMenuRegistered()); + ASSERT_FALSE( + OsIntegrationTestOverrideImpl::Get()->AreShortcutsMenuRegistered()); #endif } else { ASSERT_FALSE(os_integration_state.has_shortcut_menus()); @@ -497,16 +506,20 @@ #if BUILDFLAG(IS_WIN) const std::wstring app_user_model_id = web_app::GenerateAppUserModelId(profile()->GetPath(), app_id); - ASSERT_TRUE(GetOsIntegrationTestOverride()->IsShortcutsMenuRegisteredForApp( - app_user_model_id)); - EXPECT_THAT(GetOsIntegrationTestOverride()->GetCountOfShortcutIconsCreated( - app_user_model_id), - testing::Eq(num_menu_items)); - EXPECT_THAT(GetOsIntegrationTestOverride()->GetIconColorsForShortcutsMenu( - app_user_model_id), - testing::ElementsAreArray(colors)); + ASSERT_TRUE( + OsIntegrationTestOverrideImpl::Get()->IsShortcutsMenuRegisteredForApp( + app_user_model_id)); + EXPECT_THAT( + OsIntegrationTestOverrideImpl::Get()->GetCountOfShortcutIconsCreated( + app_user_model_id), + testing::Eq(num_menu_items)); + EXPECT_THAT( + OsIntegrationTestOverrideImpl::Get()->GetIconColorsForShortcutsMenu( + app_user_model_id), + testing::ElementsAreArray(colors)); #else - ASSERT_FALSE(GetOsIntegrationTestOverride()->AreShortcutsMenuRegistered()); + ASSERT_FALSE( + OsIntegrationTestOverrideImpl::Get()->AreShortcutsMenuRegistered()); #endif } else { ASSERT_FALSE(os_integration_state.has_shortcut_menus()); @@ -535,16 +548,20 @@ #if BUILDFLAG(IS_WIN) const std::wstring updated_model_id = web_app::GenerateAppUserModelId(profile()->GetPath(), updated_app_id); - ASSERT_TRUE(GetOsIntegrationTestOverride()->IsShortcutsMenuRegisteredForApp( - updated_model_id)); - EXPECT_THAT(GetOsIntegrationTestOverride()->GetCountOfShortcutIconsCreated( - updated_model_id), - testing::Eq(updated_num_menu_items)); - EXPECT_THAT(GetOsIntegrationTestOverride()->GetIconColorsForShortcutsMenu( - updated_model_id), - testing::ElementsAreArray(updated_colors)); + ASSERT_TRUE( + OsIntegrationTestOverrideImpl::Get()->IsShortcutsMenuRegisteredForApp( + updated_model_id)); + EXPECT_THAT( + OsIntegrationTestOverrideImpl::Get()->GetCountOfShortcutIconsCreated( + updated_model_id), + testing::Eq(updated_num_menu_items)); + EXPECT_THAT( + OsIntegrationTestOverrideImpl::Get()->GetIconColorsForShortcutsMenu( + updated_model_id), + testing::ElementsAreArray(updated_colors)); #else - ASSERT_FALSE(GetOsIntegrationTestOverride()->AreShortcutsMenuRegistered()); + ASSERT_FALSE( + OsIntegrationTestOverrideImpl::Get()->AreShortcutsMenuRegistered()); #endif } else { ASSERT_FALSE(updated_os_integration_state.has_shortcut_menus());
diff --git a/chrome/browser/web_applications/os_integration/shortcut_sub_manager_unittest.cc b/chrome/browser/web_applications/os_integration/shortcut_sub_manager_unittest.cc index d4e58a2..46ef6277 100644 --- a/chrome/browser/web_applications/os_integration/shortcut_sub_manager_unittest.cc +++ b/chrome/browser/web_applications/os_integration/shortcut_sub_manager_unittest.cc
@@ -11,9 +11,9 @@ #include "base/test/test_future.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/web_applications/os_integration/os_integration_manager.h" -#include "chrome/browser/web_applications/os_integration/os_integration_test_override.h" #include "chrome/browser/web_applications/proto/web_app_os_integration_state.pb.h" #include "chrome/browser/web_applications/test/fake_web_app_provider.h" +#include "chrome/browser/web_applications/test/os_integration_test_override_impl.h" #include "chrome/browser/web_applications/test/web_app_install_test_utils.h" #include "chrome/browser/web_applications/test/web_app_test.h" #include "chrome/browser/web_applications/test/web_app_test_utils.h" @@ -51,7 +51,7 @@ { base::ScopedAllowBlockingForTesting allow_blocking; test_override_ = - OsIntegrationTestOverride::OverrideForTesting(base::GetHomeDir()); + OsIntegrationTestOverrideImpl::OverrideForTesting(base::GetHomeDir()); } provider_ = FakeWebAppProvider::Get(profile()); @@ -115,7 +115,7 @@ private: raw_ptr<FakeWebAppProvider> provider_; - std::unique_ptr<OsIntegrationTestOverride::BlockingRegistration> + std::unique_ptr<OsIntegrationTestOverrideImpl::BlockingRegistration> test_override_; }; @@ -223,8 +223,8 @@ return SK_ColorTRANSPARENT; } - scoped_refptr<OsIntegrationTestOverride> test_override = - GetOsIntegrationTestOverride(); + scoped_refptr<OsIntegrationTestOverrideImpl> test_override = + OsIntegrationTestOverrideImpl::Get(); #if BUILDFLAG(IS_WIN) absl::optional<SkColor> desktop_color = @@ -301,7 +301,7 @@ ASSERT_FALSE(os_integration_state.has_shortcut()); } - ASSERT_TRUE(GetOsIntegrationTestOverride()->IsShortcutCreated( + ASSERT_TRUE(OsIntegrationTestOverrideImpl::Get()->IsShortcutCreated( profile(), app_id, provider().registrar_unsafe().GetAppShortName(app_id))); @@ -332,7 +332,7 @@ ASSERT_FALSE(os_integration_state.has_shortcut()); } - ASSERT_TRUE(GetOsIntegrationTestOverride()->IsShortcutCreated( + ASSERT_TRUE(OsIntegrationTestOverrideImpl::Get()->IsShortcutCreated( profile(), app_id, provider().registrar_unsafe().GetAppShortName(app_id))); ASSERT_THAT( @@ -362,7 +362,7 @@ // TODO(crbug.com/1425967): Enable once PList parsing code is added to // OsIntegrationTestOverride for Mac shortcut checking. #if !BUILDFLAG(IS_MAC) - ASSERT_TRUE(GetOsIntegrationTestOverride()->IsShortcutCreated( + ASSERT_TRUE(OsIntegrationTestOverrideImpl::Get()->IsShortcutCreated( profile(), app_id, provider().registrar_unsafe().GetAppShortName(app_id))); ASSERT_THAT( @@ -391,7 +391,7 @@ ASSERT_FALSE(os_integration_state.has_shortcut()); } - ASSERT_TRUE(GetOsIntegrationTestOverride()->IsShortcutCreated( + ASSERT_TRUE(OsIntegrationTestOverrideImpl::Get()->IsShortcutCreated( profile(), app_id, provider().registrar_unsafe().GetAppShortName(app_id))); ASSERT_THAT( @@ -402,7 +402,7 @@ test::UninstallAllWebApps(profile()); if (HasShortcutsOsIntegration()) { - ASSERT_FALSE(GetOsIntegrationTestOverride()->IsShortcutCreated( + ASSERT_FALSE(OsIntegrationTestOverrideImpl::Get()->IsShortcutCreated( profile(), app_id, provider().registrar_unsafe().GetAppShortName(app_id))); }
diff --git a/chrome/browser/web_applications/os_integration/uninstallation_via_os_settings_sub_manager_unittest.cc b/chrome/browser/web_applications/os_integration/uninstallation_via_os_settings_sub_manager_unittest.cc index 021f414..eb5a078 100644 --- a/chrome/browser/web_applications/os_integration/uninstallation_via_os_settings_sub_manager_unittest.cc +++ b/chrome/browser/web_applications/os_integration/uninstallation_via_os_settings_sub_manager_unittest.cc
@@ -11,9 +11,9 @@ #include "base/test/test_future.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/web_applications/os_integration/os_integration_manager.h" -#include "chrome/browser/web_applications/os_integration/os_integration_test_override.h" #include "chrome/browser/web_applications/proto/web_app_os_integration_state.pb.h" #include "chrome/browser/web_applications/test/fake_web_app_provider.h" +#include "chrome/browser/web_applications/test/os_integration_test_override_impl.h" #include "chrome/browser/web_applications/test/web_app_install_test_utils.h" #include "chrome/browser/web_applications/test/web_app_test.h" #include "chrome/browser/web_applications/test/web_app_test_utils.h" @@ -44,7 +44,7 @@ { base::ScopedAllowBlockingForTesting allow_blocking; test_override_ = - OsIntegrationTestOverride::OverrideForTesting(base::GetHomeDir()); + OsIntegrationTestOverrideImpl::OverrideForTesting(base::GetHomeDir()); } if (GetParam() == OsIntegrationSubManagersState::kSaveStateToDB) { scoped_feature_list_.InitAndEnableFeatureWithParameters( @@ -111,7 +111,7 @@ return result.Get<AppId>(); } - OsIntegrationTestOverride& test_override() const { + OsIntegrationTestOverrideImpl& test_override() const { return *test_override_->test_override; } @@ -121,7 +121,7 @@ private: raw_ptr<FakeWebAppProvider> provider_; base::test::ScopedFeatureList scoped_feature_list_; - std::unique_ptr<OsIntegrationTestOverride::BlockingRegistration> + std::unique_ptr<OsIntegrationTestOverrideImpl::BlockingRegistration> test_override_; };
diff --git a/chrome/browser/web_applications/os_integration/web_app_file_handler_registration_linux.cc b/chrome/browser/web_applications/os_integration/web_app_file_handler_registration_linux.cc index c2467f0..49125027 100644 --- a/chrome/browser/web_applications/os_integration/web_app_file_handler_registration_linux.cc +++ b/chrome/browser/web_applications/os_integration/web_app_file_handler_registration_linux.cc
@@ -75,7 +75,7 @@ void RefreshMimeInfoCache() { scoped_refptr<OsIntegrationTestOverride> test_override = - web_app::GetOsIntegrationTestOverride(); + OsIntegrationTestOverride::Get(); std::unique_ptr<base::Environment> env(base::Environment::Create()); std::vector<std::string> argv;
diff --git a/chrome/browser/web_applications/os_integration/web_app_file_handler_registration_linux_browsertest.cc b/chrome/browser/web_applications/os_integration/web_app_file_handler_registration_linux_browsertest.cc index f2cd62a..fd97ab8 100644 --- a/chrome/browser/web_applications/os_integration/web_app_file_handler_registration_linux_browsertest.cc +++ b/chrome/browser/web_applications/os_integration/web_app_file_handler_registration_linux_browsertest.cc
@@ -19,7 +19,7 @@ #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/web_applications/test/web_app_browsertest_util.h" #include "chrome/browser/web_applications/external_install_options.h" -#include "chrome/browser/web_applications/os_integration/os_integration_test_override.h" +#include "chrome/browser/web_applications/test/os_integration_test_override_impl.h" #include "chrome/browser/web_applications/test/web_app_install_test_utils.h" #include "chrome/browser/web_applications/web_app_id.h" #include "chrome/browser/web_applications/web_app_provider.h" @@ -56,7 +56,8 @@ protected: WebAppFileHandlerRegistrationLinuxBrowserTest() { base::ScopedAllowBlockingForTesting allow_blocking; - override_registration_ = OsIntegrationTestOverride::OverrideForTesting(); + override_registration_ = + OsIntegrationTestOverrideImpl::OverrideForTesting(); } Profile* profile() { return browser()->profile(); } @@ -81,7 +82,7 @@ } absl::optional<webapps::InstallResultCode> result_code_; - std::unique_ptr<OsIntegrationTestOverride::BlockingRegistration> + std::unique_ptr<OsIntegrationTestOverrideImpl::BlockingRegistration> override_registration_; };
diff --git a/chrome/browser/web_applications/os_integration/web_app_protocol_handler_registration_win.cc b/chrome/browser/web_applications/os_integration/web_app_protocol_handler_registration_win.cc index 8015884..eeb76af 100644 --- a/chrome/browser/web_applications/os_integration/web_app_protocol_handler_registration_win.cc +++ b/chrome/browser/web_applications/os_integration/web_app_protocol_handler_registration_win.cc
@@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/check_is_test.h" #include "chrome/browser/web_applications/os_integration/web_app_protocol_handler_registration.h" #include <string> @@ -36,48 +37,50 @@ #include "third_party/abseil-cpp/absl/types/optional.h" #include "url/gurl.h" +namespace web_app { namespace { void RegisterProtocolHandlersWithOSInBackground( - const web_app::AppId& app_id, + const AppId& app_id, const std::wstring& app_name, const base::FilePath profile_path, std::vector<apps::ProtocolHandlerInfo> protocol_handlers, const std::wstring& app_name_extension) { base::AssertLongCPUWorkAllowed(); - if (web_app::GetOsIntegrationTestOverride()) { // IN-TEST + scoped_refptr<OsIntegrationTestOverride> os_override = + OsIntegrationTestOverride::Get(); + if (os_override) { + CHECK_IS_TEST(); // Instead of modifying the registry, add them to the testing data. std::vector<std::string> protocols_registered; for (apps::ProtocolHandlerInfo& info : protocol_handlers) { protocols_registered.push_back(info.protocol); } - web_app::GetOsIntegrationTestOverride()->RegisterProtocolSchemes( - app_id, std::move(protocols_registered)); + os_override->RegisterProtocolSchemes(app_id, + std::move(protocols_registered)); return; } base::FilePath web_app_path = - web_app::GetOsIntegrationResourcesDirectoryForApp(profile_path, app_id, - GURL()); + GetOsIntegrationResourcesDirectoryForApp(profile_path, app_id, GURL()); absl::optional<base::FilePath> app_specific_launcher_path = - web_app::CreateAppLauncherFile(app_name, app_name_extension, - web_app_path); - if (!app_specific_launcher_path.has_value()) + CreateAppLauncherFile(app_name, app_name_extension, web_app_path); + if (!app_specific_launcher_path.has_value()) { return; + } - base::CommandLine app_specific_launcher_command = - web_app::GetAppLauncherCommand(app_id, app_specific_launcher_path.value(), - profile_path); + base::CommandLine app_specific_launcher_command = GetAppLauncherCommand( + app_id, app_specific_launcher_path.value(), profile_path); std::wstring user_visible_app_name(app_name); user_visible_app_name.append(app_name_extension); - base::FilePath icon_path = web_app::internals::GetIconFilePath( - web_app_path, base::AsString16(app_name)); + base::FilePath icon_path = + internals::GetIconFilePath(web_app_path, base::AsString16(app_name)); - std::wstring prog_id = web_app::GetProgIdForApp(profile_path, app_id); + std::wstring prog_id = GetProgIdForApp(profile_path, app_id); ShellUtil::AddApplicationClass(prog_id, app_specific_launcher_command, user_visible_app_name, user_visible_app_name, icon_path); @@ -95,11 +98,12 @@ } void UnregisterProtocolHandlersWithOsInBackground( - const web_app::AppId& app_id, + const AppId& app_id, const base::FilePath& profile_path) { base::AssertLongCPUWorkAllowed(); - if (web_app::GetOsIntegrationTestOverride()) { // IN-TEST + if (OsIntegrationTestOverride::Get()) { + CHECK_IS_TEST(); // The unregistration is not tested due to complication in the // implementation of other OS's. Instead, we check if the updated // registrations are empty / don't have the offending protocol. @@ -110,7 +114,7 @@ // remove the web application directory. This must be done before cleaning up // the registry, since the app-specific-launcher path is retrieved from the // registry. - std::wstring prog_id = web_app::GetProgIdForApp(profile_path, app_id); + std::wstring prog_id = GetProgIdForApp(profile_path, app_id); base::FilePath app_specific_launcher_path = ShellUtil::GetApplicationPathForProgId(prog_id); @@ -123,13 +127,11 @@ // Remove protocol associations from the Windows registry. ShellUtil::RemoveAppProtocolAssociations( - web_app::GetProgIdForApp(profile_path, app_id)); + GetProgIdForApp(profile_path, app_id)); } } // namespace -namespace web_app { - void RegisterProtocolHandlersWithOs( const AppId& app_id, const std::string& app_name, @@ -137,9 +139,11 @@ std::vector<apps::ProtocolHandlerInfo> protocol_handlers, ResultCallback callback) { if (protocol_handlers.empty()) { - if (web_app::GetOsIntegrationTestOverride()) { // IN-TEST - web_app::GetOsIntegrationTestOverride()->RegisterProtocolSchemes( - app_id, std::vector<std::string>()); + scoped_refptr<OsIntegrationTestOverride> os_override = + OsIntegrationTestOverride::Get(); + if (os_override) { + CHECK_IS_TEST(); + os_override->RegisterProtocolSchemes(app_id, std::vector<std::string>()); } std::move(callback).Run(Result::kOk); return;
diff --git a/chrome/browser/web_applications/os_integration/web_app_run_on_os_login_mac_unittest.mm b/chrome/browser/web_applications/os_integration/web_app_run_on_os_login_mac_unittest.mm index 7bb96c1..46323f5 100644 --- a/chrome/browser/web_applications/os_integration/web_app_run_on_os_login_mac_unittest.mm +++ b/chrome/browser/web_applications/os_integration/web_app_run_on_os_login_mac_unittest.mm
@@ -17,8 +17,8 @@ #include "base/mac/foundation_util.h" #include "base/path_service.h" #include "base/strings/utf_string_conversions.h" -#include "chrome/browser/web_applications/os_integration/os_integration_test_override.h" #include "chrome/browser/web_applications/os_integration/web_app_shortcut_mac.h" +#include "chrome/browser/web_applications/test/os_integration_test_override_impl.h" #include "chrome/browser/web_applications/test/web_app_test.h" #include "chrome/browser/web_applications/web_app_constants.h" #include "chrome/common/chrome_paths.h" @@ -79,7 +79,8 @@ WebAppTest::SetUp(); base::mac::SetBaseBundleID(kFakeChromeBundleId); - override_registration_ = OsIntegrationTestOverride::OverrideForTesting(); + override_registration_ = + OsIntegrationTestOverrideImpl::OverrideForTesting(); destination_dir_ = override_registration_->test_override->chrome_apps_folder(); @@ -142,7 +143,7 @@ std::unique_ptr<WebAppAutoLoginUtilMock> auto_login_util_mock_; std::unique_ptr<ShortcutInfo> info_; base::FilePath shim_path_; - std::unique_ptr<OsIntegrationTestOverride::BlockingRegistration> + std::unique_ptr<OsIntegrationTestOverrideImpl::BlockingRegistration> override_registration_; };
diff --git a/chrome/browser/web_applications/os_integration/web_app_shortcut_linux.cc b/chrome/browser/web_applications/os_integration/web_app_shortcut_linux.cc index 49d7565..9c8576a 100644 --- a/chrome/browser/web_applications/os_integration/web_app_shortcut_linux.cc +++ b/chrome/browser/web_applications/os_integration/web_app_shortcut_linux.cc
@@ -10,6 +10,7 @@ #include <fcntl.h> #include "base/base_paths.h" +#include "base/check_is_test.h" #include "base/environment.h" #include "base/files/file_path.h" #include "base/files/file_util.h" @@ -42,6 +43,8 @@ #include "chrome/common/buildflags.h" #include "chrome/common/chrome_constants.h" +namespace web_app { + namespace { // UMA metric name for creating shortcut result. @@ -53,25 +56,29 @@ "Apps.CreateShortcutIcon.Linux.Result"; // Testing hook for shell_integration_linux -web_app::LaunchXdgUtilityForTesting& GetInstalledLaunchXdgUtilityForTesting() { - static base::NoDestructor<web_app::LaunchXdgUtilityForTesting> instance; +LaunchXdgUtilityForTesting& GetInstalledLaunchXdgUtilityForTesting() { + static base::NoDestructor<LaunchXdgUtilityForTesting> instance; return *instance; } base::FilePath GetDesktopPath() { base::FilePath desktop_path; - auto test_override = web_app::GetOsIntegrationTestOverride(); - if (test_override) { - return test_override->desktop(); + scoped_refptr<OsIntegrationTestOverride> os_override = + OsIntegrationTestOverride::Get(); + if (os_override) { + CHECK_IS_TEST(); + return os_override->desktop(); } base::PathService::Get(base::DIR_USER_DESKTOP, &desktop_path); return desktop_path; } base::FilePath GetAutostartPath(base::Environment* env) { - auto test_override = web_app::GetOsIntegrationTestOverride(); - if (test_override) { - return test_override->startup(); + scoped_refptr<OsIntegrationTestOverride> os_override = + OsIntegrationTestOverride::Get(); + if (os_override) { + CHECK_IS_TEST(); + return os_override->startup(); } return AutoStart::GetAutostartDirectory(env); } @@ -118,9 +125,10 @@ } bool LaunchXdgUtility(const std::vector<std::string>& argv, int* exit_code) { - if (GetInstalledLaunchXdgUtilityForTesting()) + if (GetInstalledLaunchXdgUtilityForTesting()) { return std::move(GetInstalledLaunchXdgUtilityForTesting()) .Run(argv, exit_code); + } return shell_integration_linux::LaunchXdgUtility(argv, exit_code); } @@ -203,8 +211,9 @@ O_CREAT | O_EXCL | O_WRONLY, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); if (fd < 0) { - if (IGNORE_EINTR(close(location_fd)) < 0) + if (IGNORE_EINTR(close(location_fd)) < 0) { PLOG(ERROR) << "close"; + } RecordCreateShortcut(CreateShortcutResult::kFailToOpenShortcutFilepath); return false; } @@ -218,11 +227,13 @@ unlinkat(location_fd, shortcut_filename.value().c_str(), 0); } - if (IGNORE_EINTR(close(fd)) < 0) + if (IGNORE_EINTR(close(fd)) < 0) { PLOG(ERROR) << "close"; + } - if (IGNORE_EINTR(close(location_fd)) < 0) + if (IGNORE_EINTR(close(location_fd)) < 0) { PLOG(ERROR) << "close"; + } return true; } @@ -259,7 +270,7 @@ const std::string& contents, const base::FilePath& directory_filename, const std::string& directory_contents) { - DCHECK(!web_app::GetOsIntegrationTestOverride()); + DCHECK(!OsIntegrationTestOverride::Get()); base::ScopedTempDir temp_dir; if (!temp_dir.CreateUniqueTempDir()) { RecordCreateShortcut(CreateShortcutResult::kFailToCreateTempDir); @@ -292,8 +303,9 @@ argv.push_back("user"); // If provided, install the shortcut file inside the given directory. - if (!directory_filename.empty()) + if (!directory_filename.empty()) { argv.push_back(temp_directory_path.value()); + } argv.push_back(temp_file_path.value()); int exit_code; LaunchXdgUtility(argv, &exit_code); @@ -326,8 +338,6 @@ } // namespace -namespace web_app { - DesktopActionInfo::DesktopActionInfo() = default; DesktopActionInfo::DesktopActionInfo(const std::string& id, @@ -375,8 +385,9 @@ bool DeleteShortcutOnDesktop(const base::FilePath& shortcut_filename) { base::FilePath desktop_path = GetDesktopPath(); bool result = false; - if (!desktop_path.empty()) + if (!desktop_path.empty()) { result = base::DeleteFile(desktop_path.Append(shortcut_filename)); + } return result; } @@ -390,7 +401,7 @@ const base::FilePath& shortcut_filename, const base::FilePath& directory_filename) { // TODO(crbug.com/1276141): Support shortcut testing in Applications Menu. - DCHECK(!web_app::GetOsIntegrationTestOverride()); + DCHECK(!OsIntegrationTestOverride::Get()); std::vector<std::string> argv; argv.push_back("xdg-desktop-menu"); argv.push_back("uninstall"); @@ -403,8 +414,9 @@ // items from the menu with a matching name. // If |directory_filename| is supplied, this will also remove the item from // the directory, and remove the directory if it is empty. - if (!directory_filename.empty()) + if (!directory_filename.empty()) { argv.push_back(directory_filename.value()); + } argv.push_back(shortcut_filename.value()); int exit_code; return LaunchXdgUtility(argv, &exit_code); @@ -418,7 +430,7 @@ // If this is set, then keeping this as a local variable ensures it is not // destroyed while we use it. scoped_refptr<OsIntegrationTestOverride> test_override = - web_app::GetOsIntegrationTestOverride(); + OsIntegrationTestOverride::Get(); bool create_shortcut_in_startup = creation_locations.in_startup; @@ -437,11 +449,13 @@ shortcut_info.app_id); // For extensions we do not want duplicate shortcuts. So, delete any that // already exist and replace them. - if (creation_locations.on_desktop) + if (creation_locations.on_desktop) { DeleteShortcutOnDesktop(shortcut_filename); + } - if (create_shortcut_in_startup) + if (create_shortcut_in_startup) { DeleteShortcutInAutoStart(env, shortcut_filename); + } if (applications_menu_location != APP_MENU_LOCATION_NONE) { DeleteShortcutInApplicationsMenu(shortcut_filename, base::FilePath()); @@ -488,7 +502,8 @@ CreateShortcutInAutoStart(env, shortcut_filename, contents) && success; } - if (test_override) { // IN-TEST + if (test_override) { + CHECK_IS_TEST(); std::vector<std::string> protocol_handler( shortcut_info.protocol_handlers.begin(), shortcut_info.protocol_handlers.end()); @@ -594,7 +609,7 @@ // If this is set, then keeping this as a local variable ensures it is not // destroyed while we use it. scoped_refptr<OsIntegrationTestOverride> test_override = - web_app::GetOsIntegrationTestOverride(); + OsIntegrationTestOverride::Get(); base::FilePath shortcut_filename = GetAppShortcutFilename(profile_path, extension_id); @@ -627,7 +642,7 @@ // If this is set, then keeping this as a local variable ensures it is not // destroyed while we use it. scoped_refptr<OsIntegrationTestOverride> test_override = - web_app::GetOsIntegrationTestOverride(); + OsIntegrationTestOverride::Get(); bool result = true; // Delete shortcuts from Desktop. @@ -637,8 +652,9 @@ shell_integration_linux::GetExistingProfileShortcutFilenames( profile_path, desktop_path); for (const auto& shortcut : shortcut_filenames_desktop) { - if (!DeleteShortcutOnDesktop(shortcut)) + if (!DeleteShortcutOnDesktop(shortcut)) { result = false; + } } } @@ -650,8 +666,9 @@ if (test_override) { continue; } - if (!DeleteShortcutInAutoStart(env, shortcut)) + if (!DeleteShortcutInAutoStart(env, shortcut)) { result = false; + } } // Delete shortcuts from |kDirectoryFilename|. @@ -685,8 +702,9 @@ // Always create a hidden shortcut in applications if a visible one is not // being created. This allows the operating system to identify the app, but // not show it in the menu. - if (creation_locations.applications_menu_location == APP_MENU_LOCATION_NONE) + if (creation_locations.applications_menu_location == APP_MENU_LOCATION_NONE) { creation_locations.applications_menu_location = APP_MENU_LOCATION_HIDDEN; + } return CreateDesktopShortcut(env, shortcut_info, creation_locations); } @@ -701,7 +719,7 @@ // If this is set, then keeping this as a local variable ensures it is not // destroyed while we use it. scoped_refptr<OsIntegrationTestOverride> test_override = - web_app::GetOsIntegrationTestOverride(); + OsIntegrationTestOverride::Get(); std::vector<base::FilePath> shortcut_locations; base::FilePath shortcut_filename = @@ -713,8 +731,9 @@ if (!desktop_path.empty()) { base::FilePath desktop_shortcut_path = desktop_path.Append(shortcut_filename); - if (base::PathExists(desktop_shortcut_path)) + if (base::PathExists(desktop_shortcut_path)) { shortcut_locations.push_back(desktop_shortcut_path); + } } } @@ -723,8 +742,9 @@ if (!autostart_path.empty()) { base::FilePath autostart_shortcut_path = autostart_path.Append(shortcut_filename); - if (base::PathExists(autostart_shortcut_path)) + if (base::PathExists(autostart_shortcut_path)) { shortcut_locations.push_back(autostart_shortcut_path); + } } }
diff --git a/chrome/browser/web_applications/os_integration/web_app_shortcut_mac.mm b/chrome/browser/web_applications/os_integration/web_app_shortcut_mac.mm index 55849b7d..b792ebb 100644 --- a/chrome/browser/web_applications/os_integration/web_app_shortcut_mac.mm +++ b/chrome/browser/web_applications/os_integration/web_app_shortcut_mac.mm
@@ -3,6 +3,7 @@ // found in the LICENSE file. #import "chrome/browser/web_applications/os_integration/web_app_shortcut_mac.h" +#include "base/check_is_test.h" #import <Cocoa/Cocoa.h> #include <stdint.h> @@ -226,7 +227,7 @@ // creating Finder windows that are never closed. return base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kTestType) || - GetOsIntegrationTestOverride(); + OsIntegrationTestOverride::Get(); } base::FilePath GetWritableApplicationsDirectory() { @@ -412,6 +413,32 @@ return command_line; } +NSRunningApplication* FindRunningApplicationForBundleIdAndPath( + const std::string& bundle_id, + const base::FilePath& bundle_path) { + NSArray<NSRunningApplication*>* apps = [NSRunningApplication + runningApplicationsWithBundleIdentifier:base::SysUTF8ToNSString( + bundle_id)]; + for (NSRunningApplication* app in apps) { + if (base::mac::NSURLToFilePath(app.bundleURL) == bundle_path) { + return app; + } + } + + // Sometimes runningApplicationsWithBundleIdentifier incorrectly fails to + // return all apps with the provided bundle id. So also scan over the full + // list of running applications. + apps = [NSWorkspace sharedWorkspace].runningApplications; + for (NSRunningApplication* app in apps) { + if (base::SysNSStringToUTF8(app.bundleIdentifier) == bundle_id && + base::mac::NSURLToFilePath(app.bundleURL) == bundle_path) { + return app; + } + } + + return nil; +} + // Wrapper around base::mac::LaunchApplication that attempts to retry the launch // once, if the initial launch fails. This helps reduce test flakiness on older // Mac OS bots (Mac 11 and Mac 10.16). @@ -434,6 +461,14 @@ return; } + if (@available(macOS 12.0, *)) { + // In newer Mac OS versions this workaround isn't needed, and in + // fact can itself cause flaky tests by launching the app twice + // when only one launch is expected. + std::move(callback).Run(std::move(result)); + return; + } + LOG(ERROR) << "Failed to open application with path: " << app_bundle_path << ", retrying in 100ms"; internals::GetShortcutIOTaskRunner()->PostDelayedTask( @@ -475,16 +510,13 @@ LOG(ERROR) << "Failed to open application with path: " << app_bundle_path; if (!options.create_new_instance) { - NSArray<NSRunningApplication*>* apps = - [NSRunningApplication runningApplicationsWithBundleIdentifier: - base::SysUTF8ToNSString(bundle_id)]; - for (NSRunningApplication* app in apps) { - if (base::mac::NSURLToFilePath(app.bundleURL) == - app_bundle_path) { - LOG(ERROR) << "But found a running application anyway."; - std::move(callback).Run(app); - return; - } + NSRunningApplication* app = + FindRunningApplicationForBundleIdAndPath(bundle_id, + app_bundle_path); + if (app) { + LOG(ERROR) << "But found a running application anyway."; + std::move(callback).Run(app); + return; } } @@ -944,14 +976,16 @@ // tests. Unit tests need to set the test override. return base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kTestType) && - !GetOsIntegrationTestOverride(); + !OsIntegrationTestOverride::Get(); } base::FilePath GetChromeAppsFolder() { - auto override = GetOsIntegrationTestOverride(); - if (override) { - if (override->IsChromeAppsValid()) { - return override->chrome_apps_folder(); + scoped_refptr<OsIntegrationTestOverride> os_override = + OsIntegrationTestOverride::Get(); + if (os_override) { + CHECK_IS_TEST(); + if (os_override->IsChromeAppsValid()) { + return os_override->chrome_apps_folder(); } return base::FilePath(); } @@ -980,10 +1014,12 @@ void WebAppAutoLoginUtil::AddToLoginItems(const base::FilePath& app_bundle_path, bool hide_on_startup) { - auto override = GetOsIntegrationTestOverride(); - if (override) { - override->EnableOrDisablePathOnLogin(app_bundle_path, - /*enabled_on_start=*/true); + scoped_refptr<OsIntegrationTestOverride> os_override = + OsIntegrationTestOverride::Get(); + if (os_override) { + CHECK_IS_TEST(); + os_override->EnableOrDisablePathOnLogin(app_bundle_path, + /*enabled_on_start=*/true); } else { base::mac::AddToLoginItems(app_bundle_path, hide_on_startup); } @@ -991,10 +1027,12 @@ void WebAppAutoLoginUtil::RemoveFromLoginItems( const base::FilePath& app_bundle_path) { - auto override = GetOsIntegrationTestOverride(); - if (override) { - override->EnableOrDisablePathOnLogin(app_bundle_path, - /*enabled_on_start=*/false); + scoped_refptr<OsIntegrationTestOverride> os_override = + OsIntegrationTestOverride::Get(); + if (os_override) { + CHECK_IS_TEST(); + os_override->EnableOrDisablePathOnLogin(app_bundle_path, + /*enabled_on_start=*/false); } else { base::mac::RemoveFromLoginItems(app_bundle_path); } @@ -1466,14 +1504,16 @@ app_mode::kCFBundleURLSchemesKey : handlers } ]; } - if (GetOsIntegrationTestOverride()) { // IN-TEST + scoped_refptr<OsIntegrationTestOverride> os_override = + OsIntegrationTestOverride::Get(); + if (os_override) { + CHECK_IS_TEST(); std::vector<std::string> protocol_handlers_vec; protocol_handlers_vec.insert(protocol_handlers_vec.end(), protocol_handlers.begin(), protocol_handlers.end()); - GetOsIntegrationTestOverride() // IN-TEST - ->RegisterProtocolSchemes(info_->app_id, - std::move(protocol_handlers_vec)); + os_override->RegisterProtocolSchemes(info_->app_id, + std::move(protocol_handlers_vec)); } // TODO(crbug.com/1273526): If we decide to rename app bundles on app title @@ -1698,17 +1738,11 @@ const std::string& app_id, bool terminate_shim) { std::string bundle_id = GetBundleIdentifier(app_id); - NSArray<NSRunningApplication*>* apps = [NSRunningApplication - runningApplicationsWithBundleIdentifier:base::SysUTF8ToNSString( - bundle_id)]; - NSRunningApplication* matching_app = nil; - for (NSRunningApplication* app in apps) { - if (base::mac::NSURLToFilePath(app.bundleURL) == shim_path) { - matching_app = app; - break; - } - } + NSRunningApplication* matching_app = + FindRunningApplicationForBundleIdAndPath(bundle_id, shim_path); if (!matching_app) { + LOG(ERROR) << "No matching applications found for app_id " << app_id + << " and path " << shim_path; return; } @@ -1746,7 +1780,7 @@ // destroyed while we use state from it (retrieved in // `GetChromeAppsFolder()`). scoped_refptr<OsIntegrationTestOverride> test_override = - web_app::GetOsIntegrationTestOverride(); + web_app::OsIntegrationTestOverride::Get(); if (AppShimCreationAndLaunchDisabledForTest()) { return true; } @@ -1763,7 +1797,7 @@ // destroyed while we use state from it (retrieved in // `GetChromeAppsFolder()`). scoped_refptr<OsIntegrationTestOverride> test_override = - web_app::GetOsIntegrationTestOverride(); + web_app::OsIntegrationTestOverride::Get(); WebAppShortcutCreator shortcut_creator( internals::GetShortcutDataDir(shortcut_info), &shortcut_info); ShortcutLocations locations; @@ -1783,7 +1817,7 @@ // destroyed while we use state from it (retrieved in // `GetChromeAppsFolder()`). scoped_refptr<OsIntegrationTestOverride> test_override = - web_app::GetOsIntegrationTestOverride(); + web_app::OsIntegrationTestOverride::Get(); const std::string bundle_id = GetBundleIdentifier(shortcut_info.app_id, shortcut_info.profile_path); auto bundle_infos = SearchForBundlesById(bundle_id); @@ -1806,7 +1840,7 @@ // destroyed while we use state from it (retrieved in // `GetChromeAppsFolder()`). scoped_refptr<OsIntegrationTestOverride> test_override = - web_app::GetOsIntegrationTestOverride(); + web_app::OsIntegrationTestOverride::Get(); const std::string bundle_id = GetBundleIdentifier(app_id); auto bundle_infos = SearchForBundlesById(bundle_id); for (const auto& bundle_info : bundle_infos) { @@ -1825,7 +1859,7 @@ // destroyed while we use state from it (retrieved in // `GetChromeAppsFolder()`). scoped_refptr<OsIntegrationTestOverride> test_override = - web_app::GetOsIntegrationTestOverride(); + web_app::OsIntegrationTestOverride::Get(); if (AppShimCreationAndLaunchDisabledForTest()) { return Result::kOk; } @@ -1845,7 +1879,7 @@ // destroyed while we use state from it (retrieved in // `GetChromeAppsFolder()`). scoped_refptr<OsIntegrationTestOverride> test_override = - web_app::GetOsIntegrationTestOverride(); + web_app::OsIntegrationTestOverride::Get(); std::list<BundleInfoPlist> bundles_info = BundleInfoPlist::GetAllInPath( GetChromeAppsFolder(), true /* recursive */); for (const auto& info : bundles_info) {
diff --git a/chrome/browser/web_applications/os_integration/web_app_shortcut_mac_unittest.mm b/chrome/browser/web_applications/os_integration/web_app_shortcut_mac_unittest.mm index 172beab..5206beddb 100644 --- a/chrome/browser/web_applications/os_integration/web_app_shortcut_mac_unittest.mm +++ b/chrome/browser/web_applications/os_integration/web_app_shortcut_mac_unittest.mm
@@ -19,7 +19,7 @@ #include "base/path_service.h" #include "base/strings/sys_string_conversions.h" #include "base/strings/utf_string_conversions.h" -#include "chrome/browser/web_applications/os_integration/os_integration_test_override.h" +#include "chrome/browser/web_applications/test/os_integration_test_override_impl.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/chrome_switches.h" #import "chrome/common/mac/app_mode_common.h" @@ -130,7 +130,8 @@ void SetUp() override { base::mac::SetBaseBundleID(kFakeChromeBundleId); - override_registration_ = OsIntegrationTestOverride::OverrideForTesting(); + override_registration_ = + OsIntegrationTestOverrideImpl::OverrideForTesting(); destination_dir_ = override_registration_->test_override->chrome_apps_folder(); @@ -187,7 +188,7 @@ base::FilePath shim_base_name_; base::FilePath shim_path_; - std::unique_ptr<OsIntegrationTestOverride::BlockingRegistration> + std::unique_ptr<OsIntegrationTestOverrideImpl::BlockingRegistration> override_registration_; };
diff --git a/chrome/browser/web_applications/os_integration/web_app_shortcut_manager_mac_unittest.cc b/chrome/browser/web_applications/os_integration/web_app_shortcut_manager_mac_unittest.cc index df615e1..f5849d8 100644 --- a/chrome/browser/web_applications/os_integration/web_app_shortcut_manager_mac_unittest.cc +++ b/chrome/browser/web_applications/os_integration/web_app_shortcut_manager_mac_unittest.cc
@@ -8,9 +8,9 @@ #include "base/mac/foundation_util.h" #include "base/test/bind.h" #include "chrome/browser/web_applications/os_integration/os_integration_manager.h" -#include "chrome/browser/web_applications/os_integration/os_integration_test_override.h" #include "chrome/browser/web_applications/test/fake_os_integration_manager.h" #include "chrome/browser/web_applications/test/fake_web_app_provider.h" +#include "chrome/browser/web_applications/test/os_integration_test_override_impl.h" #include "chrome/browser/web_applications/test/web_app_install_test_utils.h" #include "chrome/browser/web_applications/test/web_app_test.h" #include "chrome/browser/web_applications/web_app_provider.h" @@ -37,7 +37,7 @@ // Put shortcuts somewhere under the home dir, as otherwise LaunchServices // won't be able to find them. override_registration_ = - OsIntegrationTestOverride::OverrideForTesting(base::GetHomeDir()); + OsIntegrationTestOverrideImpl::OverrideForTesting(base::GetHomeDir()); provider_ = FakeWebAppProvider::Get(profile()); @@ -105,7 +105,7 @@ const GURL kTestApp2Url = GURL("https://example.com"); private: - std::unique_ptr<OsIntegrationTestOverride::BlockingRegistration> + std::unique_ptr<OsIntegrationTestOverrideImpl::BlockingRegistration> override_registration_; raw_ptr<FakeWebAppProvider> provider_;
diff --git a/chrome/browser/web_applications/os_integration/web_app_shortcut_win.cc b/chrome/browser/web_applications/os_integration/web_app_shortcut_win.cc index 0634fb7f..b61cee5 100644 --- a/chrome/browser/web_applications/os_integration/web_app_shortcut_win.cc +++ b/chrome/browser/web_applications/os_integration/web_app_shortcut_win.cc
@@ -12,6 +12,7 @@ #include <utility> #include <vector> +#include "base/check_is_test.h" #include "base/check_op.h" #include "base/command_line.h" #include "base/files/file_enumerator.h" @@ -426,7 +427,8 @@ // Calling UnpinShortcuts in unit-tests currently crashes the test, so skip it // for now using the shortcut override mechanism. - if (web_app::GetOsIntegrationTestOverride()) { + if (OsIntegrationTestOverride::Get()) { + CHECK_IS_TEST(); DeleteShortcuts(all_shortcuts, std::move(result_callback)); return; } @@ -569,7 +571,7 @@ // If this is set, then keeping this as a local variable ensures it is not // destroyed while we use state from it (retrieved in `GetShortcutPaths()`). scoped_refptr<OsIntegrationTestOverride> test_override = - web_app::GetOsIntegrationTestOverride(); + OsIntegrationTestOverride::Get(); // Shortcut paths under which to create shortcuts. std::vector<base::FilePath> shortcut_paths = @@ -628,7 +630,7 @@ // If this is set, then keeping this as a local variable ensures it is not // destroyed while we use state from it (retrieved in `GetShortcutPaths()`). scoped_refptr<OsIntegrationTestOverride> test_override = - web_app::GetOsIntegrationTestOverride(); + OsIntegrationTestOverride::Get(); // Update the icon if necessary. const base::FilePath icon_file = @@ -662,7 +664,7 @@ // If this is set, then keeping this as a local variable ensures it is not // destroyed while we use state from it (retrieved in `GetShortcutPaths()`). scoped_refptr<OsIntegrationTestOverride> test_override = - web_app::GetOsIntegrationTestOverride(); + OsIntegrationTestOverride::Get(); ShortcutLocations result; ShortcutLocations desktop; desktop.on_desktop = true; @@ -738,7 +740,7 @@ // If this is set, then keeping this as a local variable ensures it is not // destroyed while we use state from it (retrieved in `GetShortcutPaths()`). scoped_refptr<OsIntegrationTestOverride> test_override = - web_app::GetOsIntegrationTestOverride(); + OsIntegrationTestOverride::Get(); GetShortcutLocationsAndDeleteShortcuts( web_app_path, shortcut_info.profile_path, shortcut_info.title, base::BindOnce(&FinishDeletingPlatformShortcuts, web_app_path, @@ -762,7 +764,7 @@ // If this is set, then keeping this as a local variable ensures it is not // destroyed while we use state from it (retrieved in `GetShortcutPaths()`). scoped_refptr<OsIntegrationTestOverride> test_override = - web_app::GetOsIntegrationTestOverride(); + OsIntegrationTestOverride::Get(); GetShortcutLocationsAndDeleteShortcuts( base::FilePath(), profile_path, std::u16string(), base::BindOnce(&FinishDeletingAllShortcutsForProfile)); @@ -774,7 +776,7 @@ std::vector<base::FilePath> shortcut_paths; // if there is no ShortcutOverrirdeForTesting, set it to empty. scoped_refptr<OsIntegrationTestOverride> testing_shortcuts = - GetOsIntegrationTestOverride(); + OsIntegrationTestOverride::Get(); // Locations to add to shortcut_paths. struct { bool use_this_location;
diff --git a/chrome/browser/web_applications/os_integration/web_app_shortcuts_menu_win.cc b/chrome/browser/web_applications/os_integration/web_app_shortcuts_menu_win.cc index 7fc40f6e..3e9e505 100644 --- a/chrome/browser/web_applications/os_integration/web_app_shortcuts_menu_win.cc +++ b/chrome/browser/web_applications/os_integration/web_app_shortcuts_menu_win.cc
@@ -14,6 +14,7 @@ #include <utility> #include <vector> +#include "base/check_is_test.h" #include "base/command_line.h" #include "base/files/file_path.h" #include "base/files/file_util.h" @@ -120,8 +121,9 @@ .Run(app_user_model_id, link_items); scoped_refptr<OsIntegrationTestOverride> test_override = - GetOsIntegrationTestOverride(); + OsIntegrationTestOverride::Get(); if (test_override) { + CHECK_IS_TEST(); test_override->AddShortcutsMenuJumpListEntryForApp(app_user_model_id, link_items); } @@ -173,7 +175,7 @@ const std::vector<WebAppShortcutsMenuItemInfo>& shortcuts_menu_item_infos, const ShortcutsMenuIconBitmaps& shortcuts_menu_icon_bitmaps) { scoped_refptr<OsIntegrationTestOverride> test_override = - GetOsIntegrationTestOverride(); + OsIntegrationTestOverride::Get(); // Each entry in the ShortcutsMenu (JumpList on Windows) needs an icon in .ico // format. This helper writes these icon files to disk as a series of @@ -244,8 +246,9 @@ const base::FilePath& profile_path, RegisterShortcutsMenuCallback callback) { scoped_refptr<OsIntegrationTestOverride> test_override = - GetOsIntegrationTestOverride(); + OsIntegrationTestOverride::Get(); if (test_override) { + CHECK_IS_TEST(); test_override->DeleteShortcutsMenuJumpListEntryForApp( GenerateAppUserModelId(profile_path, app_id)); }
diff --git a/chrome/browser/web_applications/test/os_integration_test_override_impl.cc b/chrome/browser/web_applications/test/os_integration_test_override_impl.cc new file mode 100644 index 0000000..18f343cc --- /dev/null +++ b/chrome/browser/web_applications/test/os_integration_test_override_impl.cc
@@ -0,0 +1,840 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/web_applications/test/os_integration_test_override_impl.h" + +#include <codecvt> +#include <map> +#include <memory> +#include <ostream> +#include <string> +#include <tuple> +#include <vector> + +#include "base/check_is_test.h" +#include "base/containers/contains.h" +#include "base/containers/span.h" +#include "base/files/file_enumerator.h" +#include "base/files/file_path.h" +#include "base/files/file_util.h" +#include "base/files/scoped_temp_dir.h" +#include "base/functional/callback_helpers.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_refptr.h" +#include "base/no_destructor.h" +#include "base/run_loop.h" +#include "base/strings/string_util.h" +#include "base/synchronization/lock.h" +#include "base/threading/thread_restrictions.h" +#include "base/types/expected.h" +#include "build/build_config.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/web_applications/os_integration/os_integration_test_override.h" +#include "chrome/browser/web_applications/os_integration/web_app_file_handler_registration.h" +#include "chrome/browser/web_applications/web_app.h" +#include "chrome/browser/web_applications/web_app_icon_generator.h" +#include "chrome/browser/web_applications/web_app_icon_manager.h" +#include "chrome/browser/web_applications/web_app_id.h" +#include "chrome/browser/web_applications/web_app_install_info.h" +#include "chrome/browser/web_applications/web_app_provider.h" +#include "third_party/abseil-cpp/absl/types/optional.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "third_party/skia/include/core/SkColor.h" + +#if BUILDFLAG(IS_MAC) +#include <ImageIO/ImageIO.h> + +#include "base/files/scoped_temp_dir.h" +#include "base/mac/foundation_util.h" +#include "base/mac/scoped_cftyperef.h" +#include "chrome/browser/shell_integration.h" +#include "chrome/browser/web_applications/app_shim_registry_mac.h" +#include "net/base/filename_util.h" +#import "skia/ext/skia_utils_mac.h" +#endif + +#if BUILDFLAG(IS_WIN) +#include <windows.h> + +#include <shellapi.h> +#include "base/command_line.h" +#include "base/containers/contains.h" +#include "base/containers/flat_map.h" +#include "base/containers/flat_set.h" +#include "base/strings/strcat.h" +#include "base/strings/string_split.h" +#include "base/strings/stringprintf.h" +#include "base/strings/utf_string_conversions.h" +#include "base/win/registry.h" +#include "base/win/scoped_gdi_object.h" +#include "base/win/shortcut.h" +#include "base/win/windows_types.h" +#include "chrome/browser/web_applications/os_integration/web_app_handler_registration_utils_win.h" +#include "chrome/browser/web_applications/os_integration/web_app_uninstallation_via_os_settings_registration.h" +#include "chrome/browser/web_applications/web_app_helpers.h" +#include "chrome/browser/win/jumplist_updater.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/install_static/install_util.h" +#include "chrome/installer/util/shell_util.h" +#include "third_party/re2/src/re2/re2.h" +#include "ui/gfx/icon_util.h" +#endif + +namespace web_app { + +namespace { + +std::string GetAllFilesInDir(const base::FilePath& file_path) { + std::vector<std::string> files_as_strs; + base::FileEnumerator files(file_path, true, base::FileEnumerator::FILES); + for (base::FilePath current = files.Next(); !current.empty(); + current = files.Next()) { + files_as_strs.push_back(current.AsUTF8Unsafe()); + } + return base::JoinString(base::make_span(files_as_strs), "\n "); +} + +#if BUILDFLAG(IS_WIN) +base::FilePath GetShortcutProfile(base::FilePath shortcut_path) { + base::FilePath shortcut_profile; + std::wstring cmd_line_string; + if (base::win::ResolveShortcut(shortcut_path, nullptr, &cmd_line_string)) { + base::CommandLine shortcut_cmd_line = + base::CommandLine::FromString(L"program " + cmd_line_string); + shortcut_profile = + shortcut_cmd_line.GetSwitchValuePath(switches::kProfileDirectory); + } + return shortcut_profile; +} + +std::vector<std::wstring> GetFileExtensionsForProgId( + const std::wstring& file_handler_prog_id) { + const std::wstring prog_id_path = + base::StrCat({ShellUtil::kRegClasses, L"\\", file_handler_prog_id}); + + // Get list of handled file extensions from value FileExtensions at + // HKEY_CURRENT_USER\Software\Classes\<file_handler_prog_id>. + base::win::RegKey file_extensions_key(HKEY_CURRENT_USER, prog_id_path.c_str(), + KEY_QUERY_VALUE); + std::wstring handled_file_extensions; + LONG result = file_extensions_key.ReadValue(L"FileExtensions", + &handled_file_extensions); + CHECK_EQ(result, ERROR_SUCCESS); + + return base::SplitString(handled_file_extensions, std::wstring(L";"), + base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); +} +#endif + +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) +// Performs a blocking read of app icons from the disk. +SkColor IconManagerReadIconTopLeftColorForSize(WebAppIconManager& icon_manager, + const AppId& app_id, + SquareSizePx size_px) { + SkColor result = SK_ColorTRANSPARENT; + if (!icon_manager.HasIcons(app_id, IconPurpose::ANY, {size_px})) { + return result; + } + base::RunLoop run_loop; + icon_manager.ReadIcons( + app_id, IconPurpose::ANY, {size_px}, + base::BindOnce( + [](base::RunLoop* run_loop, SkColor* result, SquareSizePx size_px, + std::map<SquareSizePx, SkBitmap> icon_bitmaps) { + CHECK(base::Contains(icon_bitmaps, size_px)); + *result = icon_bitmaps.at(size_px).getColor(0, 0); + run_loop->Quit(); + }, + &run_loop, &result, size_px)); + run_loop.Run(); + return result; +} +#endif + +} // namespace + +OsIntegrationTestOverrideImpl::BlockingRegistration::BlockingRegistration() = + default; +OsIntegrationTestOverrideImpl::BlockingRegistration::~BlockingRegistration() { + base::ScopedAllowBlockingForTesting blocking; + base::RunLoop wait_until_destruction_loop; + // Lock the destrunction closure + { + base::AutoLock lock(test_override->destruction_closure_lock); + CHECK(!test_override->on_destruction_) + << "Cannot have multiple registrations at the same time."; + // Set the destruction closure for the scoped override object. + test_override->on_destruction_.ReplaceClosure( + wait_until_destruction_loop.QuitClosure()); + + // Unregister the override so new handles cannot be acquired. + OsIntegrationTestOverride::SetForTesting(nullptr); + } + + // Release the override & wait until all references are released. + // Note: The `test_override` MUST be released before waiting on the run + // loop, as then it will hang forever. + test_override.reset(); + wait_until_destruction_loop.Run(); +} + +// static +scoped_refptr<OsIntegrationTestOverrideImpl> +OsIntegrationTestOverrideImpl::Get() { + CHECK_IS_TEST(); + scoped_refptr<OsIntegrationTestOverride> current_override = + OsIntegrationTestOverride::Get(); + CHECK(current_override); + scoped_refptr<OsIntegrationTestOverrideImpl> test_override = + base::WrapRefCounted<OsIntegrationTestOverrideImpl>( + current_override->AsOsIntegrationTestOverrideImpl()); + CHECK(test_override); + return test_override; +} + +// static +std::unique_ptr<OsIntegrationTestOverrideImpl::BlockingRegistration> +OsIntegrationTestOverrideImpl::OverrideForTesting( + const base::FilePath& base_path) { + auto test_override = + base::WrapRefCounted(new OsIntegrationTestOverrideImpl(base_path)); + OsIntegrationTestOverride::SetForTesting(test_override); + std::unique_ptr<BlockingRegistration> registration = + std::make_unique<BlockingRegistration>(); + registration->test_override = std::move(test_override); + return registration; +} + +bool OsIntegrationTestOverrideImpl::SimulateDeleteShortcutsByUser( + Profile* profile, + const AppId& app_id, + const std::string& app_name) { +#if BUILDFLAG(IS_WIN) + base::FilePath desktop_shortcut_path = + GetShortcutPath(profile, desktop(), app_id, app_name); + CHECK(base::PathExists(desktop_shortcut_path)); + base::FilePath app_menu_shortcut_path = + GetShortcutPath(profile, application_menu(), app_id, app_name); + CHECK(base::PathExists(app_menu_shortcut_path)); + return base::DeleteFile(desktop_shortcut_path) && + base::DeleteFile(app_menu_shortcut_path); +#elif BUILDFLAG(IS_MAC) + base::FilePath app_folder_shortcut_path = + GetShortcutPath(profile, chrome_apps_folder(), app_id, app_name); + CHECK(base::PathExists(app_folder_shortcut_path)); + return base::DeletePathRecursively(app_folder_shortcut_path); +#elif BUILDFLAG(IS_LINUX) + base::FilePath desktop_shortcut_path = + GetShortcutPath(profile, desktop(), app_id, app_name); + LOG(INFO) << desktop_shortcut_path; + CHECK(base::PathExists(desktop_shortcut_path)); + return base::DeleteFile(desktop_shortcut_path); +#else + NOTREACHED() << "Not implemented on ChromeOS/Fuchsia "; + return true; +#endif +} + +bool OsIntegrationTestOverrideImpl::ForceDeleteAllShortcuts() { +#if BUILDFLAG(IS_WIN) + return DeleteDesktopDirOnWin() && DeleteApplicationMenuDirOnWin(); +#elif BUILDFLAG(IS_MAC) + return DeleteChromeAppsDir(); +#elif BUILDFLAG(IS_LINUX) + return DeleteDesktopDirOnLinux(); +#else + NOTREACHED() << "Not implemented on ChromeOS/Fuchsia "; + return true; +#endif +} + +#if BUILDFLAG(IS_MAC) +bool OsIntegrationTestOverrideImpl::DeleteChromeAppsDir() { + if (chrome_apps_folder_.IsValid()) { + return chrome_apps_folder_.Delete(); + } else { + return false; + } +} +#endif // BUILDFLAG(IS_MAC) + +#if BUILDFLAG(IS_WIN) +bool OsIntegrationTestOverrideImpl::DeleteDesktopDirOnWin() { + if (desktop_.IsValid()) { + return desktop_.Delete(); + } else { + return false; + } +} + +bool OsIntegrationTestOverrideImpl::DeleteApplicationMenuDirOnWin() { + if (application_menu_.IsValid()) { + return application_menu_.Delete(); + } else { + return false; + } +} +#endif // BUILDFLAG(IS_WIN) + +#if BUILDFLAG(IS_LINUX) +bool OsIntegrationTestOverrideImpl::DeleteDesktopDirOnLinux() { + if (desktop_.IsValid()) { + return desktop_.Delete(); + } else { + return false; + } +} +#endif // BUILDFLAG(IS_LINUX) + +bool OsIntegrationTestOverrideImpl::IsRunOnOsLoginEnabled( + Profile* profile, + const AppId& app_id, + const std::string& app_name) { +#if BUILDFLAG(IS_LINUX) + std::string shortcut_filename = + "chrome-" + app_id + "-" + profile->GetBaseName().value() + ".desktop"; + return base::PathExists(startup().Append(shortcut_filename)); +#elif BUILDFLAG(IS_WIN) + base::FilePath startup_shortcut_path = + GetShortcutPath(profile, startup(), app_id, app_name); + return base::PathExists(startup_shortcut_path); +#elif BUILDFLAG(IS_MAC) + std::string shortcut_filename = app_name + ".app"; + base::FilePath app_shortcut_path = + chrome_apps_folder().Append(shortcut_filename); + return startup_enabled_[app_shortcut_path]; +#else + NOTREACHED() << "Not implemented on ChromeOS/Fuchsia "; + return true; +#endif +} + +bool OsIntegrationTestOverrideImpl::IsFileExtensionHandled( + Profile* profile, + const AppId& app_id, + std::string app_name, + std::string file_extension) { + base::ScopedAllowBlockingForTesting allow_blocking; + bool is_file_handled = false; +#if BUILDFLAG(IS_WIN) + const std::wstring prog_id = GetProgIdForApp(profile->GetPath(), app_id); + const std::vector<std::wstring> file_handler_prog_ids = + ShellUtil::GetFileHandlerProgIdsForAppId(prog_id); + const std::wstring extension = base::UTF8ToWide(file_extension); + base::win::RegKey key; + for (const auto& file_handler_prog_id : file_handler_prog_ids) { + const std::vector<std::wstring> supported_file_extensions = + GetFileExtensionsForProgId(file_handler_prog_id); + if (base::Contains(supported_file_extensions, extension)) { + const std::wstring reg_key = std::wstring(ShellUtil::kRegClasses) + + base::FilePath::kSeparators[0] + extension + + base::FilePath::kSeparators[0] + + ShellUtil::kRegOpenWithProgids; + LONG result = key.Open(HKEY_CURRENT_USER, reg_key.data(), KEY_READ); + CHECK_EQ(ERROR_SUCCESS, result); + return key.HasValue(file_handler_prog_id.data()); + } + } +#elif BUILDFLAG(IS_MAC) + const base::FilePath test_file_path = + chrome_apps_folder().AppendASCII("test" + file_extension); + const base::File test_file( + test_file_path, base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE); + const GURL test_file_url = net::FilePathToFileURL(test_file_path); + base::FilePath app_path = + GetShortcutPath(profile, chrome_apps_folder(), app_id, app_name); + is_file_handled = + shell_integration::CanApplicationHandleURL(app_path, test_file_url); + base::DeleteFile(test_file_path); +#elif BUILDFLAG(IS_LINUX) + base::FilePath user_applications_dir = + applications_dir().Append("applications"); + bool database_update_called = false; + for (const LinuxFileRegistration& command : linux_file_registration_) { + if (base::Contains(command.xdg_command, app_id) && + base::Contains(command.xdg_command, + profile->GetPath().BaseName().value())) { + if (base::StartsWith(command.xdg_command, "xdg-mime install")) { + is_file_handled = base::Contains(command.file_contents, + "\"*" + file_extension + "\""); + } else { + CHECK(base::StartsWith(command.xdg_command, "xdg-mime uninstall")) + << command.xdg_command; + is_file_handled = false; + } + } + + // Verify if the mimeinfo.cache is also updated. See + // web_app_file_handler_registration_linux.cc for more information. + if (base::StartsWith(command.xdg_command, "update-desktop-database")) { + database_update_called = + base::Contains(command.xdg_command, user_applications_dir.value()); + } + } + is_file_handled = is_file_handled && database_update_called; +#endif + return is_file_handled; +} + +absl::optional<SkColor> +OsIntegrationTestOverrideImpl::GetShortcutIconTopLeftColor( + Profile* profile, + base::FilePath shortcut_dir, + const AppId& app_id, + const std::string& app_name, + SquareSizePx size_px) { +#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) + base::FilePath shortcut_path = + GetShortcutPath(profile, shortcut_dir, app_id, app_name); + if (!base::PathExists(shortcut_path)) { + return absl::nullopt; + } + return GetIconTopLeftColorFromShortcutFile(shortcut_path); +#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) + WebAppProvider* provider = WebAppProvider::GetForLocalAppsUnchecked(profile); + if (!provider) { + return absl::nullopt; + } + return IconManagerReadIconTopLeftColorForSize(provider->icon_manager(), + app_id, size_px); +#else + NOTREACHED() << "Not implemented on Fuchsia"; + return absl::nullopt; +#endif +} + +base::FilePath OsIntegrationTestOverrideImpl::GetShortcutPath( + Profile* profile, + base::FilePath shortcut_dir, + const AppId& app_id, + const std::string& app_name) { +#if BUILDFLAG(IS_WIN) + base::FileEnumerator enumerator(shortcut_dir, false, + base::FileEnumerator::FILES); + while (!enumerator.Next().empty()) { + const std::wstring shortcut_filename = + enumerator.GetInfo().GetName().value(); + const std::string narrowed_filename = + base::WideToUTF8(enumerator.GetInfo().GetName().value()); + if (re2::RE2::FullMatch(narrowed_filename, app_name + "(.*).lnk")) { + base::FilePath shortcut_path = shortcut_dir.Append(shortcut_filename); + if (GetShortcutProfile(shortcut_path) == profile->GetBaseName()) { + return shortcut_path; + } + } + } +#elif BUILDFLAG(IS_MAC) + std::string shortcut_filename = app_name + ".app"; + base::FilePath shortcut_path = shortcut_dir.Append(shortcut_filename); + // Exits early if the app id is empty because the verification won't work. + // TODO(crbug.com/1289865): Figure a way to find the profile that has the app + // installed without using app ID. + if (app_id.empty()) { + return shortcut_path; + } + + AppShimRegistry* registry = AppShimRegistry::Get(); + std::set<base::FilePath> app_installed_profiles = + registry->GetInstalledProfilesForApp(app_id); + if (app_installed_profiles.find(profile->GetPath()) != + app_installed_profiles.end()) { + return shortcut_path; + } +#elif BUILDFLAG(IS_LINUX) + std::string shortcut_filename = + "chrome-" + app_id + "-" + profile->GetBaseName().value() + ".desktop"; + base::FilePath shortcut_path = shortcut_dir.Append(shortcut_filename); + if (base::PathExists(shortcut_path)) { + return shortcut_path; + } +#endif + return base::FilePath(); +} + +bool OsIntegrationTestOverrideImpl::IsShortcutCreated( + Profile* profile, + const AppId& app_id, + const std::string& app_name) { +#if BUILDFLAG(IS_WIN) + base::FilePath desktop_shortcut_path = + GetShortcutPath(profile, desktop(), app_id, app_name); + base::FilePath application_menu_shortcut_path = + GetShortcutPath(profile, application_menu(), app_id, app_name); + return (base::PathExists(desktop_shortcut_path) && + base::PathExists(application_menu_shortcut_path)); +#elif BUILDFLAG(IS_MAC) + base::FilePath app_shortcut_path = + GetShortcutPath(profile, chrome_apps_folder(), app_id, app_name); + return base::PathExists(app_shortcut_path); +#elif BUILDFLAG(IS_LINUX) + base::FilePath desktop_shortcut_path = + GetShortcutPath(profile, desktop(), app_id, app_name); + return base::PathExists(desktop_shortcut_path); +#else + NOTREACHED() << "Not implemented on ChromeOS/Fuchsia "; + return true; +#endif +} + +bool OsIntegrationTestOverrideImpl::AreShortcutsMenuRegistered() { + return !shortcut_menu_apps_registered_.empty(); +} + +#if BUILDFLAG(IS_WIN) + +std::vector<SkColor> +OsIntegrationTestOverrideImpl::GetIconColorsForShortcutsMenu( + const std::wstring& app_user_model_id) { + CHECK(IsShortcutsMenuRegisteredForApp(app_user_model_id)); + std::vector<SkColor> icon_colors; + for (auto& shell_link_item : jump_list_entry_map_[app_user_model_id]) { + icon_colors.emplace_back( + ReadColorFromShortcutMenuIcoFile(shell_link_item->icon_path())); + } + return icon_colors; +} + +int OsIntegrationTestOverrideImpl::GetCountOfShortcutIconsCreated( + const std::wstring& app_user_model_id) { + CHECK(IsShortcutsMenuRegisteredForApp(app_user_model_id)); + return jump_list_entry_map_[app_user_model_id].size(); +} + +bool OsIntegrationTestOverrideImpl::IsShortcutsMenuRegisteredForApp( + const std::wstring& app_user_model_id) { + return base::Contains(jump_list_entry_map_, app_user_model_id); +} + +base::expected<bool, std::string> +OsIntegrationTestOverrideImpl::IsUninstallRegisteredWithOs( + const AppId& app_id, + const std::string& app_name, + Profile* profile) { + constexpr wchar_t kUninstallRegistryKey[] = + L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall"; + + base::win::RegKey uninstall_reg_key; + LONG result = uninstall_reg_key.Open(HKEY_CURRENT_USER, kUninstallRegistryKey, + KEY_READ); + + if (result == ERROR_FILE_NOT_FOUND) { + return base::unexpected( + "Cannot find the uninstall registry key. If a testing hive is being " + "used, then this key needs to be created there on initialization."); + } + + if (result != ERROR_SUCCESS) { + return base::unexpected( + base::StringPrintf("Cannot open the registry key: %ld", result)); + } + + const std::wstring key = + GetUninstallStringKeyForTesting(profile->GetPath(), app_id); + + base::win::RegKey uninstall_reg_entry_key; + result = uninstall_reg_entry_key.Open(uninstall_reg_key.Handle(), key.c_str(), + KEY_READ); + if (result == ERROR_FILE_NOT_FOUND) { + return base::ok(false); + } + + if (result != ERROR_SUCCESS) { + return base::unexpected( + base::StringPrintf("Error opening uninstall key for app: %ld", result)); + } + + std::wstring display_icon_path; + std::wstring display_name; + std::wstring display_version; + std::wstring application_version; + std::wstring publisher; + std::wstring uninstall_string; + DWORD no_repair; + DWORD no_modify; + bool read_success = true; + read_success &= uninstall_reg_entry_key.ReadValue( + L"DisplayIcon", &display_icon_path) == ERROR_SUCCESS; + read_success &= uninstall_reg_entry_key.ReadValue( + L"DisplayName", &display_name) == ERROR_SUCCESS; + read_success &= uninstall_reg_entry_key.ReadValue( + L"DisplayVersion", &display_version) == ERROR_SUCCESS; + read_success &= + uninstall_reg_entry_key.ReadValue(L"ApplicationVersion", + &application_version) == ERROR_SUCCESS; + read_success &= uninstall_reg_entry_key.ReadValue(L"Publisher", &publisher) == + ERROR_SUCCESS; + read_success &= uninstall_reg_entry_key.ReadValue( + L"UninstallString", &uninstall_string) == ERROR_SUCCESS; + read_success &= uninstall_reg_entry_key.ReadValueDW( + L"NoRepair", &no_repair) == ERROR_SUCCESS; + read_success &= uninstall_reg_entry_key.ReadValueDW( + L"NoModify", &no_modify) == ERROR_SUCCESS; + if (!read_success) { + return base::unexpected("Error reading registry values"); + } + + if (display_version != L"1.0" || application_version != L"1.0" || + no_repair != 1 || no_modify != 1 || + publisher != install_static::GetChromeInstallSubDirectory()) { + return base::unexpected("Incorrect static registry data."); + } + + base::FilePath web_app_icon_dir = GetOsIntegrationResourcesDirectoryForApp( + profile->GetPath(), app_id, GURL()); + base::FilePath expected_icon_path = + internals::GetIconFilePath(web_app_icon_dir, base::UTF8ToUTF16(app_name)); + if (expected_icon_path.value() != display_icon_path) { + return base::unexpected(base::StrCat( + {"Invalid icon path ", base::WideToUTF8(display_icon_path), + ", expected ", base::WideToUTF8(expected_icon_path.value())})); + } + if (base::UTF8ToWide(app_name) != display_name) { + return base::unexpected( + base::StrCat({"Invalid display name ", base::WideToUTF8(display_name), + ", expected ", app_name})); + } + std::wstring expected_uninstall_substr = + base::StrCat({L"--uninstall-app-id=", base::UTF8ToWide(app_id)}); + if (!base::Contains(uninstall_string, expected_uninstall_substr)) { + return base::unexpected(base::StrCat({"Could not find uninstall flag: ", + base::WideToUTF8(uninstall_string)})); + } + + return true; +} +#endif // BUILDFLAG(IS_WIN) + +const OsIntegrationTestOverrideImpl::AppProtocolList& +OsIntegrationTestOverrideImpl::protocol_scheme_registrations() { + return protocol_scheme_registrations_; +} + +OsIntegrationTestOverrideImpl* +OsIntegrationTestOverrideImpl::AsOsIntegrationTestOverrideImpl() { + return this; +} + +#if BUILDFLAG(IS_WIN) +void OsIntegrationTestOverrideImpl::AddShortcutsMenuJumpListEntryForApp( + const std::wstring& app_user_model_id, + const std::vector<scoped_refptr<ShellLinkItem>>& shell_link_items) { + jump_list_entry_map_[app_user_model_id] = shell_link_items; + shortcut_menu_apps_registered_.emplace(app_user_model_id); +} + +void OsIntegrationTestOverrideImpl::DeleteShortcutsMenuJumpListEntryForApp( + const std::wstring& app_user_model_id) { + jump_list_entry_map_.erase(app_user_model_id); + shortcut_menu_apps_registered_.erase(app_user_model_id); +} +const base::FilePath& OsIntegrationTestOverrideImpl::desktop() { + return desktop_.GetPath(); +} +const base::FilePath& OsIntegrationTestOverrideImpl::application_menu() { + return application_menu_.GetPath(); +} +const base::FilePath& OsIntegrationTestOverrideImpl::quick_launch() { + return quick_launch_.GetPath(); +} +const base::FilePath& OsIntegrationTestOverrideImpl::startup() { + return startup_.GetPath(); +} +#endif // BUILDFLAG(IS_WIN) + +#if BUILDFLAG(IS_MAC) +bool OsIntegrationTestOverrideImpl::IsChromeAppsValid() { + return chrome_apps_folder_.IsValid(); +} +const base::FilePath& OsIntegrationTestOverrideImpl::chrome_apps_folder() { + return chrome_apps_folder_.GetPath(); +} +void OsIntegrationTestOverrideImpl::EnableOrDisablePathOnLogin( + const base::FilePath& file_path, + bool enable_on_login) { + startup_enabled_[file_path] = enable_on_login; +} +#endif // BUILDFLAG(IS_MAC) + +#if BUILDFLAG(IS_LINUX) +const base::FilePath& OsIntegrationTestOverrideImpl::desktop() { + return desktop_.GetPath(); +} +const base::FilePath& OsIntegrationTestOverrideImpl::startup() { + return startup_.GetPath(); +} +const base::FilePath& OsIntegrationTestOverrideImpl::applications_dir() { + return applications_dir_.GetPath(); +} +#endif // BUILDFLAG(IS_LINUX) + +void OsIntegrationTestOverrideImpl::RegisterProtocolSchemes( + const AppId& app_id, + std::vector<std::string> protocols) { + protocol_scheme_registrations_.emplace_back(app_id, std::move(protocols)); +} + +OsIntegrationTestOverrideImpl::OsIntegrationTestOverrideImpl( + const base::FilePath& base_path) { + // Initialize all directories used. The success & the CHECK are separated to + // ensure that these function calls occur on release builds. + if (!base_path.empty()) { +#if BUILDFLAG(IS_WIN) + bool success = desktop_.CreateUniqueTempDirUnderPath(base_path); + CHECK(success); + success = application_menu_.CreateUniqueTempDirUnderPath(base_path); + CHECK(success); + success = quick_launch_.CreateUniqueTempDirUnderPath(base_path); + CHECK(success); + success = startup_.CreateUniqueTempDirUnderPath(base_path); + CHECK(success); +#elif BUILDFLAG(IS_MAC) + bool success = chrome_apps_folder_.CreateUniqueTempDirUnderPath(base_path); + CHECK(success); +#elif BUILDFLAG(IS_LINUX) + bool success = desktop_.CreateUniqueTempDirUnderPath(base_path); + CHECK(success); + success = startup_.CreateUniqueTempDirUnderPath(base_path); + CHECK(success); + success = applications_dir_.CreateUniqueTempDirUnderPath(base_path); + CHECK(success); +#endif + } else { +#if BUILDFLAG(IS_WIN) + bool success = desktop_.CreateUniqueTempDir(); + CHECK(success); + success = application_menu_.CreateUniqueTempDir(); + CHECK(success); + success = quick_launch_.CreateUniqueTempDir(); + CHECK(success); + success = startup_.CreateUniqueTempDir(); + CHECK(success); +#elif BUILDFLAG(IS_MAC) + bool success = chrome_apps_folder_.CreateUniqueTempDir(); + CHECK(success); +#elif BUILDFLAG(IS_LINUX) + bool success = desktop_.CreateUniqueTempDir(); + CHECK(success); + success = startup_.CreateUniqueTempDir(); + CHECK(success); + success = applications_dir_.CreateUniqueTempDir(); + CHECK(success); +#endif + } + +#if BUILDFLAG(IS_LINUX) + auto callback = base::BindRepeating([](base::FilePath filename_in, + std::string xdg_command, + std::string file_contents) { + auto test_override = OsIntegrationTestOverrideImpl::Get(); + CHECK(test_override); + LinuxFileRegistration file_registration = LinuxFileRegistration(); + file_registration.file_name = filename_in; + file_registration.xdg_command = xdg_command; + file_registration.file_contents = file_contents; + test_override->linux_file_registration_.push_back(file_registration); + return true; + }); + SetUpdateMimeInfoDatabaseOnLinuxCallbackForTesting(std::move(callback)); +#endif +} + +OsIntegrationTestOverrideImpl::~OsIntegrationTestOverrideImpl() { + std::vector<base::ScopedTempDir*> directories; +#if BUILDFLAG(IS_WIN) + directories = {&desktop_, &application_menu_, &quick_launch_, &startup_}; +#elif BUILDFLAG(IS_MAC) + directories = {&chrome_apps_folder_}; + // Checks and cleans up possible hidden files in directories. + std::vector<std::string> hidden_files{"Icon\r", ".localized"}; + for (base::ScopedTempDir* dir : directories) { + if (dir->IsValid()) { + for (auto& f : hidden_files) { + base::FilePath path = dir->GetPath().Append(f); + if (base::PathExists(path)) { + base::DeletePathRecursively(path); + } + } + } + } +#elif BUILDFLAG(IS_LINUX) + // Reset the file handling callback. + SetUpdateMimeInfoDatabaseOnLinuxCallbackForTesting( + UpdateMimeInfoDatabaseOnLinuxCallback()); + directories = {&desktop_, &applications_dir_}; +#endif + for (base::ScopedTempDir* dir : directories) { + if (!dir->IsValid()) { + continue; + } + CHECK(base::IsDirectoryEmpty(dir->GetPath())) + << "Directory not empty: " << dir->GetPath().AsUTF8Unsafe() + << ". Please uninstall all webapps that have been installed while " + "shortcuts were overriden. Contents:\n" + << GetAllFilesInDir(dir->GetPath()); + } + { + base::AutoLock lock(destruction_closure_lock); + on_destruction_.RunAndReset(); + } +} + +#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) +SkColor OsIntegrationTestOverrideImpl::GetIconTopLeftColorFromShortcutFile( + const base::FilePath& shortcut_path) { + CHECK(base::PathExists(shortcut_path)); +#if BUILDFLAG(IS_MAC) + base::FilePath icon_path = + shortcut_path.AppendASCII("Contents/Resources/app.icns"); + base::ScopedCFTypeRef<CFDictionaryRef> empty_dict( + CFDictionaryCreate(nullptr, nullptr, nullptr, 0, nullptr, nullptr)); + base::ScopedCFTypeRef<CFURLRef> url = base::mac::FilePathToCFURL(icon_path); + base::ScopedCFTypeRef<CGImageSourceRef> source( + CGImageSourceCreateWithURL(url, nullptr)); + if (!source) { + return 0; + } + // Get the first icon in the .icns file (index 0) + base::ScopedCFTypeRef<CGImageRef> cg_image( + CGImageSourceCreateImageAtIndex(source, 0, empty_dict)); + if (!cg_image) { + return 0; + } + SkBitmap bitmap = skia::CGImageToSkBitmap(cg_image); + if (bitmap.empty()) { + return 0; + } + return bitmap.getColor(0, 0); +#elif BUILDFLAG(IS_WIN) + SHFILEINFO file_info = {0}; + if (SHGetFileInfo(shortcut_path.value().c_str(), FILE_ATTRIBUTE_NORMAL, + &file_info, sizeof(file_info), + SHGFI_ICON | 0 | SHGFI_USEFILEATTRIBUTES)) { + const SkBitmap bitmap = IconUtil::CreateSkBitmapFromHICON(file_info.hIcon); + if (bitmap.empty()) { + return 0; + } + return bitmap.getColor(0, 0); + } else { + return 0; + } +#endif +} +#endif + +#if BUILDFLAG(IS_WIN) +SkColor OsIntegrationTestOverrideImpl::ReadColorFromShortcutMenuIcoFile( + const base::FilePath& file_path) { + HICON icon = static_cast<HICON>( + LoadImage(NULL, file_path.value().c_str(), IMAGE_ICON, 32, 32, + LR_LOADTRANSPARENT | LR_LOADFROMFILE)); + base::win::ScopedHICON scoped_icon(icon); + SkBitmap output_image = + IconUtil::CreateSkBitmapFromHICON(scoped_icon.get(), gfx::Size(32, 32)); + SkColor color = output_image.getColor(output_image.dimensions().width() / 2, + output_image.dimensions().height() / 2); + return color; +} +#endif + +} // namespace web_app
diff --git a/chrome/browser/web_applications/test/os_integration_test_override_impl.h b/chrome/browser/web_applications/test/os_integration_test_override_impl.h new file mode 100644 index 0000000..6aafb81 --- /dev/null +++ b/chrome/browser/web_applications/test/os_integration_test_override_impl.h
@@ -0,0 +1,308 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_WEB_APPLICATIONS_TEST_OS_INTEGRATION_TEST_OVERRIDE_IMPL_H_ +#define CHROME_BROWSER_WEB_APPLICATIONS_TEST_OS_INTEGRATION_TEST_OVERRIDE_IMPL_H_ + +#include <map> +#include <memory> +#include <string> +#include <tuple> +#include <vector> + +#include "base/containers/flat_set.h" +#include "base/files/file_path.h" +#include "base/files/scoped_temp_dir.h" +#include "base/functional/callback_helpers.h" +#include "base/memory/ref_counted.h" +#include "base/types/expected.h" +#include "build/build_config.h" +#include "chrome/browser/web_applications/os_integration/os_integration_test_override.h" +#include "chrome/browser/web_applications/web_app_icon_generator.h" +#include "chrome/browser/web_applications/web_app_id.h" +#include "chrome/browser/web_applications/web_app_install_info.h" +#include "third_party/abseil-cpp/absl/types/optional.h" +#include "third_party/skia/include/core/SkColor.h" + +#if BUILDFLAG(IS_WIN) +#include "base/containers/flat_map.h" +#endif + +class Profile; + +#if BUILDFLAG(IS_WIN) +class ShellLinkItem; +#endif + +namespace web_app { + +#if BUILDFLAG(IS_LINUX) +struct LinuxFileRegistration { + base::FilePath file_name; + std::string xdg_command; + std::string file_contents; +}; +#endif + +// See the `OsIntegrationTestOverride` base class documentation for more +// information about the purpose of this class. This is the implementation, and +// being test-only can include test-only code. +// +// Other than inheriting the base class & providing implementations of those +// getters & setters, this class is also responsible for providing common ways +// of checking the OS integration state in a test. The class methods are +// organized per-os-integration. +class OsIntegrationTestOverrideImpl : public OsIntegrationTestOverride { + public: + using AppProtocolList = + std::vector<std::tuple<AppId, std::vector<std::string>>>; +#if BUILDFLAG(IS_WIN) + using JumpListEntryMap = + base::flat_map<std::wstring, std::vector<scoped_refptr<ShellLinkItem>>>; +#endif + // Destroying this class blocks the thread until all users of + // OsIntegrationTestOverride::Get() have destroyed any saved + // `scoped_refptr<OsIntegrationTestOverride>`. + struct BlockingRegistration { + BlockingRegistration(); + ~BlockingRegistration(); + + scoped_refptr<OsIntegrationTestOverrideImpl> test_override; + }; + + // Returns the current test override. This will CHECK-fail if one does not + // exist. + static scoped_refptr<OsIntegrationTestOverrideImpl> Get(); + + // Overrides applicable directories for shortcut integration and returns an + // object that: + // 1) Contains the directories. + // 2) Keeps the override active until the object is destroyed. + // 3) DCHECK-fails on destruction if any of the shortcut directories / os + // hooks are NOT cleanup by the test. This ensures that trybots don't have + // old test artifacts on them that can make future tests flaky. + // All installs that occur during the lifetime of the + // OsIntegrationTestOverrideImpl MUST be uninstalled before it is + // destroyed. + // The returned value, on destruction, will block until all usages of the + // OsIntegrationTestOverride::Get() are destroyed. + static std::unique_ptr<BlockingRegistration> OverrideForTesting( + const base::FilePath& base_path = base::FilePath()); + + // ------------------------------- + // === Simulating user actions === + // ------------------------------- + // These methods simulate users doing the given action on the operating + // system. + + // Delete shortcuts stored in the test override for a specific app. This + // should only be run on Windows, Mac and Linux. + bool SimulateDeleteShortcutsByUser(Profile* profile, + const AppId& app_id, + const std::string& app_name); + + // Used to clear all shortcut override paths during tests. This should only be + // run on Windows, Mac and Linux. + bool ForceDeleteAllShortcuts(); + +#if BUILDFLAG(IS_MAC) + bool DeleteChromeAppsDir(); +#endif // BUILDFLAG(IS_MAC) + +#if BUILDFLAG(IS_WIN) + bool DeleteDesktopDirOnWin(); + bool DeleteApplicationMenuDirOnWin(); +#endif // BUILDFLAG(IS_WIN) + +#if BUILDFLAG(IS_LINUX) + bool DeleteDesktopDirOnLinux(); +#endif // BUILDFLAG(IS_LINUX) + + // ------------------------------- + // === Run on OS Login === + // ------------------------------- + + // Looks into shortcuts stored for OS integration and returns if run on OS + // login mode is enabled based on the location. This should only be run on + // Windows, Mac and Linux. + bool IsRunOnOsLoginEnabled(Profile* profile, + const AppId& app_id, + const std::string& app_name); + + // ------------------------------- + // === File Handling === + // ------------------------------- + + bool IsFileExtensionHandled(Profile* profile, + const AppId& app_id, + std::string app_name, + std::string file_extension); + + // ------------------------------- + // === Shortcuts === + // ------------------------------- + + // Reads the icon color for a specific shortcut that has been created. + // For Mac and Win, the shortcut_dir field is mandatory. For all other OSes, + // this can be an empty base::FilePath(). + // For ChromeOS and Linux, the size_px field is mandatory to prevent erroneous + // results. For all other OSes, the field can be skipped. The default value of + // size_px is usually filled up with kLauncherIconSize (see + // chrome/browser/web_applications/web_app_icon_generator.h for more + // information), which is 128. + absl::optional<SkColor> GetShortcutIconTopLeftColor( + Profile* profile, + base::FilePath shortcut_dir, + const AppId& app_id, + const std::string& app_name, + SquareSizePx size_px = icon_size::k128); + + // Gets the current shortcut path based on a shortcut directory, app_id and + // app_name. This should only be run on Windows, Mac and Linux. + base::FilePath GetShortcutPath(Profile* profile, + base::FilePath shortcut_dir, + const AppId& app_id, + const std::string& app_name); + + // Looks into the current shortcut paths to determine if a shortcut has + // been created or not. This should only be run on Windows, Mac and Linux. + // TODO(crbug.com/1425967): Add PList parsing logic for Mac shortcut checking. + bool IsShortcutCreated(Profile* profile, + const AppId& app_id, + const std::string& app_name); + + // --------------------------------- + // === Shortcut menu / jump list === + // --------------------------------- + + bool AreShortcutsMenuRegistered(); + +#if BUILDFLAG(IS_WIN) + std::vector<SkColor> GetIconColorsForShortcutsMenu( + const std::wstring& app_user_model_id); + int GetCountOfShortcutIconsCreated(const std::wstring& app_user_model_id); + bool IsShortcutsMenuRegisteredForApp(const std::wstring& app_user_model_id); +#endif // BUILDFLAG(IS_WIN) + + // ------------------------------ + // === Uninstall Registration === + // ------------------------------ + +#if BUILDFLAG(IS_WIN) + // Returns true if the given app_id/name/profile is registered with the OS in + // the uninstall menu, and false if it isn't. The unexpected value is a string + // description of the error. + base::expected<bool, std::string> IsUninstallRegisteredWithOs( + const AppId& app_id, + const std::string& app_name, + Profile* profile); +#endif // BUILDFLAG(IS_WIN) + + // ------------------------- + // === Protocol Handlers === + // ------------------------- + + const AppProtocolList& protocol_scheme_registrations(); + + // --------------------------------- + // === OsIntegrationTestOverride === + // --------------------------------- + + OsIntegrationTestOverrideImpl* AsOsIntegrationTestOverrideImpl() override; + +#if BUILDFLAG(IS_WIN) + // These should not be called from tests, these are automatically + // called from production code in testing to set + // up OS integration data for shortcuts menu registration and + // unregistration. + void AddShortcutsMenuJumpListEntryForApp( + const std::wstring& app_user_model_id, + const std::vector<scoped_refptr<ShellLinkItem>>& shell_link_items) + override; + void DeleteShortcutsMenuJumpListEntryForApp( + const std::wstring& app_user_model_id) override; +#endif + +#if BUILDFLAG(IS_WIN) + const base::FilePath& desktop() override; + const base::FilePath& application_menu() override; + const base::FilePath& quick_launch() override; + const base::FilePath& startup() override; +#elif BUILDFLAG(IS_MAC) + bool IsChromeAppsValid() override; + const base::FilePath& chrome_apps_folder() override; + void EnableOrDisablePathOnLogin(const base::FilePath& file_path, + bool enable_on_login) override; +#elif BUILDFLAG(IS_LINUX) + const base::FilePath& desktop() override; + const base::FilePath& startup() override; + const base::FilePath& applications_dir() override; +#endif + + // Creates a tuple of app_id to protocols and adds it to the vector + // of registered protocols. There can be multiple entries for the same + // app_id. + void RegisterProtocolSchemes(const AppId& app_id, + std::vector<std::string> protocols) override; + + private: + friend class base::RefCountedThreadSafe<OsIntegrationTestOverrideImpl>; + + explicit OsIntegrationTestOverrideImpl(const base::FilePath& base_path); + ~OsIntegrationTestOverrideImpl() override; + +#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) + // Reads an icon file (.ico/.png/.icns) and returns the color at the + // top left position (0,0). + SkColor GetIconTopLeftColorFromShortcutFile( + const base::FilePath& shortcut_path); +#endif + +#if BUILDFLAG(IS_WIN) + SkColor ReadColorFromShortcutMenuIcoFile(const base::FilePath& file_path); +#endif + +#if BUILDFLAG(IS_WIN) + base::ScopedTempDir desktop_; + base::ScopedTempDir application_menu_; + base::ScopedTempDir quick_launch_; + base::ScopedTempDir startup_; + + // Records all ShellLinkItems for a given AppUserModelId for handling + // shortcuts menu registration. + JumpListEntryMap jump_list_entry_map_; + +#elif BUILDFLAG(IS_MAC) + base::ScopedTempDir chrome_apps_folder_; + std::map<base::FilePath, bool> startup_enabled_; + +#elif BUILDFLAG(IS_LINUX) + base::ScopedTempDir desktop_; + base::ScopedTempDir startup_; + base::ScopedTempDir applications_dir_; + std::vector<LinuxFileRegistration> linux_file_registration_; +#endif + + // Records all registration events for a given app id & protocol list. Due to + // simplification on the OS-side, unregistrations are not recorded, and + // instead this list can be checked for an empty registration. + AppProtocolList protocol_scheme_registrations_; + + base::flat_set<std::wstring> shortcut_menu_apps_registered_; + + // `on_destruction_` has it's closure set only once (when BlockingRegistration + // is destroyed) and executed when OsIntegrationTestOverrideImpl is destroyed. + // The destructor of BlockingRegistration + // - Gets the lock to prevent multi-thread issues. + // - Sets `on_destruction_` using a run loop. + // - Destroys this object + // - When waits on the closure to ensure destruction has completed everywhere. + base::Lock destruction_closure_lock; + base::ScopedClosureRunner on_destruction_ + GUARDED_BY(destruction_closure_lock); +}; + +} // namespace web_app + +#endif // CHROME_BROWSER_WEB_APPLICATIONS_TEST_OS_INTEGRATION_TEST_OVERRIDE_IMPL_H_
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt index 6f8104f5..562cec8 100644 --- a/chrome/build/linux.pgo.txt +++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@ -chrome-linux-main-1681386955-f0512a98defae96d024b992245588a2bcf3f03a7.profdata +chrome-linux-main-1681408779-a51ca6409bd52549bc0a4dfabd8d7100f1800a42.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt index 9c3767e..642d6b74 100644 --- a/chrome/build/mac-arm.pgo.txt +++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@ -chrome-mac-arm-main-1681408779-19562355795693dc9271fba711025a47c2a3373e.profdata +chrome-mac-arm-main-1681415994-3afce92f72a711deeb417a8f712f8335adf11ebb.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt index 129b030..352e127 100644 --- a/chrome/build/mac.pgo.txt +++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@ -chrome-mac-main-1681386955-633432fea5f3f479a217505b0fb5a28cb4c081af.profdata +chrome-mac-main-1681408779-ea51d93c73ced0c9764685b502df06d179a75775.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt index e706f7a..29c1d5b 100644 --- a/chrome/build/win32.pgo.txt +++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@ -chrome-win32-main-1681397997-e43e6f3cbcaa1aa4b0d5bae4dfd28e661595bd29.profdata +chrome-win32-main-1681408779-df528b372f44a09535f7b91fa49ac4eea82569c9.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt index 1b04ce3..5110e28 100644 --- a/chrome/build/win64.pgo.txt +++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@ -chrome-win64-main-1681397997-1a8c5ec9d0f5a3f3ea4e108a5fc9e8ee887cae84.profdata +chrome-win64-main-1681408779-3d41b8eead752c812455d8a446463aa32e46c96a.profdata
diff --git a/chrome/chrome_paks.gni b/chrome/chrome_paks.gni index 69782d1..dfa978fc 100644 --- a/chrome/chrome_paks.gni +++ b/chrome/chrome_paks.gni
@@ -12,6 +12,7 @@ import("//headless/headless.gni") import("//pdf/features.gni") import("//ui/base/ui_features.gni") +import("//ui/webui/webui_features.gni") import("chrome_repack_locales.gni") # Generates a rule to repack a set of resources, substituting a given string @@ -246,6 +247,12 @@ "//chrome/browser/resources/media_router/cast_feedback:resources", ] } + if (!optimize_webui) { + # Only add when optimize_webui=false, since in other cases the same + # resources are already bundled within the UIs that use them. + sources += [ "$root_gen_dir/chrome/settings_shared_resources.pak" ] + deps += [ "//chrome/browser/resources/settings_shared:resources" ] + } } if (is_chromeos_ash) { sources += [
diff --git a/chrome/common/mac/app_shim.mojom b/chrome/common/mac/app_shim.mojom index d323260..84f3867c 100644 --- a/chrome/common/mac/app_shim.mojom +++ b/chrome/common/mac/app_shim.mojom
@@ -130,6 +130,10 @@ // Sent when the app should be opened with an override url (e.g. // user clicks on an item in the application dock menu). OpenAppWithOverrideUrl(url.mojom.Url override_url); + + // Sent when the app is about to terminate. Used to persist what profiles + // where open when the app was terminated. + ApplicationWillTerminate(); }; // Properties of an app shim that are specified when it connects to the browser
diff --git a/chrome/services/sharing/nearby/quick_start_decoder/BUILD.gn b/chrome/services/sharing/nearby/quick_start_decoder/BUILD.gn index cb0d627..93701d8 100644 --- a/chrome/services/sharing/nearby/quick_start_decoder/BUILD.gn +++ b/chrome/services/sharing/nearby/quick_start_decoder/BUILD.gn
@@ -8,6 +8,8 @@ source_set("quick_start_decoder") { sources = [ + "quick_start_conversions.cc", + "quick_start_conversions.h", "quick_start_decoder.cc", "quick_start_decoder.h", ]
diff --git a/chrome/services/sharing/nearby/quick_start_decoder/quick_start_conversions.cc b/chrome/services/sharing/nearby/quick_start_decoder/quick_start_conversions.cc new file mode 100644 index 0000000..91eb4bfb --- /dev/null +++ b/chrome/services/sharing/nearby/quick_start_decoder/quick_start_conversions.cc
@@ -0,0 +1,55 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "quick_start_conversions.h" + +#include "chromeos/ash/services/nearby/public/mojom/quick_start_decoder_types.mojom-shared.h" + +namespace ash::quick_start { + +namespace { +// The following are string representations of expected Wifi security types +constexpr char kPSK[] = "PSK"; +constexpr char kWEP[] = "WEP"; +constexpr char kEAP[] = "EAP"; +constexpr char kOpen[] = "Open"; +constexpr char kOWE[] = "OWE"; +constexpr char kSAE[] = "SAE"; +constexpr char kUnsupported[] = "Unsupported"; +} // namespace + +absl::optional<mojom::WifiSecurityType> WifiSecurityTypeFromString( + base::StringPiece security_type_string) { + if (security_type_string == kPSK) { + return mojom::WifiSecurityType::kPSK; + } + + if (security_type_string == kWEP) { + return mojom::WifiSecurityType::kWEP; + } + + if (security_type_string == kEAP) { + return mojom::WifiSecurityType::kEAP; + } + + if (security_type_string == kOpen) { + return mojom::WifiSecurityType::kOpen; + } + + if (security_type_string == kOWE) { + return mojom::WifiSecurityType::kOWE; + } + + if (security_type_string == kSAE) { + return mojom::WifiSecurityType::kSAE; + } + + if (security_type_string == kUnsupported) { + LOG(ERROR) << "Unsupported security type!"; + } + + return absl::nullopt; +} + +} // namespace ash::quick_start
diff --git a/chrome/services/sharing/nearby/quick_start_decoder/quick_start_conversions.h b/chrome/services/sharing/nearby/quick_start_decoder/quick_start_conversions.h new file mode 100644 index 0000000..e8a9bc3 --- /dev/null +++ b/chrome/services/sharing/nearby/quick_start_decoder/quick_start_conversions.h
@@ -0,0 +1,19 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_SERVICES_SHARING_NEARBY_QUICK_START_DECODER_QUICK_START_CONVERSIONS_H_ +#define CHROME_SERVICES_SHARING_NEARBY_QUICK_START_DECODER_QUICK_START_CONVERSIONS_H_ + +#include "chromeos/ash/services/nearby/public/mojom/quick_start_decoder_types.mojom-shared.h" + +namespace ash::quick_start { + +// Converts a string into a WifiSecurityType enum, or returns nullopt if +// it's not a valid security type. +absl::optional<mojom::WifiSecurityType> WifiSecurityTypeFromString( + base::StringPiece security_type_string); + +} // namespace ash::quick_start + +#endif // CHROME_SERVICES_SHARING_NEARBY_QUICK_START_DECODER_QUICK_START_CONVERSIONS_H_
diff --git a/chrome/services/sharing/nearby/quick_start_decoder/quick_start_decoder.cc b/chrome/services/sharing/nearby/quick_start_decoder/quick_start_decoder.cc index 8be63f5..bad6ec8 100644 --- a/chrome/services/sharing/nearby/quick_start_decoder/quick_start_decoder.cc +++ b/chrome/services/sharing/nearby/quick_start_decoder/quick_start_decoder.cc
@@ -13,9 +13,12 @@ #include "base/values.h" #include "chromeos/ash/components/quick_start/quick_start_message.h" #include "chromeos/ash/components/quick_start/quick_start_message_type.h" +#include "chromeos/ash/services/nearby/public/mojom/quick_start_decoder_types.mojom-forward.h" +#include "chromeos/ash/services/nearby/public/mojom/quick_start_decoder_types.mojom-shared.h" #include "chromeos/ash/services/nearby/public/mojom/quick_start_decoder_types.mojom.h" #include "components/cbor/reader.h" #include "components/cbor/values.h" +#include "quick_start_conversions.h" #include "sandbox/policy/sandbox.h" namespace ash::quick_start { @@ -25,6 +28,9 @@ using CBOR = cbor::Value; using GetAssertionStatus = mojom::GetAssertionResponse::GetAssertionStatus; +using GetWifiCredentialsFailureReason = mojom::GetWifiCredentialsFailureReason; +using GetWifiCredentialsResponse = mojom::GetWifiCredentialsResponse; + constexpr char kCredentialIdKey[] = "id"; constexpr char kEntitiyIdMapKey[] = "id"; constexpr char kDeviceDetailsKey[] = "deviceDetails"; @@ -35,6 +41,23 @@ constexpr uint8_t kCtap2ErrInvalidCBOR = 0x12; constexpr char kFidoMessageKey[] = "fidoMessage"; +// Key in Wifi Information response containing information about the wifi +// network as a JSON Dictionary. +constexpr char kWifiNetworkInformationKey[] = "wifi_network"; + +// Key in wifi_network dictionary containing the SSID of the wifi network. +constexpr char kWifiNetworkSsidKey[] = "wifi_ssid"; + +// Key in wifi_network dictionary containing the password of the wifi network. +constexpr char kWifiNetworkPasswordKey[] = "pre_shared_key"; + +// Key in wifi_network dictionary containing the security type of the wifi +// network. +constexpr char kWifiNetworkSecurityTypeKey[] = "wifi_security_type"; + +// Key in wifi_network dictionary containing if the wifi network is hidden. +constexpr char kWifiNetworkIsHiddenKey[] = "wifi_hidden_ssid"; + std::pair<int, absl::optional<cbor::Value>> CborDecodeGetAssertionResponse( base::span<const uint8_t> response) { cbor::Reader::DecoderError error; @@ -200,6 +223,88 @@ std::move(callback).Run(DoDecodeBootstrapConfigurations(data)); } +void QuickStartDecoder::DecodeWifiCredentialsResponse( + const std::vector<uint8_t>& data, + DecodeWifiCredentialsResponseCallback callback) { + DCHECK(sandbox::policy::Sandbox::IsProcessSandboxed()); + std::move(callback).Run(DoDecodeWifiCredentialsResponse(data)); +} + +mojom::GetWifiCredentialsResponsePtr +QuickStartDecoder::DoDecodeWifiCredentialsResponse( + const std::vector<uint8_t>& data) { + std::unique_ptr<ash::quick_start::QuickStartMessage> message = + QuickStartMessage::ReadMessage(data, + QuickStartMessageType::kQuickStartPayload); + + if (!message) { + LOG(ERROR) << "Message cannot be parsed as a JSON Dictionary."; + return GetWifiCredentialsResponse::NewFailureReason( + GetWifiCredentialsFailureReason::kFailedToDecodeMessage); + } + + base::Value::Dict* wifi_network_information = + message->GetPayload()->FindDict(kWifiNetworkInformationKey); + if (!wifi_network_information) { + LOG(ERROR) << "Wifi Network information not present in payload"; + return GetWifiCredentialsResponse::NewFailureReason( + GetWifiCredentialsFailureReason::kMissingWifiInformation); + } + + std::string* ssid = wifi_network_information->FindString(kWifiNetworkSsidKey); + if (!ssid) { + LOG(ERROR) << "SSID cannot be found within WifiCredentialsResponse."; + return GetWifiCredentialsResponse::NewFailureReason( + GetWifiCredentialsFailureReason::kMissingWifiSSID); + } + + if (ssid->length() == 0) { + LOG(ERROR) << "SSID has a length of 0."; + return GetWifiCredentialsResponse::NewFailureReason( + GetWifiCredentialsFailureReason::kEmptyWifiSSID); + } + + std::string* password = + wifi_network_information->FindString(kWifiNetworkPasswordKey); + if (!password) { + LOG(ERROR) << "Password cannot be found within WifiCredentialsResponse"; + return GetWifiCredentialsResponse::NewFailureReason( + GetWifiCredentialsFailureReason::kMissingWifiPassword); + } + + std::string* security_type_string = + wifi_network_information->FindString(kWifiNetworkSecurityTypeKey); + if (!security_type_string) { + LOG(ERROR) + << "Security Type cannot be found within WifiCredentialsResponse"; + return GetWifiCredentialsResponse::NewFailureReason( + GetWifiCredentialsFailureReason::kMissingWifiSecurityType); + } + + absl::optional<mojom::WifiSecurityType> security_type = + WifiSecurityTypeFromString(*security_type_string); + + if (!security_type.has_value()) { + { + LOG(ERROR) << "Security type was not a valid value."; + return GetWifiCredentialsResponse::NewFailureReason( + GetWifiCredentialsFailureReason::kInvalidWifiSecurityType); + } + } + + absl::optional<bool> is_hidden = + wifi_network_information->FindBool(kWifiNetworkIsHiddenKey); + if (!is_hidden.has_value()) { + LOG(ERROR) + << "Wifi Hide Status cannot be found within WifiCredentialsResponse"; + return GetWifiCredentialsResponse::NewFailureReason( + GetWifiCredentialsFailureReason::kMissingWifiHiddenStatus); + } + + return GetWifiCredentialsResponse::NewCredentials(mojom::WifiCredentials::New( + *ssid, security_type.value(), is_hidden.value(), *password)); +} + void QuickStartDecoder::DecodeGetAssertionResponse( const std::vector<uint8_t>& data, DecodeGetAssertionResponseCallback callback) {
diff --git a/chrome/services/sharing/nearby/quick_start_decoder/quick_start_decoder.h b/chrome/services/sharing/nearby/quick_start_decoder/quick_start_decoder.h index 9d049f9..3cfb159 100644 --- a/chrome/services/sharing/nearby/quick_start_decoder/quick_start_decoder.h +++ b/chrome/services/sharing/nearby/quick_start_decoder/quick_start_decoder.h
@@ -8,6 +8,7 @@ #include <vector> #include "chromeos/ash/services/nearby/public/mojom/quick_start_decoder.mojom.h" +#include "chromeos/ash/services/nearby/public/mojom/quick_start_decoder_types.mojom-forward.h" #include "chromeos/ash/services/nearby/public/mojom/quick_start_decoder_types.mojom.h" #include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/cpp/bindings/pending_remote.h" @@ -32,17 +33,23 @@ const std::vector<uint8_t>& data, DecodeBootstrapConfigurationsCallback callback) override; - // mojom::QuickStartDecoder; void DecodeGetAssertionResponse( const std::vector<uint8_t>& data, DecodeGetAssertionResponseCallback callback) override; + void DecodeWifiCredentialsResponse( + const std::vector<uint8_t>& data, + DecodeWifiCredentialsResponseCallback callback) override; + // mojom::QuickStartDecoder: + private: friend class QuickStartDecoderTest; mojom::BootstrapConfigurationsPtr DoDecodeBootstrapConfigurations( const std::vector<uint8_t>& data); mojom::GetAssertionResponsePtr DoDecodeGetAssertionResponse( const std::vector<uint8_t>& data); + mojom::GetWifiCredentialsResponsePtr DoDecodeWifiCredentialsResponse( + const std::vector<uint8_t>& data); absl::optional<std::vector<uint8_t>> ExtractFidoDataFromJsonResponse( const std::vector<uint8_t>& data); mojo::Receiver<mojom::QuickStartDecoder> receiver_;
diff --git a/chrome/services/sharing/nearby/quick_start_decoder/quick_start_decoder_unittest.cc b/chrome/services/sharing/nearby/quick_start_decoder/quick_start_decoder_unittest.cc index ad772af..5142781 100644 --- a/chrome/services/sharing/nearby/quick_start_decoder/quick_start_decoder_unittest.cc +++ b/chrome/services/sharing/nearby/quick_start_decoder/quick_start_decoder_unittest.cc
@@ -10,6 +10,8 @@ #include "base/test/task_environment.h" #include "base/values.h" #include "chromeos/ash/components/quick_start/quick_start_message.h" +#include "chromeos/ash/services/nearby/public/mojom/quick_start_decoder_types.mojom-forward.h" +#include "chromeos/ash/services/nearby/public/mojom/quick_start_decoder_types.mojom-shared.h" #include "components/cbor/values.h" #include "components/cbor/writer.h" #include "mojo/public/cpp/bindings/remote.h" @@ -33,6 +35,23 @@ constexpr int kCborDecoderNoError = 0; constexpr int kCborDecoderUnknownError = 14; +// Key in Wifi Information response containing information about the wifi +// network as a JSON Dictionary. +constexpr char kWifiNetworkInformationKey[] = "wifi_network"; + +// Key in wifi_network dictionary containing the SSID of the wifi network. +constexpr char kWifiNetworkSsidKey[] = "wifi_ssid"; + +// Key in wifi_network dictionary containing the password of the wifi network. +constexpr char kWifiNetworkPasswordKey[] = "pre_shared_key"; + +// Key in wifi_network dictionary containing the security type of the wifi +// network. +constexpr char kWifiNetworkSecurityTypeKey[] = "wifi_security_type"; + +// Key in wifi_network dictionary containing if the wifi network is hidden. +constexpr char kWifiNetworkIsHiddenKey[] = "wifi_hidden_ssid"; + const std::vector<uint8_t> kValidCredentialId = {0x01, 0x02, 0x03}; const std::vector<uint8_t> kValidAuthData = {0x02, 0x03, 0x04}; const std::vector<uint8_t> kValidSignature = {0x03, 0x04, 0x05}; @@ -84,6 +103,12 @@ return decoder_->DoDecodeBootstrapConfigurations(data); } + mojom::GetWifiCredentialsResponsePtr DoDecodeWifiCredentialsResponse( + QuickStartMessage* message) { + return decoder_->DoDecodeWifiCredentialsResponse( + ConvertMessageToBytes(message)); + } + absl::optional<std::vector<uint8_t>> ExtractFidoDataFromJsonResponse( const std::vector<uint8_t>& data) { return decoder_->ExtractFidoDataFromJsonResponse(data); @@ -369,4 +394,152 @@ EXPECT_FALSE(result.has_value()); } +TEST_F(QuickStartDecoderTest, ExtractWifiInformationPassesOnValidResponse) { + base::Value::Dict wifi_information; + wifi_information.Set(kWifiNetworkSsidKey, "ssid"); + wifi_information.Set(kWifiNetworkPasswordKey, "password"); + wifi_information.Set(kWifiNetworkSecurityTypeKey, "PSK"); + wifi_information.Set(kWifiNetworkIsHiddenKey, true); + + QuickStartMessage message(QuickStartMessageType::kQuickStartPayload); + message.GetPayload()->Set(kWifiNetworkInformationKey, + std::move(wifi_information)); + + mojom::GetWifiCredentialsResponsePtr response = + DoDecodeWifiCredentialsResponse(&message); + + EXPECT_TRUE(response->is_credentials()); + + EXPECT_EQ(response->get_credentials()->ssid, "ssid"); + EXPECT_EQ(response->get_credentials()->password, "password"); + EXPECT_EQ(response->get_credentials()->security_type, + mojom::WifiSecurityType::kPSK); + EXPECT_TRUE(response->get_credentials()->is_hidden); +} + +TEST_F(QuickStartDecoderTest, ExtractWifiInformationFailsIfSSIDLengthIsZero) { + base::Value::Dict wifi_information; + wifi_information.Set(kWifiNetworkSsidKey, ""); + wifi_information.Set(kWifiNetworkPasswordKey, "password"); + wifi_information.Set(kWifiNetworkSecurityTypeKey, "PSK"); + wifi_information.Set(kWifiNetworkIsHiddenKey, true); + + QuickStartMessage message(QuickStartMessageType::kQuickStartPayload); + message.GetPayload()->Set(kWifiNetworkInformationKey, + std::move(wifi_information)); + + mojom::GetWifiCredentialsResponsePtr response = + DoDecodeWifiCredentialsResponse(&message); + + EXPECT_TRUE(response->is_failure_reason()); + EXPECT_EQ(response->get_failure_reason(), + mojom::GetWifiCredentialsFailureReason::kEmptyWifiSSID); +} + +TEST_F(QuickStartDecoderTest, ExtractWifiInformationFailsWhenMissingSSID) { + base::Value::Dict wifi_information; + wifi_information.Set(kWifiNetworkPasswordKey, "password"); + wifi_information.Set(kWifiNetworkSecurityTypeKey, "PSK"); + wifi_information.Set(kWifiNetworkIsHiddenKey, true); + + QuickStartMessage message(QuickStartMessageType::kQuickStartPayload); + message.GetPayload()->Set(kWifiNetworkInformationKey, + std::move(wifi_information)); + + mojom::GetWifiCredentialsResponsePtr response = + DoDecodeWifiCredentialsResponse(&message); + + EXPECT_TRUE(response->is_failure_reason()); + EXPECT_EQ(response->get_failure_reason(), + mojom::GetWifiCredentialsFailureReason::kMissingWifiSSID); +} + +TEST_F(QuickStartDecoderTest, ExtractWifiInformationFailsWhenMissingPassword) { + base::Value::Dict wifi_information; + wifi_information.Set(kWifiNetworkSsidKey, "ssid"); + wifi_information.Set(kWifiNetworkSecurityTypeKey, "PSK"); + wifi_information.Set(kWifiNetworkIsHiddenKey, true); + + QuickStartMessage message(QuickStartMessageType::kQuickStartPayload); + message.GetPayload()->Set(kWifiNetworkInformationKey, + std::move(wifi_information)); + + mojom::GetWifiCredentialsResponsePtr response = + DoDecodeWifiCredentialsResponse(&message); + + EXPECT_TRUE(response->is_failure_reason()); + EXPECT_EQ(response->get_failure_reason(), + mojom::GetWifiCredentialsFailureReason::kMissingWifiPassword); +} + +TEST_F(QuickStartDecoderTest, + ExtractWifiInformationFailsWhenMissingSecurityType) { + base::Value::Dict wifi_information; + wifi_information.Set(kWifiNetworkSsidKey, "ssid"); + wifi_information.Set(kWifiNetworkPasswordKey, "password"); + wifi_information.Set(kWifiNetworkIsHiddenKey, true); + + QuickStartMessage message(QuickStartMessageType::kQuickStartPayload); + message.GetPayload()->Set(kWifiNetworkInformationKey, + std::move(wifi_information)); + + mojom::GetWifiCredentialsResponsePtr response = + DoDecodeWifiCredentialsResponse(&message); + + EXPECT_TRUE(response->is_failure_reason()); + EXPECT_EQ(response->get_failure_reason(), + mojom::GetWifiCredentialsFailureReason::kMissingWifiSecurityType); +} + +TEST_F(QuickStartDecoderTest, + ExtractWifiInformationFailsOnInvalidSecurityType) { + base::Value::Dict wifi_information; + wifi_information.Set(kWifiNetworkSsidKey, "ssid"); + wifi_information.Set(kWifiNetworkPasswordKey, "password"); + wifi_information.Set(kWifiNetworkSecurityTypeKey, "invalid"); + wifi_information.Set(kWifiNetworkIsHiddenKey, true); + + QuickStartMessage message(QuickStartMessageType::kQuickStartPayload); + message.GetPayload()->Set(kWifiNetworkInformationKey, + std::move(wifi_information)); + + mojom::GetWifiCredentialsResponsePtr response = + DoDecodeWifiCredentialsResponse(&message); + + EXPECT_TRUE(response->is_failure_reason()); + EXPECT_EQ(response->get_failure_reason(), + mojom::GetWifiCredentialsFailureReason::kInvalidWifiSecurityType); +} + +TEST_F(QuickStartDecoderTest, + ExtractWifiInformationFailsWhenMissingHiddenStatus) { + base::Value::Dict wifi_information; + wifi_information.Set(kWifiNetworkSsidKey, "ssid"); + wifi_information.Set(kWifiNetworkPasswordKey, "password"); + wifi_information.Set(kWifiNetworkSecurityTypeKey, "PSK"); + + QuickStartMessage message(QuickStartMessageType::kQuickStartPayload); + message.GetPayload()->Set(kWifiNetworkInformationKey, + std::move(wifi_information)); + + mojom::GetWifiCredentialsResponsePtr response = + DoDecodeWifiCredentialsResponse(&message); + + EXPECT_TRUE(response->is_failure_reason()); + EXPECT_EQ(response->get_failure_reason(), + mojom::GetWifiCredentialsFailureReason::kMissingWifiHiddenStatus); +} + +TEST_F(QuickStartDecoderTest, + ExtractWifiInformationFailsWhenMissingWifiInformation) { + QuickStartMessage message(QuickStartMessageType::kQuickStartPayload); + + mojom::GetWifiCredentialsResponsePtr response = + DoDecodeWifiCredentialsResponse(&message); + + EXPECT_TRUE(response->is_failure_reason()); + EXPECT_EQ(response->get_failure_reason(), + mojom::GetWifiCredentialsFailureReason::kMissingWifiInformation); +} + } // namespace ash::quick_start
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 674046ab..8f1a89a 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -4074,6 +4074,7 @@ "../browser/ash/policy/networking/policy_certs_browsertest.cc", "../browser/ash/policy/remote_commands/curtain_mode_chromeos_browsertest.cc", "../browser/ash/policy/reporting/metrics_reporting/apps/app_events_observer_browsertest.cc", + "../browser/ash/policy/reporting/metrics_reporting/apps/app_usage_telemetry_sampler_browsertest.cc", "../browser/ash/policy/reporting/metrics_reporting/audio/audio_events_observer_browsertest.cc", "../browser/ash/policy/reporting/metrics_reporting/cros_healthd_info_metric_sampler_browsertest.cc", "../browser/ash/policy/reporting/metrics_reporting/metric_browsertest_utils.cc",
diff --git a/chrome/test/data/fullscreen_keyboardlock/fullscreen_keyboardlock.html b/chrome/test/data/fullscreen_keyboardlock/fullscreen_keyboardlock.html index 8869800a..16edfd5 100644 --- a/chrome/test/data/fullscreen_keyboardlock/fullscreen_keyboardlock.html +++ b/chrome/test/data/fullscreen_keyboardlock/fullscreen_keyboardlock.html
@@ -9,19 +9,22 @@ <head> <title>Fullscreen Keyboard Lock Test</title> <script> - let x_pressed = false; - let report_called = false; + let x_pressed_resolve; + let x_pressed; let prevent_default = true; function processResult() { - if (x_pressed && report_called) { - window.domAutomationController.send(container().innerHTML); + if (x_pressed && x_pressed_resolve) { + x_pressed_resolve(container().innerHTML); } } - function getKeyEventReport() { - report_called = true; - processResult(); + async function getKeyEventReport() { + await new Promise(resolve => { + x_pressed_resolve = resolve; + processResult(); + }); + return container().innerHTML; } function isMacOSFullscreenShortcut(e) {
diff --git a/chrome/test/data/geolocation/basic_geolocation.js b/chrome/test/data/geolocation/basic_geolocation.js index b2990c6..e25ffca 100644 --- a/chrome/test/data/geolocation/basic_geolocation.js +++ b/chrome/test/data/geolocation/basic_geolocation.js
@@ -8,9 +8,9 @@ var position_initialized = false; var position_updated = false; -function sendString(string) { - window.domAutomationController.send(string); -} +const callbackStatuses = new ResultQueue(); +const geopositionUpdates = new ResultQueue(); + function geoSuccessCallback(position) { last_position = position; } @@ -20,20 +20,20 @@ function geoSuccessCallbackWithResponse(position) { last_position = position; + callbackStatuses.push('request-callback-success'); if (!position_initialized) { // First time callback invoked. position_initialized = true; - sendString('request-callback-success'); return; } if (!position_updated) { // Second time callback invoked. position_updated = true; - sendString('geoposition-updated'); + geopositionUpdates.push('geoposition-updated'); } } function geoErrorCallbackWithResponse(error) { last_error = error; - sendString('request-callback-error'); + callbackStatuses.push('request-callback-error'); } function geoStart() { watch_id = navigator.geolocation.watchPosition( @@ -43,14 +43,15 @@ } function geoStartWithAsyncResponse() { navigator.geolocation.watchPosition( - geoSuccessCallbackWithResponse, geoErrorCallbackWithResponse, - {maximumAge:600000, timeout:100000, enableHighAccuracy:true}); + geoSuccessCallbackWithResponse, geoErrorCallbackWithResponse, + {maximumAge:600000, timeout:100000, enableHighAccuracy:true}); + return callbackStatuses.pop(); } function geoStartWithSyncResponse() { navigator.geolocation.watchPosition( geoSuccessCallback, geoErrorCallback, {maximumAge:600000, timeout:100000, enableHighAccuracy:true}); - sendString('requested'); + return 'requested'; } function geoGetLastPositionLatitude() { return "" + last_position.coords.latitude;
diff --git a/chrome/test/data/geolocation/simple.html b/chrome/test/data/geolocation/simple.html index c591761..138f972 100644 --- a/chrome/test/data/geolocation/simple.html +++ b/chrome/test/data/geolocation/simple.html
@@ -1,5 +1,6 @@ <html> <head> + <script src="../result_queue.js"></script> <script src="basic_geolocation.js"></script> </head> <body>
diff --git a/chrome/test/data/geolocation/two_iframes.html b/chrome/test/data/geolocation/two_iframes.html index ba629ed..0256c85 100644 --- a/chrome/test/data/geolocation/two_iframes.html +++ b/chrome/test/data/geolocation/two_iframes.html
@@ -1,6 +1,7 @@ <html> <head> <script src="iframe_controller.js"></script> + <script src="../result_queue.js"></script> <script src="basic_geolocation.js"></script> </head> <body>
diff --git a/chrome/test/data/geolocation/two_watches.html b/chrome/test/data/geolocation/two_watches.html index 2c723b9..0bdddcf5 100644 --- a/chrome/test/data/geolocation/two_watches.html +++ b/chrome/test/data/geolocation/two_watches.html
@@ -1,5 +1,6 @@ <html> <head> + <script src="../result_queue.js"></script> <script> var position_1 = 0; var position_2 = 0; @@ -11,9 +12,8 @@ var first_position_received = false; var position_updated = false; - function sendString(string) { - window.domAutomationController.send(string); - } + const resultQueue = new ResultQueue(); + const geopositionUpdates = resultQueue; // The permission request is not considered complete until both of the // watches have been set. @@ -26,10 +26,10 @@ last_error = "TEST FAIL: watches received different locations. " + " Watch 1 (" + watch_1_id + ") got " + position_1 + " Watch 2 (" + watch_2_id + ") got " + position_2; - sendString(last_error); + resultQueue.push(last_error); return; } - sendString('request-callback-success'); + resultQueue.push('request-callback-success'); } // This will be triggered twice: @@ -46,7 +46,7 @@ if (position.coords.latitude == expected_final_position_latitude && position.coords.longitude == expected_final_position_longitude) { position_updated = true; - sendString('geoposition-updated'); + resultQueue.push('geoposition-updated'); } } @@ -67,7 +67,7 @@ function geoErrorCallback(error) { last_error = error; - sendString('request-callback-error'); + resultQueue.push('request-callback-error'); } function geoStartWithAsyncResponse() { watch_1_id = navigator.geolocation.watchPosition( @@ -76,6 +76,8 @@ watch_2_id = navigator.geolocation.watchPosition( geoSuccessCallback2, geoErrorCallback, {maximumAge:600000, timeout:100000, enableHighAccuracy:true}); + + return resultQueue.pop(); } function geoGetLastPositionLatitude() { return "" + position_1.coords.latitude;
diff --git a/chrome/test/data/webui/chromeos/set_time_dialog_test.js b/chrome/test/data/webui/chromeos/set_time_dialog_test.js index 6b6ede7..5aa0eab 100644 --- a/chrome/test/data/webui/chromeos/set_time_dialog_test.js +++ b/chrome/test/data/webui/chromeos/set_time_dialog_test.js
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'chrome://set-time/set_time_dialog.js'; +import 'chrome://set-time/set_time.js'; import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
diff --git a/chrome/test/data/webui/chromeos/shortcut_customization/fake_shortcut_provider_test.ts b/chrome/test/data/webui/chromeos/shortcut_customization/fake_shortcut_provider_test.ts index abd5325..8d8db8b 100644 --- a/chrome/test/data/webui/chromeos/shortcut_customization/fake_shortcut_provider_test.ts +++ b/chrome/test/data/webui/chromeos/shortcut_customization/fake_shortcut_provider_test.ts
@@ -113,9 +113,13 @@ test('ReplaceAcceleratorFake', () => { // TODO(jimmyxgong): Remove this test once real data is ready. - return getProvider().replaceAccelerator().then((result) => { - assertEquals(AcceleratorConfigResult.kSuccess, result); - }); + return getProvider() + .replaceAccelerator( + AcceleratorSource.kAsh, /*action_id=*/ 0, {} as Accelerator, + {} as Accelerator) + .then(({result}) => { + assertEquals(AcceleratorConfigResult.kSuccess, result.result); + }); }); test('RemoveAcceleratorFake', () => {
diff --git a/chrome/test/data/webui/cr_components/BUILD.gn b/chrome/test/data/webui/cr_components/BUILD.gn index b35cef3..4924242 100644 --- a/chrome/test/data/webui/cr_components/BUILD.gn +++ b/chrome/test/data/webui/cr_components/BUILD.gn
@@ -27,8 +27,8 @@ "most_visited_test_support.ts", "managed_footnote_test.ts", "settings_prefs_test_cases.ts", - "settings_prefs_tests.ts", - "settings_pref_util_tests.ts", + "settings_prefs_test.ts", + "settings_pref_util_test.ts", ] if (use_nss_certs) {
diff --git a/chrome/test/data/webui/cr_components/cr_components_browsertest.js b/chrome/test/data/webui/cr_components/cr_components_browsertest.js index f0ffaf73..a302d81 100644 --- a/chrome/test/data/webui/cr_components/cr_components_browsertest.js +++ b/chrome/test/data/webui/cr_components/cr_components_browsertest.js
@@ -167,7 +167,7 @@ var CrComponentsSettingsPrefsTest = class extends CrComponentsBrowserTest { /** @override */ get browsePreload() { - return 'chrome://settings/test_loader.html?module=cr_components/settings_prefs_tests.js'; // presubmit: ignore-long-line + return 'chrome://settings/test_loader.html?module=cr_components/settings_prefs_test.js'; // presubmit: ignore-long-line } }; @@ -178,7 +178,7 @@ var CrComponentsSettingsPrefUtilsTest = class extends CrComponentsBrowserTest { /** @override */ get browsePreload() { - return 'chrome://settings/test_loader.html?module=cr_components/settings_pref_util_tests.js'; // presubmit: ignore-long-line + return 'chrome://settings/test_loader.html?module=cr_components/settings_pref_util_test.js'; // presubmit: ignore-long-line } };
diff --git a/chrome/test/data/webui/cr_components/settings_pref_util_tests.ts b/chrome/test/data/webui/cr_components/settings_pref_util_test.ts similarity index 100% rename from chrome/test/data/webui/cr_components/settings_pref_util_tests.ts rename to chrome/test/data/webui/cr_components/settings_pref_util_test.ts
diff --git a/chrome/test/data/webui/cr_components/settings_prefs_tests.ts b/chrome/test/data/webui/cr_components/settings_prefs_test.ts similarity index 100% rename from chrome/test/data/webui/cr_components/settings_prefs_tests.ts rename to chrome/test/data/webui/cr_components/settings_prefs_test.ts
diff --git a/chrome/test/data/webui/cr_elements/BUILD.gn b/chrome/test/data/webui/cr_elements/BUILD.gn index 9be087b7..ca21d12 100644 --- a/chrome/test/data/webui/cr_elements/BUILD.gn +++ b/chrome/test/data/webui/cr_elements/BUILD.gn
@@ -14,31 +14,31 @@ "cr_a11y_announcer_test.ts", "cr_action_menu_test.ts", "cr_auto_img_test.ts", - "cr_button_tests.ts", + "cr_button_test.ts", "cr_card_radio_button_test.ts", "cr_checkbox_test.ts", "cr_container_shadow_mixin_test.ts", "cr_dialog_test.ts", - "cr_drawer_tests.ts", - "cr_expand_button_tests.ts", - "cr_fingerprint_progress_arc_tests.ts", + "cr_drawer_test.ts", + "cr_expand_button_test.ts", + "cr_fingerprint_progress_arc_test.ts", "cr_focus_row_mixin_test.ts", "cr_grid_focus_test.ts", - "cr_icon_button_tests.ts", + "cr_icon_button_test.ts", "cr_input_test.ts", - "cr_lazy_render_tests.ts", - "cr_link_row_tests.ts", - "cr_lottie_tests.ts", + "cr_lazy_render_test.ts", + "cr_link_row_test.ts", + "cr_lottie_test.ts", "cr_menu_selector_focus_test.ts", - "cr_policy_indicator_mixin_tests.ts", - "cr_policy_indicator_tests.ts", - "cr_policy_pref_indicator_tests.ts", + "cr_policy_indicator_mixin_test.ts", + "cr_policy_indicator_test.ts", + "cr_policy_pref_indicator_test.ts", "cr_policy_strings.ts", - "cr_profile_avatar_selector_tests.ts", + "cr_profile_avatar_selector_test.ts", "cr_radio_button_test.ts", "cr_radio_group_test.ts", - "cr_scrollable_mixin_tests.ts", - "cr_search_field_tests.ts", + "cr_scrollable_mixin_test.ts", + "cr_search_field_test.ts", "cr_slider_test.ts", "cr_splitter_test.ts", "cr_tabs_test.ts", @@ -46,8 +46,8 @@ "cr_toast_manager_test.ts", "cr_toast_test.ts", "cr_toggle_test.ts", - "cr_toolbar_focus_tests.ts", - "cr_toolbar_search_field_tests.ts", + "cr_toolbar_focus_test.ts", + "cr_toolbar_search_field_test.ts", "cr_toolbar_test.ts", "cr_tree_test.ts", "cr_url_list_item_test.ts", @@ -55,12 +55,12 @@ "find_shortcut_mixin_test.ts", "i18n_mixin_test.ts", "iron_list_focus_test.ts", - "list_property_update_mixin_tests.ts", + "list_property_update_mixin_test.ts", "web_ui_listener_mixin_test.ts", ] if (is_chromeos_ash) { - files += [ "cr_searchable_drop_down_tests.ts" ] + files += [ "cr_searchable_drop_down_test.ts" ] } ts_definitions = [
diff --git a/chrome/test/data/webui/cr_elements/cr_button_tests.ts b/chrome/test/data/webui/cr_elements/cr_button_test.ts similarity index 100% rename from chrome/test/data/webui/cr_elements/cr_button_tests.ts rename to chrome/test/data/webui/cr_elements/cr_button_test.ts
diff --git a/chrome/test/data/webui/cr_elements/cr_drawer_tests.ts b/chrome/test/data/webui/cr_elements/cr_drawer_test.ts similarity index 100% rename from chrome/test/data/webui/cr_elements/cr_drawer_tests.ts rename to chrome/test/data/webui/cr_elements/cr_drawer_test.ts
diff --git a/chrome/test/data/webui/cr_elements/cr_elements_browsertest.js b/chrome/test/data/webui/cr_elements/cr_elements_browsertest.js index 35ca0a5..e5f0ade 100644 --- a/chrome/test/data/webui/cr_elements/cr_elements_browsertest.js +++ b/chrome/test/data/webui/cr_elements/cr_elements_browsertest.js
@@ -39,7 +39,7 @@ var CrElementsButtonTest = class extends CrElementsBrowserTest { /** @override */ get browsePreload() { - return 'chrome://webui-test/test_loader.html?module=cr_elements/cr_button_tests.js'; + return 'chrome://webui-test/test_loader.html?module=cr_elements/cr_button_test.js'; } }; @@ -72,7 +72,7 @@ var CrElementsDrawerTest = class extends CrElementsBrowserTest { /** @override */ get browsePreload() { - return 'chrome://webui-test/test_loader.html?module=cr_elements/cr_drawer_tests.js'; + return 'chrome://webui-test/test_loader.html?module=cr_elements/cr_drawer_test.js'; } }; @@ -90,7 +90,7 @@ var CrElementsExpandButtonTest = class extends CrElementsBrowserTest { /** @override */ get browsePreload() { - return 'chrome://webui-test/test_loader.html?module=cr_elements/cr_expand_button_tests.js'; + return 'chrome://webui-test/test_loader.html?module=cr_elements/cr_expand_button_test.js'; } }; @@ -112,7 +112,7 @@ var CrElementsFingerprintProgressArcTest = class extends CrElementsBrowserTest { /** @override */ get browsePreload() { - return 'chrome://webui-test/test_loader.html?module=cr_elements/cr_fingerprint_progress_arc_tests.js'; + return 'chrome://webui-test/test_loader.html?module=cr_elements/cr_fingerprint_progress_arc_test.js'; } /** @override */ @@ -146,7 +146,7 @@ var CrElementsIconButtonTest = class extends CrElementsBrowserTest { /** @override */ get browsePreload() { - return 'chrome://webui-test/test_loader.html?module=cr_elements/cr_icon_button_tests.js'; + return 'chrome://webui-test/test_loader.html?module=cr_elements/cr_icon_button_test.js'; } }; @@ -157,7 +157,7 @@ var CrElementsLazyRenderTest = class extends CrElementsBrowserTest { /** @override */ get browsePreload() { - return 'chrome://webui-test/test_loader.html?module=cr_elements/cr_lazy_render_tests.js'; + return 'chrome://webui-test/test_loader.html?module=cr_elements/cr_lazy_render_test.js'; } }; @@ -168,7 +168,7 @@ var CrElementsLinkRowTest = class extends CrElementsBrowserTest { /** @override */ get browsePreload() { - return 'chrome://webui-test/test_loader.html?module=cr_elements/cr_link_row_tests.js'; + return 'chrome://webui-test/test_loader.html?module=cr_elements/cr_link_row_test.js'; } }; @@ -180,7 +180,7 @@ class extends CrElementsBrowserTest { /** @override */ get browsePreload() { - return 'chrome://webui-test/test_loader.html?module=cr_elements/list_property_update_mixin_tests.js'; + return 'chrome://webui-test/test_loader.html?module=cr_elements/list_property_update_mixin_test.js'; } }; @@ -225,7 +225,7 @@ var CrElementsScrollableMixinTest = class extends CrElementsBrowserTest { /** @override */ get browsePreload() { - return 'chrome://webui-test/test_loader.html?module=cr_elements/cr_scrollable_mixin_tests.js'; + return 'chrome://webui-test/test_loader.html?module=cr_elements/cr_scrollable_mixin_test.js'; } }; @@ -236,7 +236,7 @@ var CrElementsSearchFieldTest = class extends CrElementsBrowserTest { /** @override */ get browsePreload() { - return 'chrome://webui-test/test_loader.html?module=cr_elements/cr_search_field_tests.js'; + return 'chrome://webui-test/test_loader.html?module=cr_elements/cr_search_field_test.js'; } }; @@ -248,7 +248,7 @@ var CrElementsSearchableDropDownTest = class extends CrElementsBrowserTest { /** @override */ get browsePreload() { - return 'chrome://webui-test/test_loader.html?module=cr_elements/cr_searchable_drop_down_tests.js'; + return 'chrome://webui-test/test_loader.html?module=cr_elements/cr_searchable_drop_down_test.js'; } }; @@ -315,7 +315,7 @@ var CrElementsPolicyIndicatorTest = class extends CrElementsBrowserTest { /** @override */ get browsePreload() { - return 'chrome://webui-test/test_loader.html?module=cr_elements/cr_policy_indicator_tests.js'; + return 'chrome://webui-test/test_loader.html?module=cr_elements/cr_policy_indicator_test.js'; } }; @@ -327,7 +327,7 @@ /** @override */ get browsePreload() { // Preload a settings URL, so that the test can access settingsPrivate. - return 'chrome://settings/test_loader.html?module=cr_elements/cr_policy_pref_indicator_tests.js'; + return 'chrome://settings/test_loader.html?module=cr_elements/cr_policy_pref_indicator_test.js'; } }; @@ -338,7 +338,7 @@ var CrElementsPolicyIndicatorMixinTest = class extends CrElementsBrowserTest { /** @override */ get browsePreload() { - return 'chrome://webui-test/test_loader.html?module=cr_elements/cr_policy_indicator_mixin_tests.js'; + return 'chrome://webui-test/test_loader.html?module=cr_elements/cr_policy_indicator_mixin_test.js'; } }; @@ -349,7 +349,7 @@ var CrElementsLottieTest = class extends CrElementsBrowserTest { /** @override */ get browsePreload() { - return 'chrome://webui-test/test_loader.html?module=cr_elements/cr_lottie_tests.js'; + return 'chrome://webui-test/test_loader.html?module=cr_elements/cr_lottie_test.js'; } /** @override */
diff --git a/chrome/test/data/webui/cr_elements/cr_elements_focus_test.js b/chrome/test/data/webui/cr_elements/cr_elements_focus_test.js index 0aaa19e..a9dd0c8 100644 --- a/chrome/test/data/webui/cr_elements/cr_elements_focus_test.js +++ b/chrome/test/data/webui/cr_elements/cr_elements_focus_test.js
@@ -64,7 +64,7 @@ var CrElementsProfileAvatarSelectorTest = class extends CrElementsFocusTest { /** @override */ get browsePreload() { - return 'chrome://webui-test/test_loader.html?module=cr_elements/cr_profile_avatar_selector_tests.js'; + return 'chrome://webui-test/test_loader.html?module=cr_elements/cr_profile_avatar_selector_test.js'; } }; @@ -97,7 +97,7 @@ var CrElementsToolbarSearchFieldTest = class extends CrElementsFocusTest { /** @override */ get browsePreload() { - return 'chrome://webui-test/test_loader.html?module=cr_elements/cr_toolbar_search_field_tests.js'; + return 'chrome://webui-test/test_loader.html?module=cr_elements/cr_toolbar_search_field_test.js'; } }; @@ -145,7 +145,7 @@ var CrElementsToolbarFocusTest = class extends CrElementsFocusTest { /** @override */ get browsePreload() { - return 'chrome://webui-test/test_loader.html?module=cr_elements/cr_toolbar_focus_tests.js'; + return 'chrome://webui-test/test_loader.html?module=cr_elements/cr_toolbar_focus_test.js'; } };
diff --git a/chrome/test/data/webui/cr_elements/cr_expand_button_tests.ts b/chrome/test/data/webui/cr_elements/cr_expand_button_test.ts similarity index 100% rename from chrome/test/data/webui/cr_elements/cr_expand_button_tests.ts rename to chrome/test/data/webui/cr_elements/cr_expand_button_test.ts
diff --git a/chrome/test/data/webui/cr_elements/cr_fingerprint_progress_arc_tests.ts b/chrome/test/data/webui/cr_elements/cr_fingerprint_progress_arc_test.ts similarity index 100% rename from chrome/test/data/webui/cr_elements/cr_fingerprint_progress_arc_tests.ts rename to chrome/test/data/webui/cr_elements/cr_fingerprint_progress_arc_test.ts
diff --git a/chrome/test/data/webui/cr_elements/cr_icon_button_tests.ts b/chrome/test/data/webui/cr_elements/cr_icon_button_test.ts similarity index 100% rename from chrome/test/data/webui/cr_elements/cr_icon_button_tests.ts rename to chrome/test/data/webui/cr_elements/cr_icon_button_test.ts
diff --git a/chrome/test/data/webui/cr_elements/cr_lazy_render_tests.ts b/chrome/test/data/webui/cr_elements/cr_lazy_render_test.ts similarity index 100% rename from chrome/test/data/webui/cr_elements/cr_lazy_render_tests.ts rename to chrome/test/data/webui/cr_elements/cr_lazy_render_test.ts
diff --git a/chrome/test/data/webui/cr_elements/cr_link_row_tests.ts b/chrome/test/data/webui/cr_elements/cr_link_row_test.ts similarity index 100% rename from chrome/test/data/webui/cr_elements/cr_link_row_tests.ts rename to chrome/test/data/webui/cr_elements/cr_link_row_test.ts
diff --git a/chrome/test/data/webui/cr_elements/cr_lottie_tests.ts b/chrome/test/data/webui/cr_elements/cr_lottie_test.ts similarity index 100% rename from chrome/test/data/webui/cr_elements/cr_lottie_tests.ts rename to chrome/test/data/webui/cr_elements/cr_lottie_test.ts
diff --git a/chrome/test/data/webui/cr_elements/cr_policy_indicator_mixin_tests.ts b/chrome/test/data/webui/cr_elements/cr_policy_indicator_mixin_test.ts similarity index 100% rename from chrome/test/data/webui/cr_elements/cr_policy_indicator_mixin_tests.ts rename to chrome/test/data/webui/cr_elements/cr_policy_indicator_mixin_test.ts
diff --git a/chrome/test/data/webui/cr_elements/cr_policy_indicator_tests.ts b/chrome/test/data/webui/cr_elements/cr_policy_indicator_test.ts similarity index 100% rename from chrome/test/data/webui/cr_elements/cr_policy_indicator_tests.ts rename to chrome/test/data/webui/cr_elements/cr_policy_indicator_test.ts
diff --git a/chrome/test/data/webui/cr_elements/cr_policy_pref_indicator_tests.ts b/chrome/test/data/webui/cr_elements/cr_policy_pref_indicator_test.ts similarity index 100% rename from chrome/test/data/webui/cr_elements/cr_policy_pref_indicator_tests.ts rename to chrome/test/data/webui/cr_elements/cr_policy_pref_indicator_test.ts
diff --git a/chrome/test/data/webui/cr_elements/cr_profile_avatar_selector_tests.ts b/chrome/test/data/webui/cr_elements/cr_profile_avatar_selector_test.ts similarity index 100% rename from chrome/test/data/webui/cr_elements/cr_profile_avatar_selector_tests.ts rename to chrome/test/data/webui/cr_elements/cr_profile_avatar_selector_test.ts
diff --git a/chrome/test/data/webui/cr_elements/cr_scrollable_mixin_tests.ts b/chrome/test/data/webui/cr_elements/cr_scrollable_mixin_test.ts similarity index 100% rename from chrome/test/data/webui/cr_elements/cr_scrollable_mixin_tests.ts rename to chrome/test/data/webui/cr_elements/cr_scrollable_mixin_test.ts
diff --git a/chrome/test/data/webui/cr_elements/cr_search_field_tests.ts b/chrome/test/data/webui/cr_elements/cr_search_field_test.ts similarity index 100% rename from chrome/test/data/webui/cr_elements/cr_search_field_tests.ts rename to chrome/test/data/webui/cr_elements/cr_search_field_test.ts
diff --git a/chrome/test/data/webui/cr_elements/cr_searchable_drop_down_tests.ts b/chrome/test/data/webui/cr_elements/cr_searchable_drop_down_test.ts similarity index 100% rename from chrome/test/data/webui/cr_elements/cr_searchable_drop_down_tests.ts rename to chrome/test/data/webui/cr_elements/cr_searchable_drop_down_test.ts
diff --git a/chrome/test/data/webui/cr_elements/cr_toolbar_focus_tests.ts b/chrome/test/data/webui/cr_elements/cr_toolbar_focus_test.ts similarity index 100% rename from chrome/test/data/webui/cr_elements/cr_toolbar_focus_tests.ts rename to chrome/test/data/webui/cr_elements/cr_toolbar_focus_test.ts
diff --git a/chrome/test/data/webui/cr_elements/cr_toolbar_search_field_tests.ts b/chrome/test/data/webui/cr_elements/cr_toolbar_search_field_test.ts similarity index 100% rename from chrome/test/data/webui/cr_elements/cr_toolbar_search_field_tests.ts rename to chrome/test/data/webui/cr_elements/cr_toolbar_search_field_test.ts
diff --git a/chrome/test/data/webui/cr_elements/list_property_update_mixin_tests.ts b/chrome/test/data/webui/cr_elements/list_property_update_mixin_test.ts similarity index 100% rename from chrome/test/data/webui/cr_elements/list_property_update_mixin_tests.ts rename to chrome/test/data/webui/cr_elements/list_property_update_mixin_test.ts
diff --git a/chrome/test/data/webui/downloads/BUILD.gn b/chrome/test/data/webui/downloads/BUILD.gn index de58eddd..11c2c41 100644 --- a/chrome/test/data/webui/downloads/BUILD.gn +++ b/chrome/test/data/webui/downloads/BUILD.gn
@@ -8,11 +8,11 @@ resource_path_prefix = "downloads" files = [ - "item_tests.ts", - "manager_tests.ts", + "item_test.ts", + "manager_test.ts", "search_service_test.ts", "test_support.ts", - "toolbar_tests.ts", + "toolbar_test.ts", ] ts_path_mappings = [ "chrome://downloads/downloads.js|" + rebase_path(
diff --git a/chrome/test/data/webui/downloads/downloads_browsertest.js b/chrome/test/data/webui/downloads/downloads_browsertest.js index e100317d..4630d9b3 100644 --- a/chrome/test/data/webui/downloads/downloads_browsertest.js +++ b/chrome/test/data/webui/downloads/downloads_browsertest.js
@@ -19,7 +19,7 @@ var DownloadsItemTest = class extends DownloadsTest { /** @override */ get browsePreload() { - return 'chrome://downloads/test_loader.html?module=downloads/item_tests.js'; + return 'chrome://downloads/test_loader.html?module=downloads/item_test.js'; } }; @@ -30,7 +30,7 @@ var DownloadsManagerTest = class extends DownloadsTest { /** @override */ get browsePreload() { - return 'chrome://downloads/test_loader.html?module=downloads/manager_tests.js'; + return 'chrome://downloads/test_loader.html?module=downloads/manager_test.js'; } }; @@ -41,7 +41,7 @@ var DownloadsToolbarTest = class extends DownloadsTest { /** @override */ get browsePreload() { - return 'chrome://downloads/test_loader.html?module=downloads/toolbar_tests.js'; + return 'chrome://downloads/test_loader.html?module=downloads/toolbar_test.js'; } };
diff --git a/chrome/test/data/webui/downloads/item_tests.ts b/chrome/test/data/webui/downloads/item_test.ts similarity index 100% rename from chrome/test/data/webui/downloads/item_tests.ts rename to chrome/test/data/webui/downloads/item_test.ts
diff --git a/chrome/test/data/webui/downloads/manager_tests.ts b/chrome/test/data/webui/downloads/manager_test.ts similarity index 100% rename from chrome/test/data/webui/downloads/manager_tests.ts rename to chrome/test/data/webui/downloads/manager_test.ts
diff --git a/chrome/test/data/webui/downloads/toolbar_tests.ts b/chrome/test/data/webui/downloads/toolbar_test.ts similarity index 100% rename from chrome/test/data/webui/downloads/toolbar_tests.ts rename to chrome/test/data/webui/downloads/toolbar_test.ts
diff --git a/chrome/test/data/webui/settings/BUILD.gn b/chrome/test/data/webui/settings/BUILD.gn index e29a69f..d5631e6 100644 --- a/chrome/test/data/webui/settings/BUILD.gn +++ b/chrome/test/data/webui/settings/BUILD.gn
@@ -14,9 +14,9 @@ "a11y/manage_profile_a11y_test.ts", "a11y/passwords_a11y_test.ts", "a11y/sign_out_a11y_test.ts", - "about_page_tests.ts", + "about_page_test.ts", "advanced_page_test.ts", - "all_sites_tests.ts", + "all_sites_test.ts", "anti_abuse_page_test.ts", "appearance_fonts_page_test.ts", "appearance_page_test.ts", @@ -27,26 +27,26 @@ "avatar_icon_test.ts", "basic_page_test.ts", "battery_page_test.ts", - "category_default_setting_tests.ts", - "category_setting_exceptions_tests.ts", - "checkbox_tests.ts", - "chooser_exception_list_entry_tests.ts", - "chooser_exception_list_tests.ts", + "category_default_setting_test.ts", + "category_setting_exceptions_test.ts", + "checkbox_test.ts", + "chooser_exception_list_entry_test.ts", + "chooser_exception_list_test.ts", "clear_browsing_data_test.ts", - "collapse_radio_button_tests.ts", - "controlled_button_tests.ts", - "controlled_radio_button_tests.ts", + "collapse_radio_button_test.ts", + "controlled_button_test.ts", + "controlled_radio_button_test.ts", "cookies_page_test.ts", "do_not_track_toggle_test.ts", "downloads_page_test.ts", - "dropdown_menu_tests.ts", - "extension_controlled_indicator_tests.ts", - "file_system_site_entry_tests.ts", - "file_system_site_entry_item_tests.ts", - "file_system_site_list_tests.ts", + "dropdown_menu_test.ts", + "extension_controlled_indicator_test.ts", + "file_system_site_entry_test.ts", + "file_system_site_entry_item_test.ts", + "file_system_site_list_test.ts", "help_page_test.ts", - "idle_load_tests.ts", - "on_startup_page_tests.ts", + "idle_load_test.ts", + "on_startup_page_test.ts", "password_check_test.ts", "password_edit_dialog_test.ts", "passwords_and_autofill_fake_data.ts", @@ -76,13 +76,13 @@ "privacy_page_test.ts", "privacy_sandbox_page_test.ts", "privacy_sandbox_test.ts", - "protocol_handlers_tests.ts", + "protocol_handlers_test.ts", "recent_site_permissions_test.ts", "reset_page_test.ts", "reset_profile_banner_test.ts", "review_notification_permissions_interactive_ui_test.ts", "review_notification_permissions_test.ts", - "route_tests.ts", + "route_test.ts", "safety_check_page_test.ts", "safety_check_permissions_test.ts", "safety_check_test_utils.ts", @@ -99,26 +99,26 @@ "security_keys_phones_subpage_test.ts", "security_page_test.ts", "settings_animated_pages_test.ts", - "settings_category_default_radio_group_tests.ts", + "settings_category_default_radio_group_test.ts", "settings_main_test.ts", "settings_menu_interactive_ui_test.ts", "settings_menu_test.ts", "settings_page_test_util.ts", "settings_performance_menu_test.ts", "settings_section_test.ts", - "settings_slider_tests.ts", + "settings_slider_test.ts", "settings_subpage_test.ts", - "settings_toggle_button_tests.ts", - "settings_ui_tests.ts", + "settings_toggle_button_test.ts", + "settings_ui_test.ts", "simple_confirmation_dialog_test.ts", "site_data_test.ts", - "site_details_permission_tests.ts", - "site_details_permission_device_entry_tests.ts", - "site_details_tests.ts", - "site_entry_tests.ts", + "site_details_permission_test.ts", + "site_details_permission_device_entry_test.ts", + "site_details_test.ts", + "site_entry_test.ts", "site_favicon_test.ts", - "site_list_entry_tests.ts", - "site_list_tests.ts", + "site_list_entry_test.ts", + "site_list_test.ts", "site_settings_page_test.ts", "startup_urls_page_test.ts", "sync_account_control_test.ts", @@ -145,7 +145,7 @@ "test_util.ts", "unused_site_permissions_test.ts", "unused_site_permissions_interactive_ui_test.ts", - "zoom_levels_tests.ts", + "zoom_levels_test.ts", ] if (is_chromeos_ash) { @@ -158,17 +158,17 @@ files += [ "fake_language_settings_private.ts", "languages_page_metrics_test_browser.ts", - "languages_page_tests.ts", - "languages_tests.ts", - "metrics_reporting_tests.ts", + "languages_page_test.ts", + "languages_test.ts", + "metrics_reporting_test.ts", "people_page_manage_profile_test.ts", "relaunch_confirmation_dialog_test.ts", "spell_check_page_metrics_test_browser.ts", - "spell_check_page_tests.ts", + "spell_check_page_test.ts", "test_languages_browser_proxy.ts", "test_languages_settings_metrics_proxy.ts", "translate_page_metrics_test_browser.ts", - "translate_page_tests.ts", + "translate_page_test.ts", ] } @@ -176,12 +176,12 @@ files += [ "passwords_section_test_cros.ts" ] } else { files += [ - "live_caption_section_tests.ts", - "live_translate_section_tests.ts", + "live_caption_section_test.ts", + "live_translate_section_test.ts", "test_captions_browser_proxy.ts", "default_browser_test.ts", "import_data_dialog_test.ts", - "system_page_tests.ts", + "system_page_test.ts", ] }
diff --git a/chrome/test/data/webui/settings/about_page_tests.ts b/chrome/test/data/webui/settings/about_page_test.ts similarity index 99% rename from chrome/test/data/webui/settings/about_page_tests.ts rename to chrome/test/data/webui/settings/about_page_test.ts index f65da553..808f8f4 100644 --- a/chrome/test/data/webui/settings/about_page_tests.ts +++ b/chrome/test/data/webui/settings/about_page_test.ts
@@ -4,9 +4,9 @@ // clang-format off import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; - import {AboutPageBrowserProxyImpl, LifetimeBrowserProxyImpl, Route, Router, SettingsAboutPageElement, SettingsRoutes} from 'chrome://settings/settings.js'; import {assertTrue} from 'chrome://webui-test/chai_assert.js'; + import {TestAboutPageBrowserProxy} from './test_about_page_browser_proxy.js'; import {TestLifetimeBrowserProxy} from './test_lifetime_browser_proxy.js';
diff --git a/chrome/test/data/webui/settings/all_sites_tests.ts b/chrome/test/data/webui/settings/all_sites_test.ts similarity index 100% rename from chrome/test/data/webui/settings/all_sites_tests.ts rename to chrome/test/data/webui/settings/all_sites_test.ts
diff --git a/chrome/test/data/webui/settings/category_default_setting_tests.ts b/chrome/test/data/webui/settings/category_default_setting_test.ts similarity index 99% rename from chrome/test/data/webui/settings/category_default_setting_tests.ts rename to chrome/test/data/webui/settings/category_default_setting_test.ts index bc9fb30..13a0b5b 100644 --- a/chrome/test/data/webui/settings/category_default_setting_tests.ts +++ b/chrome/test/data/webui/settings/category_default_setting_test.ts
@@ -6,6 +6,7 @@ import {assertNotReached} from 'chrome://resources/js/assert_ts.js'; import {CategoryDefaultSettingElement,ContentSetting,ContentSettingProvider,ContentSettingsTypes,SiteSettingsPrefsBrowserProxyImpl} from 'chrome://settings/lazy_load.js'; import {assertEquals, assertNotEquals} from 'chrome://webui-test/chai_assert.js'; + import {TestSiteSettingsPrefsBrowserProxy} from './test_site_settings_prefs_browser_proxy.js'; import {createContentSettingTypeToValuePair,createDefaultContentSetting,createSiteSettingsPrefs,SiteSettingsPref} from './test_util.js'; // clang-format on
diff --git a/chrome/test/data/webui/settings/category_setting_exceptions_tests.ts b/chrome/test/data/webui/settings/category_setting_exceptions_test.ts similarity index 100% rename from chrome/test/data/webui/settings/category_setting_exceptions_tests.ts rename to chrome/test/data/webui/settings/category_setting_exceptions_test.ts
diff --git a/chrome/test/data/webui/settings/checkbox_tests.ts b/chrome/test/data/webui/settings/checkbox_test.ts similarity index 100% rename from chrome/test/data/webui/settings/checkbox_tests.ts rename to chrome/test/data/webui/settings/checkbox_test.ts
diff --git a/chrome/test/data/webui/settings/chooser_exception_list_entry_tests.ts b/chrome/test/data/webui/settings/chooser_exception_list_entry_test.ts similarity index 100% rename from chrome/test/data/webui/settings/chooser_exception_list_entry_tests.ts rename to chrome/test/data/webui/settings/chooser_exception_list_entry_test.ts
diff --git a/chrome/test/data/webui/settings/chooser_exception_list_tests.ts b/chrome/test/data/webui/settings/chooser_exception_list_test.ts similarity index 100% rename from chrome/test/data/webui/settings/chooser_exception_list_tests.ts rename to chrome/test/data/webui/settings/chooser_exception_list_test.ts
diff --git a/chrome/test/data/webui/settings/collapse_radio_button_tests.ts b/chrome/test/data/webui/settings/collapse_radio_button_test.ts similarity index 99% rename from chrome/test/data/webui/settings/collapse_radio_button_tests.ts rename to chrome/test/data/webui/settings/collapse_radio_button_test.ts index fbfdd007..866c0c8 100644 --- a/chrome/test/data/webui/settings/collapse_radio_button_tests.ts +++ b/chrome/test/data/webui/settings/collapse_radio_button_test.ts
@@ -4,9 +4,9 @@ // clang-format off import 'chrome://settings/lazy_load.js'; + import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {SettingsCollapseRadioButtonElement} from 'chrome://settings/lazy_load.js'; - import {assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js'; import {isChildVisible} from 'chrome://webui-test/test_util.js';
diff --git a/chrome/test/data/webui/settings/controlled_button_tests.ts b/chrome/test/data/webui/settings/controlled_button_test.ts similarity index 100% rename from chrome/test/data/webui/settings/controlled_button_tests.ts rename to chrome/test/data/webui/settings/controlled_button_test.ts
diff --git a/chrome/test/data/webui/settings/controlled_radio_button_tests.ts b/chrome/test/data/webui/settings/controlled_radio_button_test.ts similarity index 99% rename from chrome/test/data/webui/settings/controlled_radio_button_tests.ts rename to chrome/test/data/webui/settings/controlled_radio_button_test.ts index 561f370..24acaa7 100644 --- a/chrome/test/data/webui/settings/controlled_radio_button_tests.ts +++ b/chrome/test/data/webui/settings/controlled_radio_button_test.ts
@@ -4,6 +4,7 @@ // clang-format off import 'chrome://settings/settings.js'; + import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {ControlledRadioButtonElement} from 'chrome://settings/settings.js'; import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
diff --git a/chrome/test/data/webui/settings/cr_settings_browsertest.js b/chrome/test/data/webui/settings/cr_settings_browsertest.js index ff8713f..58b4e89d 100644 --- a/chrome/test/data/webui/settings/cr_settings_browsertest.js +++ b/chrome/test/data/webui/settings/cr_settings_browsertest.js
@@ -50,7 +50,7 @@ var CrSettingsAboutPageTest = class extends CrSettingsBrowserTest { /** @override */ get browsePreload() { - return 'chrome://settings/test_loader.html?module=settings/about_page_tests.js'; + return 'chrome://settings/test_loader.html?module=settings/about_page_test.js'; } }; @@ -104,7 +104,7 @@ var CrSettingsSpellCheckPageTest = class extends CrSettingsBrowserTest { /** @override */ get browsePreload() { - return 'chrome://settings/test_loader.html?module=settings/spell_check_page_tests.js'; + return 'chrome://settings/test_loader.html?module=settings/spell_check_page_test.js'; } }; @@ -121,7 +121,7 @@ var CrSettingsLanguagesPageTest = class extends CrSettingsBrowserTest { /** @override */ get browsePreload() { - return 'chrome://settings/test_loader.html?module=settings/languages_page_tests.js'; + return 'chrome://settings/test_loader.html?module=settings/languages_page_test.js'; } }; @@ -136,7 +136,7 @@ var CrSettingsTranslatePageTest = class extends CrSettingsBrowserTest { /** @override */ get browsePreload() { - return 'chrome://settings/test_loader.html?module=settings/translate_page_tests.js'; + return 'chrome://settings/test_loader.html?module=settings/translate_page_test.js'; } }; @@ -156,7 +156,7 @@ var CrSettingsLiveCaptionSection = class extends CrSettingsBrowserTest { /** @override */ get browsePreload() { - return 'chrome://settings/test_loader.html?module=settings/live_caption_section_tests.js'; + return 'chrome://settings/test_loader.html?module=settings/live_caption_section_test.js'; } }; @@ -167,7 +167,7 @@ var CrSettingsLiveTranslateSection = class extends CrSettingsBrowserTest { /** @override */ get browsePreload() { - return 'chrome://settings/test_loader.html?module=settings/live_translate_section_tests.js'; + return 'chrome://settings/test_loader.html?module=settings/live_translate_section_test.js'; } }; @@ -378,7 +378,7 @@ var CrSettingsSiteListTest = class extends CrSettingsBrowserTest { /** @override */ get browsePreload() { - return 'chrome://settings/test_loader.html?module=settings/site_list_tests.js'; + return 'chrome://settings/test_loader.html?module=settings/site_list_test.js'; } /** @override */ @@ -435,7 +435,7 @@ var CrSettingsSiteDetailsTest = class extends CrSettingsBrowserTest { /** @override */ get browsePreload() { - return 'chrome://settings/test_loader.html?module=settings/site_details_tests.js'; + return 'chrome://settings/test_loader.html?module=settings/site_details_test.js'; } /** @override */ @@ -727,7 +727,7 @@ var CrSettingsRouteTest = class extends CrSettingsBrowserTest { /** @override */ get browsePreload() { - return 'chrome://settings/test_loader.html?module=settings/route_tests.js'; + return 'chrome://settings/test_loader.html?module=settings/route_test.js'; } }; @@ -889,25 +889,25 @@ [['AppearanceFontsPage', 'appearance_fonts_page_test.js'], [ 'SettingsCategoryDefaultRadioGroup', - 'settings_category_default_radio_group_tests.js', + 'settings_category_default_radio_group_test.js', ], ['AntiAbusePage', 'anti_abuse_page_test.js'], - ['CategoryDefaultSetting', 'category_default_setting_tests.js'], - ['CategorySettingExceptions', 'category_setting_exceptions_tests.js'], - ['Checkbox', 'checkbox_tests.js'], - ['ChooserExceptionList', 'chooser_exception_list_tests.js'], - ['ChooserExceptionListEntry', 'chooser_exception_list_entry_tests.js'], - ['CollapseRadioButton', 'collapse_radio_button_tests.js'], - ['ControlledButton', 'controlled_button_tests.js'], - ['ControlledRadioButton', 'controlled_radio_button_tests.js'], + ['CategoryDefaultSetting', 'category_default_setting_test.js'], + ['CategorySettingExceptions', 'category_setting_exceptions_test.js'], + ['Checkbox', 'checkbox_test.js'], + ['ChooserExceptionList', 'chooser_exception_list_test.js'], + ['ChooserExceptionListEntry', 'chooser_exception_list_entry_test.js'], + ['CollapseRadioButton', 'collapse_radio_button_test.js'], + ['ControlledButton', 'controlled_button_test.js'], + ['ControlledRadioButton', 'controlled_radio_button_test.js'], ['AutofillAddressValidation', 'autofill_section_address_validation_test.js'], ['DoNotTrackToggle', 'do_not_track_toggle_test.js'], ['DownloadsPage', 'downloads_page_test.js'], - ['DropdownMenu', 'dropdown_menu_tests.js'], - ['ExtensionControlledIndicator', 'extension_controlled_indicator_tests.js'], - ['FileSystemSettingsList', 'file_system_site_list_tests.js'], - ['FileSystemSettingsListEntries', 'file_system_site_entry_tests.js'], - ['FileSystemSettingsListEntryItems', 'file_system_site_entry_item_tests.js'], + ['DropdownMenu', 'dropdown_menu_test.js'], + ['ExtensionControlledIndicator', 'extension_controlled_indicator_test.js'], + ['FileSystemSettingsList', 'file_system_site_list_test.js'], + ['FileSystemSettingsListEntries', 'file_system_site_entry_test.js'], + ['FileSystemSettingsListEntryItems', 'file_system_site_entry_item_test.js'], ['HelpPage', 'help_page_test.js'], ['PasswordView', 'password_view_test.js'], ['PasswordsExportDialog', 'passwords_export_dialog_test.js'], @@ -920,7 +920,7 @@ ['PeoplePage', 'people_page_test.js'], ['PeoplePageSyncControls', 'people_page_sync_controls_test.js'], ['PreloadingPage', 'preloading_page_test.js'], - ['ProtocolHandlers', 'protocol_handlers_tests.js'], + ['ProtocolHandlers', 'protocol_handlers_test.js'], ['RecentSitePermissions', 'recent_site_permissions_test.js'], // Flaky on all OSes. TODO(crbug.com/1127733): Enable the test. ['ResetPage', 'reset_page_test.js', 'DISABLED_All'], @@ -940,21 +940,21 @@ ['SecureDns', 'secure_dns_test.js'], ['SimpleConfirmationDialog', 'simple_confirmation_dialog_test.js'], ['SiteDataTest', 'site_data_test.js'], - ['SiteDetailsPermission', 'site_details_permission_tests.js'], + ['SiteDetailsPermission', 'site_details_permission_test.js'], [ 'SiteDetailsPermissionDeviceEntry', - 'site_details_permission_device_entry_tests.js' + 'site_details_permission_device_entry_test.js' ], - ['SiteEntry', 'site_entry_tests.js'], + ['SiteEntry', 'site_entry_test.js'], ['SiteFavicon', 'site_favicon_test.js'], - ['SiteListEntry', 'site_list_entry_tests.js'], - ['Slider', 'settings_slider_tests.js'], + ['SiteListEntry', 'site_list_entry_test.js'], + ['Slider', 'settings_slider_test.js'], ['StartupUrlsPage', 'startup_urls_page_test.js'], // Flaky on all OSes. TODO(crbug.com/1302405): Enable the test. ['Subpage', 'settings_subpage_test.js', 'DISABLED_All'], ['SyncAccountControl', 'sync_account_control_test.js'], - ['ToggleButton', 'settings_toggle_button_tests.js'], - ['ZoomLevels', 'zoom_levels_tests.js'], + ['ToggleButton', 'settings_toggle_button_test.js'], + ['ZoomLevels', 'zoom_levels_test.js'], ].forEach(test => registerTest(...test)); // Timeout on Linux dbg bots: https://crbug.com/1394737 @@ -983,7 +983,7 @@ GEN('#if !BUILDFLAG(IS_CHROMEOS)'); [['DefaultBrowser', 'default_browser_test.js'], ['ImportDataDialog', 'import_data_dialog_test.js'], - ['SystemPage', 'system_page_tests.js'], + ['SystemPage', 'system_page_test.js'], // TODO(crbug.com/1350019) Test is flaky on ChromeOS ['AppearancePage', 'appearance_page_test.js'], ].forEach(test => registerTest(...test)); @@ -991,7 +991,7 @@ GEN('#if !BUILDFLAG(IS_CHROMEOS_ASH)'); [['PeoplePageManageProfile', 'people_page_manage_profile_test.js'], - ['Languages', 'languages_tests.js'], + ['Languages', 'languages_test.js'], ['RelaunchConfirmationDialog', 'relaunch_confirmation_dialog_test.js'], ].forEach(test => registerTest(...test)); GEN('#endif'); @@ -1002,7 +1002,7 @@ GEN('#endif'); GEN('#if BUILDFLAG(GOOGLE_CHROME_BRANDING) && !BUILDFLAG(IS_CHROMEOS_ASH)'); -registerTest('MetricsReporting', 'metrics_reporting_tests.js'); +registerTest('MetricsReporting', 'metrics_reporting_test.js'); GEN('#endif'); GEN('#if BUILDFLAG(GOOGLE_CHROME_BRANDING)'); @@ -1033,7 +1033,7 @@ ], [ 'AllSites', - 'all_sites_tests.js', + 'all_sites_test.js', [ 'AllSites_EnableFirstPartySets', 'AllSites_DisableFirstPartySets',
diff --git a/chrome/test/data/webui/settings/cr_settings_interactive_ui_tests.js b/chrome/test/data/webui/settings/cr_settings_interactive_ui_tests.js index 6d91cf0..651720b1 100644 --- a/chrome/test/data/webui/settings/cr_settings_interactive_ui_tests.js +++ b/chrome/test/data/webui/settings/cr_settings_interactive_ui_tests.js
@@ -68,7 +68,7 @@ var SettingsUIInteractiveTest = class extends CrSettingsInteractiveUITest { /** @override */ get browsePreload() { - return 'chrome://settings/test_loader.html?module=settings/settings_ui_tests.js'; + return 'chrome://settings/test_loader.html?module=settings/settings_ui_test.js'; } };
diff --git a/chrome/test/data/webui/settings/dropdown_menu_tests.ts b/chrome/test/data/webui/settings/dropdown_menu_test.ts similarity index 100% rename from chrome/test/data/webui/settings/dropdown_menu_tests.ts rename to chrome/test/data/webui/settings/dropdown_menu_test.ts
diff --git a/chrome/test/data/webui/settings/extension_controlled_indicator_tests.ts b/chrome/test/data/webui/settings/extension_controlled_indicator_test.ts similarity index 100% rename from chrome/test/data/webui/settings/extension_controlled_indicator_tests.ts rename to chrome/test/data/webui/settings/extension_controlled_indicator_test.ts
diff --git a/chrome/test/data/webui/settings/file_system_site_entry_item_tests.ts b/chrome/test/data/webui/settings/file_system_site_entry_item_test.ts similarity index 100% rename from chrome/test/data/webui/settings/file_system_site_entry_item_tests.ts rename to chrome/test/data/webui/settings/file_system_site_entry_item_test.ts
diff --git a/chrome/test/data/webui/settings/file_system_site_entry_tests.ts b/chrome/test/data/webui/settings/file_system_site_entry_test.ts similarity index 100% rename from chrome/test/data/webui/settings/file_system_site_entry_tests.ts rename to chrome/test/data/webui/settings/file_system_site_entry_test.ts
diff --git a/chrome/test/data/webui/settings/file_system_site_list_tests.ts b/chrome/test/data/webui/settings/file_system_site_list_test.ts similarity index 99% rename from chrome/test/data/webui/settings/file_system_site_list_tests.ts rename to chrome/test/data/webui/settings/file_system_site_list_test.ts index af8322188..ee8e16d 100644 --- a/chrome/test/data/webui/settings/file_system_site_list_tests.ts +++ b/chrome/test/data/webui/settings/file_system_site_list_test.ts
@@ -98,4 +98,4 @@ testElement.shadowRoot!.querySelectorAll('file-system-site-entry'); assertEquals(2, fileSystemSiteEntries.length); }); -}); \ No newline at end of file +});
diff --git a/chrome/test/data/webui/settings/idle_load_tests.ts b/chrome/test/data/webui/settings/idle_load_test.ts similarity index 100% rename from chrome/test/data/webui/settings/idle_load_tests.ts rename to chrome/test/data/webui/settings/idle_load_test.ts
diff --git a/chrome/test/data/webui/settings/languages_page_tests.ts b/chrome/test/data/webui/settings/languages_page_test.ts similarity index 98% rename from chrome/test/data/webui/settings/languages_page_tests.ts rename to chrome/test/data/webui/settings/languages_page_test.ts index 8d316dda..81dc4cb 100644 --- a/chrome/test/data/webui/settings/languages_page_tests.ts +++ b/chrome/test/data/webui/settings/languages_page_test.ts
@@ -134,8 +134,8 @@ setup(function() { const addLanguagesButton = - languagesPage.shadowRoot!.querySelector<HTMLElement>( - '#addLanguages')!; + languagesPage.shadowRoot!.querySelector<HTMLElement>('#addLanguages')! + ; const whenDialogOpen = eventToPromise('cr-dialog-open', languagesPage); addLanguagesButton.click(); @@ -346,8 +346,7 @@ const listItems = languagesPage.shadowRoot!.querySelector('#languagesSection')! .querySelectorAll<HTMLElement>('.list-item'); - const domRepeat = - languagesPage.shadowRoot!.querySelector('dom-repeat'); + const domRepeat = languagesPage.shadowRoot!.querySelector('dom-repeat'); assertTrue(!!domRepeat); let num_visibles = 0;
diff --git a/chrome/test/data/webui/settings/languages_tests.ts b/chrome/test/data/webui/settings/languages_test.ts similarity index 100% rename from chrome/test/data/webui/settings/languages_tests.ts rename to chrome/test/data/webui/settings/languages_test.ts
diff --git a/chrome/test/data/webui/settings/live_caption_section_tests.ts b/chrome/test/data/webui/settings/live_caption_section_test.ts similarity index 100% rename from chrome/test/data/webui/settings/live_caption_section_tests.ts rename to chrome/test/data/webui/settings/live_caption_section_test.ts
diff --git a/chrome/test/data/webui/settings/live_translate_section_tests.ts b/chrome/test/data/webui/settings/live_translate_section_test.ts similarity index 100% rename from chrome/test/data/webui/settings/live_translate_section_tests.ts rename to chrome/test/data/webui/settings/live_translate_section_test.ts
diff --git a/chrome/test/data/webui/settings/metrics_reporting_tests.ts b/chrome/test/data/webui/settings/metrics_reporting_test.ts similarity index 100% rename from chrome/test/data/webui/settings/metrics_reporting_tests.ts rename to chrome/test/data/webui/settings/metrics_reporting_test.ts
diff --git a/chrome/test/data/webui/settings/on_startup_page_tests.ts b/chrome/test/data/webui/settings/on_startup_page_test.ts similarity index 100% rename from chrome/test/data/webui/settings/on_startup_page_tests.ts rename to chrome/test/data/webui/settings/on_startup_page_test.ts
diff --git a/chrome/test/data/webui/settings/protocol_handlers_tests.ts b/chrome/test/data/webui/settings/protocol_handlers_test.ts similarity index 100% rename from chrome/test/data/webui/settings/protocol_handlers_tests.ts rename to chrome/test/data/webui/settings/protocol_handlers_test.ts
diff --git a/chrome/test/data/webui/settings/route_tests.ts b/chrome/test/data/webui/settings/route_test.ts similarity index 100% rename from chrome/test/data/webui/settings/route_tests.ts rename to chrome/test/data/webui/settings/route_test.ts
diff --git a/chrome/test/data/webui/settings/settings_category_default_radio_group_tests.ts b/chrome/test/data/webui/settings/settings_category_default_radio_group_test.ts similarity index 100% rename from chrome/test/data/webui/settings/settings_category_default_radio_group_tests.ts rename to chrome/test/data/webui/settings/settings_category_default_radio_group_test.ts
diff --git a/chrome/test/data/webui/settings/settings_idle_load_browsertest.js b/chrome/test/data/webui/settings/settings_idle_load_browsertest.js index 7e69311f..57d46e0 100644 --- a/chrome/test/data/webui/settings/settings_idle_load_browsertest.js +++ b/chrome/test/data/webui/settings/settings_idle_load_browsertest.js
@@ -15,7 +15,7 @@ /** @override */ browsePreload: - 'chrome://settings/test_loader.html?module=settings/idle_load_tests.js', + 'chrome://settings/test_loader.html?module=settings/idle_load_test.js', /** @override */ isAsync: true,
diff --git a/chrome/test/data/webui/settings/settings_slider_tests.ts b/chrome/test/data/webui/settings/settings_slider_test.ts similarity index 100% rename from chrome/test/data/webui/settings/settings_slider_tests.ts rename to chrome/test/data/webui/settings/settings_slider_test.ts
diff --git a/chrome/test/data/webui/settings/settings_toggle_button_tests.ts b/chrome/test/data/webui/settings/settings_toggle_button_test.ts similarity index 100% rename from chrome/test/data/webui/settings/settings_toggle_button_tests.ts rename to chrome/test/data/webui/settings/settings_toggle_button_test.ts
diff --git a/chrome/test/data/webui/settings/settings_ui_tests.ts b/chrome/test/data/webui/settings/settings_ui_test.ts similarity index 100% rename from chrome/test/data/webui/settings/settings_ui_tests.ts rename to chrome/test/data/webui/settings/settings_ui_test.ts
diff --git a/chrome/test/data/webui/settings/site_details_permission_device_entry_tests.ts b/chrome/test/data/webui/settings/site_details_permission_device_entry_test.ts similarity index 100% rename from chrome/test/data/webui/settings/site_details_permission_device_entry_tests.ts rename to chrome/test/data/webui/settings/site_details_permission_device_entry_test.ts
diff --git a/chrome/test/data/webui/settings/site_details_permission_tests.ts b/chrome/test/data/webui/settings/site_details_permission_test.ts similarity index 100% rename from chrome/test/data/webui/settings/site_details_permission_tests.ts rename to chrome/test/data/webui/settings/site_details_permission_test.ts
diff --git a/chrome/test/data/webui/settings/site_details_tests.ts b/chrome/test/data/webui/settings/site_details_test.ts similarity index 100% rename from chrome/test/data/webui/settings/site_details_tests.ts rename to chrome/test/data/webui/settings/site_details_test.ts
diff --git a/chrome/test/data/webui/settings/site_entry_tests.ts b/chrome/test/data/webui/settings/site_entry_test.ts similarity index 100% rename from chrome/test/data/webui/settings/site_entry_tests.ts rename to chrome/test/data/webui/settings/site_entry_test.ts
diff --git a/chrome/test/data/webui/settings/site_list_entry_tests.ts b/chrome/test/data/webui/settings/site_list_entry_test.ts similarity index 100% rename from chrome/test/data/webui/settings/site_list_entry_tests.ts rename to chrome/test/data/webui/settings/site_list_entry_test.ts
diff --git a/chrome/test/data/webui/settings/site_list_tests.ts b/chrome/test/data/webui/settings/site_list_test.ts similarity index 100% rename from chrome/test/data/webui/settings/site_list_tests.ts rename to chrome/test/data/webui/settings/site_list_test.ts
diff --git a/chrome/test/data/webui/settings/spell_check_page_tests.ts b/chrome/test/data/webui/settings/spell_check_page_test.ts similarity index 100% rename from chrome/test/data/webui/settings/spell_check_page_tests.ts rename to chrome/test/data/webui/settings/spell_check_page_test.ts
diff --git a/chrome/test/data/webui/settings/system_page_tests.ts b/chrome/test/data/webui/settings/system_page_test.ts similarity index 100% rename from chrome/test/data/webui/settings/system_page_tests.ts rename to chrome/test/data/webui/settings/system_page_test.ts
diff --git a/chrome/test/data/webui/settings/translate_page_tests.ts b/chrome/test/data/webui/settings/translate_page_test.ts similarity index 98% rename from chrome/test/data/webui/settings/translate_page_tests.ts rename to chrome/test/data/webui/settings/translate_page_test.ts index dadc2ba..b2a8f0131 100644 --- a/chrome/test/data/webui/settings/translate_page_tests.ts +++ b/chrome/test/data/webui/settings/translate_page_test.ts
@@ -91,11 +91,13 @@ suite(translate_page_tests.TestNames.TranslateSettings, function() { test('change target language', function() { - const targetLanguageSelector = translatePage.shadowRoot!.querySelector - <HTMLSelectElement>('#targetLanguage'); + const targetLanguageSelector = + translatePage.shadowRoot!.querySelector<HTMLSelectElement>( + '#targetLanguage'); assertTrue(!!targetLanguageSelector); - assertEquals(targetLanguageSelector.value, + assertEquals( + targetLanguageSelector.value, translatePage.getPref(translateTarget).value); targetLanguageSelector.value = 'sw';
diff --git a/chrome/test/data/webui/settings/zoom_levels_tests.ts b/chrome/test/data/webui/settings/zoom_levels_test.ts similarity index 100% rename from chrome/test/data/webui/settings/zoom_levels_tests.ts rename to chrome/test/data/webui/settings/zoom_levels_test.ts
diff --git a/chrome/utility/importer/safari_importer.h b/chrome/utility/importer/safari_importer.h index e953a88..db83a664 100644 --- a/chrome/utility/importer/safari_importer.h +++ b/chrome/utility/importer/safari_importer.h
@@ -17,14 +17,6 @@ #include "chrome/utility/importer/importer.h" #include "components/favicon_base/favicon_usage_data.h" -#if __OBJC__ -@class NSDictionary; -@class NSString; -#else -class NSDictionary; -class NSString; -#endif - class GURL; struct ImportedBookmarkEntry; @@ -67,18 +59,6 @@ void ParseBookmarks(const std::u16string& toolbar_name, std::vector<ImportedBookmarkEntry>* bookmarks); - // Function to recursively read Bookmarks out of Safari plist. - // |bookmark_folder| The dictionary containing a folder to parse. - // |parent_path_elements| Path elements up to this point. - // |is_in_toolbar| Is this folder in the toolbar. - // |out_bookmarks| BookMark element array to write into. - void RecursiveReadBookmarksFolder( - NSDictionary* bookmark_folder, - const std::vector<std::u16string>& parent_path_elements, - bool is_in_toolbar, - const std::u16string& toolbar_name, - std::vector<ImportedBookmarkEntry>* out_bookmarks); - // Opens the favicon database file. bool OpenDatabase(sql::Database* db);
diff --git a/chrome/utility/importer/safari_importer.mm b/chrome/utility/importer/safari_importer.mm index 0b1bfd1..25e3544a 100644 --- a/chrome/utility/importer/safari_importer.mm +++ b/chrome/utility/importer/safari_importer.mm
@@ -25,12 +25,121 @@ #include "sql/statement.h" #include "url/gurl.h" +namespace { + +// Function to recursively read Bookmarks out of Safari plist. +// +// - `bookmark_folder`: The dictionary containing a folder to parse. +// - `parent_path_elements`: Path elements up to this point. +// - `is_in_toolbar`: True if this folder is in the toolbar. +// - `out_bookmarks`: The Bookmark element array to write into. +void RecursiveReadBookmarksFolder( + NSDictionary* bookmark_folder, + const std::vector<std::u16string>& parent_path_elements, + bool is_in_toolbar, + const std::u16string& toolbar_name, + std::vector<ImportedBookmarkEntry>* out_bookmarks) { + DCHECK(bookmark_folder); + + NSString* type = bookmark_folder[@"WebBookmarkType"]; + NSString* title = bookmark_folder[@"Title"]; + + // Are we the dictionary that contains all other bookmarks? + // We need to know this so we don't add it to the path. + bool is_top_level_bookmarks_container = + bookmark_folder[@"WebBookmarkFileVersion"] != nil; + + // We're expecting a list of bookmarks here, if that isn't what we got, fail. + if (!is_top_level_bookmarks_container) { + // Top level containers sometimes don't have title attributes. + if (![type isEqualToString:@"WebBookmarkTypeList"] || !title) { + NOTREACHED() << "Type=(" + << (type ? base::SysNSStringToUTF8(type) : "Null type") + << ") Title=(" + << (title ? base::SysNSStringToUTF8(title) : "Null title") + << ")"; + return; + } + } + + NSArray* elements = bookmark_folder[@"Children"]; + if (!elements && (!parent_path_elements.empty() || !is_in_toolbar) && + ![title isEqualToString:@"BookmarksMenu"]) { + // This is an empty folder, so add it explicitly. Note that the condition + // above prevents either the toolbar folder or the bookmarks menu from being + // added if either is empty. Note also that all non-empty folders are added + // implicitly when their children are added. + ImportedBookmarkEntry entry; + // Safari doesn't specify a creation time for the folder. + entry.creation_time = base::Time::Now(); + entry.title = base::SysNSStringToUTF16(title); + entry.path = parent_path_elements; + entry.in_toolbar = is_in_toolbar; + entry.is_folder = true; + + out_bookmarks->push_back(entry); + return; + } + + std::vector<std::u16string> path_elements(parent_path_elements); + // Create a folder for the toolbar, but not for the bookmarks menu. + if (path_elements.empty() && [title isEqualToString:@"BookmarksBar"]) { + is_in_toolbar = true; + path_elements.push_back(toolbar_name); + } else if (!is_top_level_bookmarks_container && + !(path_elements.empty() && + [title isEqualToString:@"BookmarksMenu"])) { + if (title) { + path_elements.push_back(base::SysNSStringToUTF16(title)); + } + } + + // Iterate over individual bookmarks. + for (NSDictionary* bookmark in elements) { + NSString* element_type = bookmark[@"WebBookmarkType"]; + if (!element_type) { + continue; + } + + // If this is a folder, recurse. + if ([element_type isEqualToString:@"WebBookmarkTypeList"]) { + RecursiveReadBookmarksFolder(bookmark, path_elements, is_in_toolbar, + toolbar_name, out_bookmarks); + } + + // If we didn't see a bookmark folder, then we're expecting a bookmark + // item. If that's not what we got then ignore it. + if (![element_type isEqualToString:@"WebBookmarkTypeLeaf"]) { + continue; + } + + NSString* element_url = bookmark[@"URLString"]; + NSString* element_title = bookmark[@"URIDictionary"][@"title"]; + + if (!element_url || !element_title) { + continue; + } + + // Output Bookmark. + ImportedBookmarkEntry entry; + // Safari doesn't specify a creation time for the bookmark. + entry.creation_time = base::Time::Now(); + entry.title = base::SysNSStringToUTF16(element_title); + entry.url = GURL(base::SysNSStringToUTF8(element_url)); + entry.path = path_elements; + entry.in_toolbar = is_in_toolbar; + + out_bookmarks->push_back(entry); + } +} + +} // namespace + SafariImporter::SafariImporter(const base::FilePath& library_dir) : library_dir_(library_dir) { } -SafariImporter::~SafariImporter() { -} +SafariImporter::~SafariImporter() = default; void SafariImporter::StartImport(const importer::SourceProfile& source_profile, uint16_t items, @@ -138,106 +247,6 @@ } } -void SafariImporter::RecursiveReadBookmarksFolder( - NSDictionary* bookmark_folder, - const std::vector<std::u16string>& parent_path_elements, - bool is_in_toolbar, - const std::u16string& toolbar_name, - std::vector<ImportedBookmarkEntry>* out_bookmarks) { - DCHECK(bookmark_folder); - - NSString* type = bookmark_folder[@"WebBookmarkType"]; - NSString* title = bookmark_folder[@"Title"]; - - // Are we the dictionary that contains all other bookmarks? - // We need to know this so we don't add it to the path. - bool is_top_level_bookmarks_container = - bookmark_folder[@"WebBookmarkFileVersion"] != nil; - - // We're expecting a list of bookmarks here, if that isn't what we got, fail. - if (!is_top_level_bookmarks_container) { - // Top level containers sometimes don't have title attributes. - if (![type isEqualToString:@"WebBookmarkTypeList"] || !title) { - NOTREACHED() << "Type=(" - << (type ? base::SysNSStringToUTF8(type) : "Null type") - << ") Title=(" - << (title ? base::SysNSStringToUTF8(title) : "Null title") - << ")"; - return; - } - } - - NSArray* elements = bookmark_folder[@"Children"]; - if (!elements && - (!parent_path_elements.empty() || !is_in_toolbar) && - ![title isEqualToString:@"BookmarksMenu"]) { - // This is an empty folder, so add it explicitly. Note that the condition - // above prevents either the toolbar folder or the bookmarks menu from being - // added if either is empty. Note also that all non-empty folders are added - // implicitly when their children are added. - ImportedBookmarkEntry entry; - // Safari doesn't specify a creation time for the folder. - entry.creation_time = base::Time::Now(); - entry.title = base::SysNSStringToUTF16(title); - entry.path = parent_path_elements; - entry.in_toolbar = is_in_toolbar; - entry.is_folder = true; - - out_bookmarks->push_back(entry); - return; - } - - std::vector<std::u16string> path_elements(parent_path_elements); - // Create a folder for the toolbar, but not for the bookmarks menu. - if (path_elements.empty() && [title isEqualToString:@"BookmarksBar"]) { - is_in_toolbar = true; - path_elements.push_back(toolbar_name); - } else if (!is_top_level_bookmarks_container && - !(path_elements.empty() && - [title isEqualToString:@"BookmarksMenu"])) { - if (title) - path_elements.push_back(base::SysNSStringToUTF16(title)); - } - - // Iterate over individual bookmarks. - for (NSDictionary* bookmark in elements) { - NSString* element_type = bookmark[@"WebBookmarkType"]; - if (!element_type) - continue; - - // If this is a folder, recurse. - if ([element_type isEqualToString:@"WebBookmarkTypeList"]) { - RecursiveReadBookmarksFolder(bookmark, - path_elements, - is_in_toolbar, - toolbar_name, - out_bookmarks); - } - - // If we didn't see a bookmark folder, then we're expecting a bookmark - // item. If that's not what we got then ignore it. - if (![element_type isEqualToString:@"WebBookmarkTypeLeaf"]) - continue; - - NSString* element_url = bookmark[@"URLString"]; - NSString* element_title = bookmark[@"URIDictionary"][@"title"]; - - if (!element_url || !element_title) - continue; - - // Output Bookmark. - ImportedBookmarkEntry entry; - // Safari doesn't specify a creation time for the bookmark. - entry.creation_time = base::Time::Now(); - entry.title = base::SysNSStringToUTF16(element_title); - entry.url = GURL(base::SysNSStringToUTF8(element_url)); - entry.path = path_elements; - entry.in_toolbar = is_in_toolbar; - - out_bookmarks->push_back(entry); - } -} - void SafariImporter::ParseBookmarks( const std::u16string& toolbar_name, std::vector<ImportedBookmarkEntry>* bookmarks) {
diff --git a/chromeos/ash/components/nearby/presence/credentials/BUILD.gn b/chromeos/ash/components/nearby/presence/credentials/BUILD.gn index 03974ba..7859f4f0 100644 --- a/chromeos/ash/components/nearby/presence/credentials/BUILD.gn +++ b/chromeos/ash/components/nearby/presence/credentials/BUILD.gn
@@ -28,12 +28,15 @@ "//base", "//chromeos/ash/components/nearby/common/client", "//chromeos/ash/components/nearby/presence/proto", + "//chromeos/strings", "//components/prefs", "//components/signin/public/identity_manager", "//net", "//net/traffic_annotation", "//services/network/public/cpp", "//services/network/public/mojom", + "//ui/base", + "//ui/chromeos", "//url", ] @@ -59,12 +62,15 @@ "//base/test:test_support", "//chromeos/ash/components/nearby/common/client", "//chromeos/ash/components/nearby/presence/proto", + "//chromeos/strings", "//components/prefs:test_support", "//components/signin/public/identity_manager:test_support", "//net", "//net/traffic_annotation:test_support", "//services/network:test_support", "//testing/gtest", + "//ui/base", + "//ui/chromeos", ] public_deps = [
diff --git a/chromeos/ash/components/nearby/presence/credentials/DEPS b/chromeos/ash/components/nearby/presence/credentials/DEPS index 806cb80..89254fc 100644 --- a/chromeos/ash/components/nearby/presence/credentials/DEPS +++ b/chromeos/ash/components/nearby/presence/credentials/DEPS
@@ -1,4 +1,6 @@ include_rules = [ "+components/signin/public", "+third_party/nearby", + "+ui/base/l10n", + "+ui/chromeos" ]
diff --git a/chromeos/ash/components/nearby/presence/credentials/local_device_data_provider_impl.cc b/chromeos/ash/components/nearby/presence/credentials/local_device_data_provider_impl.cc index 912f40c..a834cf5 100644 --- a/chromeos/ash/components/nearby/presence/credentials/local_device_data_provider_impl.cc +++ b/chromeos/ash/components/nearby/presence/credentials/local_device_data_provider_impl.cc
@@ -5,11 +5,16 @@ #include "chromeos/ash/components/nearby/presence/credentials/local_device_data_provider_impl.h" #include "base/rand_util.h" +#include "base/strings/utf_string_conversions.h" #include "chromeos/ash/components/nearby/presence/credentials/prefs.h" #include "chromeos/ash/components/nearby/presence/credentials/proto_conversions.h" +#include "chromeos/strings/grit/chromeos_strings.h" #include "components/prefs/pref_service.h" +#include "components/signin/public/identity_manager/account_info.h" #include "components/signin/public/identity_manager/identity_manager.h" #include "google_apis/gaia/gaia_auth_util.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/chromeos/devicetype_utils.h" namespace { @@ -24,8 +29,6 @@ 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}; -const std::string& kPlaceHolderString = "0123456789"; - } // namespace namespace ash::nearby::presence { @@ -71,16 +74,50 @@ return id; } +std::string LocalDeviceDataProviderImpl::GetDeviceName() const { + std::u16string device_type = ui::GetChromeOSDeviceName(); + + const CoreAccountInfo account_info = + identity_manager_->GetPrimaryAccountInfo(signin::ConsentLevel::kSignin); + std::string given_name = + identity_manager_->FindExtendedAccountInfo(account_info).given_name; + + if (given_name.empty()) { + return base::UTF16ToUTF8(device_type); + } + + std::string device_name = + l10n_util::GetStringFUTF8(IDS_NEARBY_PRESENCE_DEVICE_NAME, + base::UTF8ToUTF16(given_name), device_type); + return device_name; +} + ::nearby::internal::Metadata LocalDeviceDataProviderImpl::GetDeviceMetadata() { - // TODO (b/276307539): Implement `GetDeviceMetadata`, this - // default implementation is to get the skeleton class to compile. + std::string user_name = + pref_service_->GetString(prefs::kNearbyPresenceUserNamePrefName); + std::string profile_url = + pref_service_->GetString(prefs::kNearbyPresenceProfileUrlPrefName); + + // At this point in the Nearby Presence flow, if the `user_name` and + // `profile_url` are not available, something is wrong. The `user_name` and + // `profile_url` are persisted to prefs during first time registration flow, + // which happens before the Device Metadata is needed to construct + // credentials. + CHECK(!user_name.empty()); + CHECK(!profile_url.empty()); + + // TODO (b/276307539): Change `device_type` to DEVICE_TYPE_CHROMEOS once + // available in //third_party/nearby protos. + // + // `mac_address` is empty for Nearby Presence MVP on ChromeOS since + // broadcasting is not supported. return BuildMetadata( /*device_type=*/::nearby::internal::DeviceType::DEVICE_TYPE_LAPTOP, - /*account_name=*/kPlaceHolderString, - /*device_name=*/kPlaceHolderString, - /*user_name=*/kPlaceHolderString, - /*profile_url=*/kPlaceHolderString, - /*mac_address=*/kPlaceHolderString); + /*account_name=*/GetAccountName(), + /*device_name=*/GetDeviceName(), + /*user_name=*/user_name, + /*profile_url=*/profile_url, + /*mac_address=*/std::string()); } std::string LocalDeviceDataProviderImpl::GetAccountName() {
diff --git a/chromeos/ash/components/nearby/presence/credentials/local_device_data_provider_impl.h b/chromeos/ash/components/nearby/presence/credentials/local_device_data_provider_impl.h index 623d40c43..4746b83 100644 --- a/chromeos/ash/components/nearby/presence/credentials/local_device_data_provider_impl.h +++ b/chromeos/ash/components/nearby/presence/credentials/local_device_data_provider_impl.h
@@ -41,6 +41,11 @@ const std::string& image_url) override; private: + // Creates a device name of the form "<given name>'s <device type>." + // For example, "Josh's Chromebook." If a given name cannot be found, returns + // just the device type. + std::string GetDeviceName() const; + PrefService* pref_service_ = nullptr; const raw_ptr<signin::IdentityManager> identity_manager_; };
diff --git a/chromeos/ash/components/nearby/presence/credentials/local_device_data_provider_impl_unittest.cc b/chromeos/ash/components/nearby/presence/credentials/local_device_data_provider_impl_unittest.cc index d0c75d7..7a4c33a 100644 --- a/chromeos/ash/components/nearby/presence/credentials/local_device_data_provider_impl_unittest.cc +++ b/chromeos/ash/components/nearby/presence/credentials/local_device_data_provider_impl_unittest.cc
@@ -1,23 +1,34 @@ // Copyright 2023 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. + #include <string> #include "chromeos/ash/components/nearby/presence/credentials/local_device_data_provider_impl.h" +#include "base/strings/utf_string_conversions.h" #include "base/test/gtest_util.h" #include "base/test/task_environment.h" #include "chromeos/ash/components/nearby/presence/credentials/local_device_data_provider.h" #include "chromeos/ash/components/nearby/presence/credentials/prefs.h" +#include "chromeos/strings/grit/chromeos_strings.h" +#include "components/prefs/pref_registry.h" +#include "components/prefs/pref_registry_simple.h" #include "components/prefs/testing_pref_service.h" +#include "components/signin/public/identity_manager/account_info.h" #include "components/signin/public/identity_manager/identity_test_environment.h" #include "components/signin/public/identity_manager/identity_test_utils.h" #include "testing/gtest/include/gtest/gtest.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/chromeos/devicetype_utils.h" namespace { const std::string kUserEmail = "test.tester@gmail.com"; const std::string kCanocalizedUserEmail = "testtester@gmail.com"; +const std::string kGivenName = "Test"; +const std::string kUserName = "Test Tester"; +const std::string kProfileUrl = "https://example.com"; } // namespace @@ -27,7 +38,7 @@ public: void SetUp() override { RegisterNearbyPresenceCredentialPrefs(pref_service_.registry()); - identity_test_env_.MakePrimaryAccountAvailable( + account_info_ = identity_test_env_.MakePrimaryAccountAvailable( kUserEmail, signin::ConsentLevel::kSignin); } @@ -39,6 +50,7 @@ void DestroyDataProvider() { local_device_data_provider_.reset(); } protected: + AccountInfo account_info_; base::test::TaskEnvironment task_environment_; TestingPrefServiceSimple pref_service_; signin::IdentityTestEnvironment identity_test_env_; @@ -68,4 +80,36 @@ local_device_data_provider_->GetAccountName()); } +TEST_F(LocalDeviceDataProviderImplTest, Metadata) { + CreateDataProvider(); + + // Assume that first time registration has already occurred. + pref_service_.SetString(prefs::kNearbyPresenceUserNamePrefName, kUserName); + pref_service_.SetString(prefs::kNearbyPresenceProfileUrlPrefName, + kProfileUrl); + + // Assume that without the given name, the device name is just the + // device type. + ::nearby::internal::Metadata metadata = + local_device_data_provider_->GetDeviceMetadata(); + EXPECT_EQ(base::UTF16ToUTF8(ui::GetChromeOSDeviceName()), + metadata.device_name()); + + // Populate the account information and expect the device name to include the + // user's given name. + account_info_.given_name = kGivenName; + identity_test_env_.UpdateAccountInfoForAccount(account_info_); + metadata = local_device_data_provider_->GetDeviceMetadata(); + EXPECT_EQ(l10n_util::GetStringFUTF8(IDS_NEARBY_PRESENCE_DEVICE_NAME, + base::UTF8ToUTF16(kGivenName), + ui::GetChromeOSDeviceName()), + metadata.device_name()); + + // Confirm the other fields are expected. + EXPECT_EQ(kCanocalizedUserEmail, metadata.account_name()); + EXPECT_EQ(kUserName, metadata.user_name()); + EXPECT_EQ(kProfileUrl, metadata.device_profile_url()); + EXPECT_EQ(std::string(), metadata.bluetooth_mac_address()); +} + } // namespace ash::nearby::presence
diff --git a/chromeos/ash/components/nearby/presence/credentials/prefs.cc b/chromeos/ash/components/nearby/presence/credentials/prefs.cc index 3841be65..a3f9e1f 100644 --- a/chromeos/ash/components/nearby/presence/credentials/prefs.cc +++ b/chromeos/ash/components/nearby/presence/credentials/prefs.cc
@@ -13,6 +13,8 @@ const char kNearbyPresenceDeviceIdPrefName[] = "nearby_presence.local_device_id"; +const char kNearbyPresenceUserNamePrefName[] = "nearby_presence.user_name"; +const char kNearbyPresenceProfileUrlPrefName[] = "nearby_presence.profile_url"; } // namespace prefs @@ -20,6 +22,10 @@ // These prefs are not synced across devices on purpose. registry->RegisterStringPref(prefs::kNearbyPresenceDeviceIdPrefName, /*default_value=*/std::string()); + registry->RegisterStringPref(prefs::kNearbyPresenceUserNamePrefName, + /*default_value=*/std::string()); + registry->RegisterStringPref(prefs::kNearbyPresenceProfileUrlPrefName, + /*default_value=*/std::string()); } } // namespace ash::nearby::presence
diff --git a/chromeos/ash/components/nearby/presence/credentials/prefs.h b/chromeos/ash/components/nearby/presence/credentials/prefs.h index 2d5328fa..50d00b6 100644 --- a/chromeos/ash/components/nearby/presence/credentials/prefs.h +++ b/chromeos/ash/components/nearby/presence/credentials/prefs.h
@@ -12,6 +12,8 @@ namespace prefs { extern const char kNearbyPresenceDeviceIdPrefName[]; +extern const char kNearbyPresenceUserNamePrefName[]; +extern const char kNearbyPresenceProfileUrlPrefName[]; } // namespace prefs
diff --git a/chromeos/ash/components/nearby/presence/credentials/proto_conversions.cc b/chromeos/ash/components/nearby/presence/credentials/proto_conversions.cc index c601c3b..7e12724a 100644 --- a/chromeos/ash/components/nearby/presence/credentials/proto_conversions.cc +++ b/chromeos/ash/components/nearby/presence/credentials/proto_conversions.cc
@@ -16,6 +16,7 @@ ::nearby::internal::Metadata proto; proto.set_device_type(device_type); proto.set_account_name(account_name); + proto.set_user_name(user_name); proto.set_device_name(device_name); proto.set_user_name(user_name); proto.set_device_profile_url(profile_url);
diff --git a/chromeos/ash/components/network/hotspot_state_handler_unittest.cc b/chromeos/ash/components/network/hotspot_state_handler_unittest.cc index ff7055d..cf03f35 100644 --- a/chromeos/ash/components/network/hotspot_state_handler_unittest.cc +++ b/chromeos/ash/components/network/hotspot_state_handler_unittest.cc
@@ -107,6 +107,17 @@ EXPECT_EQ(hotspot_state_handler_->GetHotspotState(), hotspot_config::mojom::HotspotState::kEnabling); EXPECT_EQ(3u, observer_.hotspot_status_changed_count()); + + // Simulate user stopping tethering. + status_dict.Set(shill::kTetheringStatusStateProperty, + shill::kTetheringStateStopping); + network_state_test_helper_.manager_test()->SetManagerProperty( + shill::kTetheringStatusProperty, base::Value(status_dict.Clone())); + base::RunLoop().RunUntilIdle(); + + EXPECT_EQ(hotspot_state_handler_->GetHotspotState(), + hotspot_config::mojom::HotspotState::kDisabling); + EXPECT_EQ(4u, observer_.hotspot_status_changed_count()); } TEST_F(HotspotStateHandlerTest, GetHotspotActiveClientCount) {
diff --git a/chromeos/ash/components/network/hotspot_util.cc b/chromeos/ash/components/network/hotspot_util.cc index 636440c..8ddfaeb 100644 --- a/chromeos/ash/components/network/hotspot_util.cc +++ b/chromeos/ash/components/network/hotspot_util.cc
@@ -89,6 +89,10 @@ return HotspotState::kEnabling; } + if (shill_state == shill::kTetheringStateStopping) { + return HotspotState::kDisabling; + } + NOTREACHED() << "Unexpected shill tethering state: " << shill_state; return HotspotState::kDisabled; }
diff --git a/chromeos/ash/components/quick_start/quick_start_message.cc b/chromeos/ash/components/quick_start/quick_start_message.cc index e5dd4c98..993f4e1 100644 --- a/chromeos/ash/components/quick_start/quick_start_message.cc +++ b/chromeos/ash/components/quick_start/quick_start_message.cc
@@ -66,7 +66,6 @@ if (enable_sandbox_checks_) { CHECK(sandbox::policy::Sandbox::IsProcessSandboxed()); } - std::string str_data(data.begin(), data.end()); absl::optional<base::Value> data_value = base::JSONReader::Read(str_data); if (!data_value.has_value()) {
diff --git a/chromeos/ash/services/nearby/public/cpp/mock_quick_start_decoder.h b/chromeos/ash/services/nearby/public/cpp/mock_quick_start_decoder.h index f468c2b6..440b3873 100644 --- a/chromeos/ash/services/nearby/public/cpp/mock_quick_start_decoder.h +++ b/chromeos/ash/services/nearby/public/cpp/mock_quick_start_decoder.h
@@ -42,6 +42,12 @@ DecodeGetAssertionResponseCallback callback), (override)); + MOCK_METHOD(void, + DecodeWifiCredentialsResponse, + (const std::vector<uint8_t>& data, + DecodeWifiCredentialsResponseCallback callback), + (override)); + private: mojo::ReceiverSet<ash::quick_start::mojom::QuickStartDecoder> receiver_set_; mojo::SharedRemote<ash::quick_start::mojom::QuickStartDecoder> shared_remote_;
diff --git a/chromeos/ash/services/nearby/public/mojom/quick_start_decoder.mojom b/chromeos/ash/services/nearby/public/mojom/quick_start_decoder.mojom index 482773c..6c20fde 100644 --- a/chromeos/ash/services/nearby/public/mojom/quick_start_decoder.mojom +++ b/chromeos/ash/services/nearby/public/mojom/quick_start_decoder.mojom
@@ -21,6 +21,11 @@ DecodeBootstrapConfigurations(array<uint8> data) => ( BootstrapConfigurations? bootstrap_configurations); + // Decode a D2D response to a request for Wifi Credentials + // This response is JSON, with a Base64 encoded JSON payload + DecodeWifiCredentialsResponse(array<uint8> data) => ( + GetWifiCredentialsResponse response); + // Decode a FIDO CTAP2 GetAssertionResponse from the phone into a struct // that details fields we need to pass along to GAIA as well as error // codes from the CBOR decoding step and from the phone.
diff --git a/chromeos/ash/services/nearby/public/mojom/quick_start_decoder_types.mojom b/chromeos/ash/services/nearby/public/mojom/quick_start_decoder_types.mojom index 995075e..4a900bbe 100644 --- a/chromeos/ash/services/nearby/public/mojom/quick_start_decoder_types.mojom +++ b/chromeos/ash/services/nearby/public/mojom/quick_start_decoder_types.mojom
@@ -9,6 +9,43 @@ string cryptauth_device_id; }; +enum WifiSecurityType { + kPSK = 0, + kWEP = 1, + kEAP = 2, + kOpen = 3, + kOWE = 4, + kSAE = 5, +}; + +enum GetWifiCredentialsFailureReason { + kFailedToDecodeMessage = 1, + kMissingWifiInformation = 2, + kMissingWifiSSID = 3, + kMissingWifiPassword = 4, + kMissingWifiSecurityType = 5, + kMissingWifiHiddenStatus = 6, + kInvalidWifiSecurityType = 7, + kEmptyWifiSSID = 8, +}; + +struct WifiCredentials { + string ssid; + WifiSecurityType security_type; + bool is_hidden; + string password; +}; + +union GetWifiCredentialsResponse { + + // Success - return credentials + WifiCredentials credentials; + + // Failure - return error reason + GetWifiCredentialsFailureReason failure_reason; + +}; + struct GetAssertionResponse { enum GetAssertionStatus { kSuccess = 0,
diff --git a/chromeos/ash/services/quick_pair/fast_pair_data_parser.cc b/chromeos/ash/services/quick_pair/fast_pair_data_parser.cc index 3129d7a..af30138 100644 --- a/chromeos/ash/services/quick_pair/fast_pair_data_parser.cc +++ b/chromeos/ash/services/quick_pair/fast_pair_data_parser.cc
@@ -320,11 +320,6 @@ remaining_bytes.pop_front(); absl::optional<mojom::MessageGroup> message_group = MessageGroupFromByte(message_group_byte); - if (!message_group.has_value()) { - QP_LOG(WARNING) << __func__ << ": Unknown message group. Received 0x" - << std::hex << message_group_byte << "."; - break; - } uint8_t message_code = remaining_bytes.front(); remaining_bytes.pop_front(); @@ -350,6 +345,15 @@ remaining_bytes.pop_front(); } + // If we have an unknown message group, do not process the Message Stream + // message. The data was already removed above corresponding to this + // message, and we can continue to attempt to parse the next message. + if (!message_group.has_value()) { + QP_LOG(WARNING) << __func__ << ": Unknown message group. Received 0x" + << std::hex << message_group_byte << "."; + continue; + } + mojom::MessageStreamMessagePtr message = ParseMessageStreamMessage( message_group.value(), message_code, base::span<uint8_t>(additional_data.begin(), additional_data.end())); @@ -364,6 +368,7 @@ << " remaining bytes not parsed."; } + // TODO(jackshira): Handle partial message data by returning the amount read. std::move(callback).Run(std::move(parsed_messages)); }
diff --git a/chromeos/ash/services/quick_pair/fast_pair_data_parser_unittest.cc b/chromeos/ash/services/quick_pair/fast_pair_data_parser_unittest.cc index 9a63fa4..8465139a 100644 --- a/chromeos/ash/services/quick_pair/fast_pair_data_parser_unittest.cc +++ b/chromeos/ash/services/quick_pair/fast_pair_data_parser_unittest.cc
@@ -590,7 +590,10 @@ } TEST_F(FastPairDataParserTest, ParseMessageStreamMessage_EnableSilenceMode) { - std::vector<uint8_t> bytes = {/*mesage_group=*/0x01, /*mesage_code=*/0x01, + std::vector<uint8_t> bytes = {// Bluetooth event + /*mesage_group=*/0x01, + // Enable silence mode + /*mesage_code=*/0x01, /*additional_data_length=*/0x00, 0x00}; base::RunLoop run_loop; auto callback = base::BindLambdaForTesting( @@ -607,7 +610,11 @@ TEST_F(FastPairDataParserTest, ParseMessageStreamMessage_SilenceMode_AdditionalData) { - std::vector<uint8_t> bytes = {/*mesage_group=*/0x01, /*mesage_code=*/0x01, + std::vector<uint8_t> bytes = {// Bluetooth event + /*mesage_group=*/0x01, + // Enable silence mode + /*mesage_code=*/0x01, + // Invalid additional data /*additional_data_length=*/0x00, 0x01, /*additional_data=*/0x08}; base::RunLoop run_loop; @@ -622,7 +629,10 @@ } TEST_F(FastPairDataParserTest, ParseMessageStreamMessage_DisableSilenceMode) { - std::vector<uint8_t> bytes = {/*mesage_group=*/0x01, /*mesage_code=*/0x02, + std::vector<uint8_t> bytes = {// Bluetooth event + /*mesage_group=*/0x01, + // Disable silence mode + /*mesage_code=*/0x02, /*additional_data_length=*/0x00, 0x00}; base::RunLoop run_loop; auto callback = base::BindLambdaForTesting( @@ -639,7 +649,10 @@ TEST_F(FastPairDataParserTest, ParseMessageStreamMessage_BluetoothInvalidMessageCode) { - std::vector<uint8_t> bytes = {/*mesage_group=*/0x01, /*mesage_code=*/0x03, + std::vector<uint8_t> bytes = {// Bluetooth event + /*mesage_group=*/0x01, + // Unknown message code + /*mesage_code=*/0x03, /*additional_data_length=*/0x00, 0x00}; base::RunLoop run_loop; auto callback = base::BindLambdaForTesting( @@ -654,7 +667,10 @@ TEST_F(FastPairDataParserTest, ParseMessageStreamMessage_CompanionAppLogBufferFull) { - std::vector<uint8_t> bytes = {/*mesage_group=*/0x02, /*mesage_code=*/0x01, + std::vector<uint8_t> bytes = {// Companion app event + /*mesage_group=*/0x02, + // Log buffer full + /*mesage_code=*/0x01, /*additional_data_length=*/0x00, 0x00}; base::RunLoop run_loop; auto callback = base::BindLambdaForTesting( @@ -671,7 +687,10 @@ TEST_F(FastPairDataParserTest, ParseMessageStreamMessage_CompanionAppInvalidMessageCode) { - std::vector<uint8_t> bytes = {/*mesage_group=*/0x02, /*mesage_code=*/0x02, + std::vector<uint8_t> bytes = {// Companion app event + /*mesage_group=*/0x02, + // Unknown message code + /*mesage_code=*/0x02, /*additional_data_length=*/0x00, 0x00}; base::RunLoop run_loop; auto callback = base::BindLambdaForTesting( @@ -686,7 +705,11 @@ TEST_F(FastPairDataParserTest, ParseMessageStreamMessage_CompanionAppLogBufferFull_AdditionalData) { - std::vector<uint8_t> bytes = {/*mesage_group=*/0x02, /*mesage_code=*/0x01, + std::vector<uint8_t> bytes = {// Companion App event + /*mesage_group=*/0x02, + // Log buffer full + /*mesage_code=*/0x01, + // Invalid additional data /*additional_data_length=*/0x00, 0x01, /*additional_data=*/0x08}; base::RunLoop run_loop; @@ -701,13 +724,13 @@ } TEST_F(FastPairDataParserTest, ParseMessageStreamMessage_ModelId) { - std::vector<uint8_t> bytes = {/*mesage_group=*/0x03, + std::vector<uint8_t> bytes = {// Device information + /*mesage_group=*/0x03, + // Model ID /*mesage_code=*/0x01, - /*additional_data_length=*/0x00, - 0x03, - /*additional_data=*/0xAA, - 0xBB, - 0xCC}; + /*additional_data_length=*/0x00, 0x03, + // Model ID value + /*additional_data=*/0xAA, 0xBB, 0xCC}; base::RunLoop run_loop; auto callback = base::BindLambdaForTesting( [&run_loop](std::vector<mojom::MessageStreamMessagePtr> messages) { @@ -722,16 +745,14 @@ } TEST_F(FastPairDataParserTest, ParseMessageStreamMessage_BleAddress) { - std::vector<uint8_t> bytes = {/*mesage_group=*/0x03, + std::vector<uint8_t> bytes = {// Device information + /*mesage_group=*/0x03, + // BLE address updated /*mesage_code=*/0x02, - /*additional_data_length=*/0x00, - 0x06, - /*additional_data=*/0xAA, - 0xBB, - 0xCC, - 0xDD, - 0xEE, - 0xFF}; + /*additional_data_length=*/0x00, 0x06, + // BLE Address value + /*additional_data=*/0xAA, 0xBB, 0xCC, 0xDD, + 0xEE, 0xFF}; base::RunLoop run_loop; auto callback = base::BindLambdaForTesting( [&run_loop](std::vector<mojom::MessageStreamMessagePtr> messages) { @@ -747,16 +768,14 @@ TEST_F(FastPairDataParserTest, ParseMessageStreamMessage_WrongAdditionalDataSize) { - std::vector<uint8_t> bytes = {/*mesage_group=*/0x03, + std::vector<uint8_t> bytes = {// Device information + /*mesage_group=*/0x03, + // BLE address updated /*mesage_code=*/0x02, - /*additional_data_length=*/0x00, - 0x08, - /*additional_data=*/0xAA, - 0xBB, - 0xCC, - 0xDD, - 0xEE, - 0xFF}; + /*additional_data_length=*/0x00, 0x08, + // BLE address values are only 6 bytes + /*additional_data=*/0xAA, 0xBB, 0xCC, 0xDD, + 0xEE, 0xFF}; base::RunLoop run_loop; auto callback = base::BindLambdaForTesting( [&run_loop](std::vector<mojom::MessageStreamMessagePtr> messages) { @@ -769,13 +788,13 @@ } TEST_F(FastPairDataParserTest, ParseMessageStreamMessage_BatteryNotification) { - std::vector<uint8_t> bytes = {/*mesage_group=*/0x03, + std::vector<uint8_t> bytes = {// Device information + /*mesage_group=*/0x03, + // Battery updated /*mesage_code=*/0x03, - /*additional_data_length=*/0x00, - 0x03, - /*additional_data=*/0x57, - 0x41, - 0x7F}; + /*additional_data_length=*/0x00, 0x03, + // Right, Left, Case values + /*additional_data=*/0x57, 0x41, 0x7F}; base::RunLoop run_loop; auto callback = base::BindLambdaForTesting( [&run_loop](std::vector<mojom::MessageStreamMessagePtr> messages) { @@ -794,8 +813,12 @@ } TEST_F(FastPairDataParserTest, ParseMessageStreamMessage_RemainingBatteryTime) { - std::vector<uint8_t> bytes = {/*mesage_group=*/0x03, /*mesage_code=*/0x04, + std::vector<uint8_t> bytes = {// Device information + /*mesage_group=*/0x03, + // Remaining battery time + /*mesage_code=*/0x04, /*additional_data_length=*/0x00, 0x01, + // Remaining battery time value /*additional_data=*/0xF0}; base::RunLoop run_loop; auto callback = base::BindLambdaForTesting( @@ -812,10 +835,13 @@ TEST_F(FastPairDataParserTest, ParseMessageStreamMessage_RemainingBatteryTime_2BytesAdditionalData) { - std::vector<uint8_t> bytes = { - /*mesage_group=*/0x03, /*mesage_code=*/0x04, - /*additional_data_length=*/0x00, 0x02, - /*additional_data=*/0x01, 0x0F}; + std::vector<uint8_t> bytes = {// Device information + /*mesage_group=*/0x03, + // Remaining battery time + /*mesage_code=*/0x04, + /*additional_data_length=*/0x00, 0x02, + // Support for uint16 + /*additional_data=*/0x01, 0x0F}; base::RunLoop run_loop; auto callback = base::BindLambdaForTesting( [&run_loop](std::vector<mojom::MessageStreamMessagePtr> messages) { @@ -831,7 +857,10 @@ TEST_F(FastPairDataParserTest, ParseMessageStreamMessage_DeviceInfoInvalidMessageCode) { - std::vector<uint8_t> bytes = {/*mesage_group=*/0x03, /*mesage_code=*/0x09, + std::vector<uint8_t> bytes = {// Device information + /*mesage_group=*/0x03, + // Unknown message code + /*mesage_code=*/0x09, /*additional_data_length=*/0x00, 0x00}; base::RunLoop run_loop; auto callback = base::BindLambdaForTesting( @@ -845,7 +874,11 @@ } TEST_F(FastPairDataParserTest, ParseMessageStreamMessage_ModelIdInvalidLength) { - std::vector<uint8_t> bytes = {/*mesage_group=*/0x03, /*mesage_code=*/0x01, + std::vector<uint8_t> bytes = {// Device information + /*mesage_group=*/0x03, + // Model ID + /*mesage_code=*/0x01, + // Expected 3 bytes /*additional_data_length=*/0x00, 0x00}; base::RunLoop run_loop; auto callback = base::BindLambdaForTesting( @@ -860,7 +893,11 @@ TEST_F(FastPairDataParserTest, ParseMessageStreamMessage_BleAddressUpdateInvalidLength) { - std::vector<uint8_t> bytes = {/*mesage_group=*/0x03, /*mesage_code=*/0x02, + std::vector<uint8_t> bytes = {// Device information + /*mesage_group=*/0x03, + // BLE address update + /*mesage_code=*/0x02, + // Expected 6 bytes /*additional_data_length=*/0x00, 0x00}; base::RunLoop run_loop; auto callback = base::BindLambdaForTesting( @@ -875,7 +912,11 @@ TEST_F(FastPairDataParserTest, ParseMessageStreamMessage_BatteryUpdateInvalidLength) { - std::vector<uint8_t> bytes = {/*mesage_group=*/0x03, /*mesage_code=*/0x03, + std::vector<uint8_t> bytes = {// Device information + /*mesage_group=*/0x03, + // Battery update + /*mesage_code=*/0x03, + // Expected 3 bytes /*additional_data_length=*/0x00, 0x00}; base::RunLoop run_loop; auto callback = base::BindLambdaForTesting( @@ -890,7 +931,11 @@ TEST_F(FastPairDataParserTest, ParseMessageStreamMessage_RemainingBatteryInvalidLength) { - std::vector<uint8_t> bytes = {/*mesage_group=*/0x03, /*mesage_code=*/0x04, + std::vector<uint8_t> bytes = {// Device information + /*mesage_group=*/0x03, + // Remaining battery + /*mesage_code=*/0x04, + // Expected 1 or 2 bytes /*additional_data_length=*/0x00, 0x00}; base::RunLoop run_loop; auto callback = base::BindLambdaForTesting( @@ -905,7 +950,10 @@ TEST_F(FastPairDataParserTest, ParseMessageStreamMessage_ActiveComponentsInvalidLength) { - std::vector<uint8_t> bytes = {/*mesage_group=*/0x03, /*mesage_code=*/0x06, + std::vector<uint8_t> bytes = {// Device information + /*mesage_group=*/0x03, + // Active components response + /*mesage_code=*/0x06, /*additional_data_length=*/0x00, 0x00}; base::RunLoop run_loop; auto callback = base::BindLambdaForTesting( @@ -919,7 +967,10 @@ } TEST_F(FastPairDataParserTest, ParseMessageStreamMessage_ActiveComponents) { - std::vector<uint8_t> bytes = {/*mesage_group=*/0x03, /*mesage_code=*/0x06, + std::vector<uint8_t> bytes = {// Device information + /*mesage_group=*/0x03, + // Active components response + /*mesage_code=*/0x06, /*additional_data_length=*/0x00, 0x01, /*additional_data=*/0x03}; base::RunLoop run_loop; @@ -936,12 +987,12 @@ } TEST_F(FastPairDataParserTest, ParseMessageStreamMessage_AndroidPlatform) { - std::vector<uint8_t> bytes = {/*mesage_group=*/0x03, + std::vector<uint8_t> bytes = {// Device information + /*mesage_group=*/0x03, + // Platform /*mesage_code=*/0x08, - /*additional_data_length=*/0x00, - 0x02, - /*additional_data=*/0x01, - 0x1C}; + /*additional_data_length=*/0x00, 0x02, + /*additional_data=*/0x01, 0x1C}; base::RunLoop run_loop; auto callback = base::BindLambdaForTesting( [&run_loop](std::vector<mojom::MessageStreamMessagePtr> messages) { @@ -957,7 +1008,10 @@ TEST_F(FastPairDataParserTest, ParseMessageStreamMessage_PlatformInvalidLength) { - std::vector<uint8_t> bytes = {/*mesage_group=*/0x03, /*mesage_code=*/0x08, + std::vector<uint8_t> bytes = {// Device information + /*mesage_group=*/0x03, + // Platform type + /*mesage_code=*/0x08, /*additional_data_length=*/0x00, 0x00}; base::RunLoop run_loop; auto callback = base::BindLambdaForTesting( @@ -971,12 +1025,13 @@ } TEST_F(FastPairDataParserTest, ParseMessageStreamMessage_InvalidPlatform) { - std::vector<uint8_t> bytes = {/*mesage_group=*/0x03, + std::vector<uint8_t> bytes = {// Device information + /*mesage_group=*/0x03, + // Platform type /*mesage_code=*/0x08, - /*additional_data_length=*/0x00, - 0x02, - /*additional_data=*/0x02, - 0x1C}; + /*additional_data_length=*/0x00, 0x02, + // Only supports Android of type `0x01` + /*additional_data=*/0x02, 0x1C}; base::RunLoop run_loop; auto callback = base::BindLambdaForTesting( [&run_loop](std::vector<mojom::MessageStreamMessagePtr> messages) { @@ -989,7 +1044,10 @@ } TEST_F(FastPairDataParserTest, ParseMessageStreamMessage_RingDeviceNoTimeout) { - std::vector<uint8_t> bytes = {/*mesage_group=*/0x04, /*mesage_code=*/0x01, + std::vector<uint8_t> bytes = {// Device action + /*mesage_group=*/0x04, + // Ring + /*mesage_code=*/0x01, /*additional_data_length=*/0x00, 0x01, /*additional_data=*/0x01}; base::RunLoop run_loop; @@ -1007,12 +1065,12 @@ } TEST_F(FastPairDataParserTest, ParseMessageStreamMessage_RingDeviceTimeout) { - std::vector<uint8_t> bytes = {/*mesage_group=*/0x04, + std::vector<uint8_t> bytes = {// Device action + /*mesage_group=*/0x04, + // Ring /*mesage_code=*/0x01, - /*additional_data_length=*/0x00, - 0x02, - /*additional_data=*/0x01, - 0x3C}; + /*additional_data_length=*/0x00, 0x02, + /*additional_data=*/0x01, 0x3C}; base::RunLoop run_loop; auto callback = base::BindLambdaForTesting( [&run_loop](std::vector<mojom::MessageStreamMessagePtr> messages) { @@ -1028,13 +1086,12 @@ } TEST_F(FastPairDataParserTest, ParseMessageStreamMessage_RingInvalidLength) { - std::vector<uint8_t> bytes = {/*mesage_group=*/0x04, + std::vector<uint8_t> bytes = {// Device action + /*mesage_group=*/0x04, + // Ring /*mesage_code=*/0x01, - /*additional_data_length=*/0x00, - 0x03, - /*additional_data=*/0x02, - 0x1C, - 0x02}; + /*additional_data_length=*/0x00, 0x03, + /*additional_data=*/0x02, 0x1C, 0x02}; base::RunLoop run_loop; auto callback = base::BindLambdaForTesting( [&run_loop](std::vector<mojom::MessageStreamMessagePtr> messages) { @@ -1048,12 +1105,12 @@ TEST_F(FastPairDataParserTest, ParseMessageStreamMessage_RingInvalidMessageCode) { - std::vector<uint8_t> bytes = {/*mesage_group=*/0x04, + std::vector<uint8_t> bytes = {// Device action + /*mesage_group=*/0x04, + // Unknown message code /*mesage_code=*/0x02, - /*additional_data_length=*/0x00, - 0x02, - /*additional_data=*/0x02, - 0x1C}; + /*additional_data_length=*/0x00, 0x02, + /*additional_data=*/0x02, 0x1C}; base::RunLoop run_loop; auto callback = base::BindLambdaForTesting( [&run_loop](std::vector<mojom::MessageStreamMessagePtr> messages) { @@ -1066,12 +1123,12 @@ } TEST_F(FastPairDataParserTest, ParseMessageStreamMessage_Ack) { - std::vector<uint8_t> bytes = {/*mesage_group=*/0xFF, + std::vector<uint8_t> bytes = {// Acknowledgements + /*mesage_group=*/0xFF, + // ACK /*mesage_code=*/0x01, - /*additional_data_length=*/0x00, - 0x02, - /*additional_data=*/0x04, - 0x01}; + /*additional_data_length=*/0x00, 0x02, + /*additional_data=*/0x04, 0x01}; base::RunLoop run_loop; auto callback = base::BindLambdaForTesting( [&run_loop](std::vector<mojom::MessageStreamMessagePtr> messages) { @@ -1091,13 +1148,12 @@ } TEST_F(FastPairDataParserTest, ParseMessageStreamMessage_Nak) { - std::vector<uint8_t> bytes = {/*mesage_group=*/0xFF, + std::vector<uint8_t> bytes = {// Acknowledgements + /*mesage_group=*/0xFF, + // NAK /*mesage_code=*/0x02, - /*additional_data_length=*/0x00, - 0x03, - /*additional_data=*/0x00, - 0x04, - 0x01}; + /*additional_data_length=*/0x00, 0x03, + /*additional_data=*/0x00, 0x04, 0x01}; base::RunLoop run_loop; auto callback = base::BindLambdaForTesting( [&run_loop](std::vector<mojom::MessageStreamMessagePtr> messages) { @@ -1118,12 +1174,12 @@ TEST_F(FastPairDataParserTest, ParseMessageStreamMessage_AckInvalidMessageCode) { - std::vector<uint8_t> bytes = {/*mesage_group=*/0xFF, + std::vector<uint8_t> bytes = {// Acknowledgements + /*mesage_group=*/0xFF, + // Unknown message code /*mesage_code=*/0x03, - /*additional_data_length=*/0x00, - 0x02, - /*additional_data=*/0x04, - 0x01}; + /*additional_data_length=*/0x00, 0x02, + /*additional_data=*/0x04, 0x01}; base::RunLoop run_loop; auto callback = base::BindLambdaForTesting( [&run_loop](std::vector<mojom::MessageStreamMessagePtr> messages) { @@ -1136,13 +1192,14 @@ } TEST_F(FastPairDataParserTest, ParseMessageStreamMessage_AckInvalidLength) { - std::vector<uint8_t> bytes = {/*mesage_group=*/0xFF, + std::vector<uint8_t> bytes = {// Acknowledgements + /*mesage_group=*/0xFF, + // ACK /*mesage_code=*/0x01, - /*additional_data_length=*/0x00, - 0x03, - /*additional_data=*/0x04, - 0x01, - 0x01}; + // Expect size 4 for action message group and + // corresponding to the ACK + /*additional_data_length=*/0x00, 0x03, + /*additional_data=*/0x04, 0x01, 0x01}; base::RunLoop run_loop; auto callback = base::BindLambdaForTesting( [&run_loop](std::vector<mojom::MessageStreamMessagePtr> messages) { @@ -1155,12 +1212,12 @@ } TEST_F(FastPairDataParserTest, ParseMessageStreamMessage_NakInvalidLength) { - std::vector<uint8_t> bytes = {/*mesage_group=*/0xFF, + std::vector<uint8_t> bytes = {// Acknowledgements + /*mesage_group=*/0xFF, + // NACK /*mesage_code=*/0x02, - /*additional_data_length=*/0x00, - 0x02, - /*additional_data=*/0x00, - 0x04}; + /*additional_data_length=*/0x00, 0x02, + /*additional_data=*/0x00, 0x04}; base::RunLoop run_loop; auto callback = base::BindLambdaForTesting( [&run_loop](std::vector<mojom::MessageStreamMessagePtr> messages) { @@ -1187,17 +1244,19 @@ TEST_F(FastPairDataParserTest, ParseMessageStreamMessage_MultipleMessages_Valid) { - std::vector<uint8_t> bytes = {/*mesage_group=*/0x04, + std::vector<uint8_t> bytes = {// Device Action + /*mesage_group=*/0x04, + // Ring /*mesage_code=*/0x01, - /*additional_data_length=*/0x00, - 0x01, + /*additional_data_length=*/0x00, 0x01, /*additional_data=*/0x01, + + // Device Information /*mesage_group=*/0x03, + // Platform Type /*mesage_code=*/0x08, - /*additional_data_length=*/0x00, - 0x02, - /*additional_data=*/0x01, - 0x1C}; + /*additional_data_length=*/0x00, 0x02, + /*additional_data=*/0x01, 0x1C}; base::RunLoop run_loop; auto callback = base::BindLambdaForTesting( [&run_loop](std::vector<mojom::MessageStreamMessagePtr> messages) { @@ -1216,17 +1275,19 @@ TEST_F(FastPairDataParserTest, ParseMessageStreamMessage_MultipleMessages_ValidInvalid) { - std::vector<uint8_t> bytes = {/*mesage_group=*/0x04, + std::vector<uint8_t> bytes = {// Device Action + /*mesage_group=*/0x04, + // Ring /*mesage_code=*/0x01, - /*additional_data_length=*/0x00, - 0x01, + /*additional_data_length=*/0x00, 0x01, /*additional_data=*/0x01, + + // Device Information /*mesage_group=*/0x03, + // Platform Type /*mesage_code=*/0x08, - /*additional_data_length=*/0x00, - 0x02, - /*additional_data=*/0x02, - 0x1C}; + /*additional_data_length=*/0x00, 0x02, + /*additional_data=*/0x02, 0x1C}; base::RunLoop run_loop; auto callback = base::BindLambdaForTesting( [&run_loop](std::vector<mojom::MessageStreamMessagePtr> messages) { @@ -1243,16 +1304,18 @@ TEST_F(FastPairDataParserTest, ParseMessageStreamMessage_MultipleMessages_Invalid) { - std::vector<uint8_t> bytes = {/*mesage_group=*/0x04, + std::vector<uint8_t> bytes = {// Device Action + /*mesage_group=*/0x04, + // Ring /*mesage_code=*/0x01, - /*additional_data_length=*/0x00, - 0x00, + /*additional_data_length=*/0x00, 0x00, + + // Device Information /*mesage_group=*/0x03, + // Platform type /*mesage_code=*/0x08, - /*additional_data_length=*/0x00, - 0x02, - /*additional_data=*/0x02, - 0x1C}; + /*additional_data_length=*/0x00, 0x02, + /*additional_data=*/0x02, 0x1C}; base::RunLoop run_loop; auto callback = base::BindLambdaForTesting( [&run_loop](std::vector<mojom::MessageStreamMessagePtr> messages) { @@ -1264,5 +1327,73 @@ run_loop.Run(); } +// Regression test for b/274788634. +TEST_F(FastPairDataParserTest, + ParseMessageStreamMessage_InvalidMessageCodeFollowedByBatteryUpdate) { + std::vector<uint8_t> bytes = {// Device Information + /*mesage_group=*/0x03, + // Session Nonce + /*mesage_code=*/0x0A, + /*additional_data_length=*/0x00, 0x08, + /*additional_data=*/0x63, 0x19, 0xEC, 0x34, + 0x5F, 0xB3, 0xEF, 0x90, + + // Device Information + /*mesage_group=*/0x03, + // Battery Update + /*mesage_code=*/0x03, + /*additional_data_length=*/0x00, 0x03, + /*additional_data=*/0x57, 0x41, 0x7F}; + base::RunLoop run_loop; + auto callback = base::BindLambdaForTesting( + [&run_loop](std::vector<mojom::MessageStreamMessagePtr> messages) { + EXPECT_EQ(static_cast<int>(messages.size()), 1); + EXPECT_TRUE(messages[0]->is_battery_update()); + EXPECT_EQ(87, + messages[0]->get_battery_update()->left_bud_info->percentage); + EXPECT_EQ( + 65, messages[0]->get_battery_update()->right_bud_info->percentage); + EXPECT_EQ(-1, messages[0]->get_battery_update()->case_info->percentage); + run_loop.Quit(); + }); + + data_parser_->ParseMessageStreamMessages(bytes, std::move(callback)); + run_loop.Run(); +} + +// Regression test for b/274788634. +TEST_F(FastPairDataParserTest, + ParseMessageStreamMessage_InvalidMessageGroupFollowedByBatteryUpdate) { + std::vector<uint8_t> bytes = {// SASS + /*mesage_group=*/0x07, + // Connection Status + /*mesage_code=*/0x34, + /*additional_data_length=*/0x00, 0x0C, + /*additional_data=*/0x4E, 0x61, 0xD9, 0x5B, + 0x50, 0x57, 0x9C, 0x69, 0x3E, 0x6B, 0x6C, 0x74, + + // Device Information + /*mesage_group=*/0x03, + // Battery Update + /*mesage_code=*/0x03, + /*additional_data_length=*/0x00, 0x03, + /*additional_data=*/0x57, 0x41, 0x7F}; + base::RunLoop run_loop; + auto callback = base::BindLambdaForTesting( + [&run_loop](std::vector<mojom::MessageStreamMessagePtr> messages) { + EXPECT_EQ(static_cast<int>(messages.size()), 1); + EXPECT_TRUE(messages[0]->is_battery_update()); + EXPECT_EQ(87, + messages[0]->get_battery_update()->left_bud_info->percentage); + EXPECT_EQ( + 65, messages[0]->get_battery_update()->right_bud_info->percentage); + EXPECT_EQ(-1, messages[0]->get_battery_update()->case_info->percentage); + run_loop.Quit(); + }); + + data_parser_->ParseMessageStreamMessages(bytes, std::move(callback)); + run_loop.Run(); +} + } // namespace quick_pair } // namespace ash
diff --git a/chromeos/chromeos_strings.grd b/chromeos/chromeos_strings.grd index 64d646f..9f98690 100644 --- a/chromeos/chromeos_strings.grd +++ b/chromeos/chromeos_strings.grd
@@ -3205,6 +3205,10 @@ <message name="IDS_SHIMLESS_RMA_LID_CALIBRATION_INSTRUCTIONS" translateable="false" desc="Instructions for calibrating gyroscope and accelerometer located in the lid of the device."> Before proceeding, place your whole device (base and lid) on a flat surface. </message> + <!-- Nearby Presence --> + <message name="IDS_NEARBY_PRESENCE_DEVICE_NAME" is_accessibility_with_no_ui="true" desc="The device name used to advertise the user's device during a feature flow. Displayed to other devices."> + <ph name="GIVEN_NAME">$1<ex>Josh</ex></ph>'s <ph name="DEVICE_TYPE">$2<ex>Chromebook</ex></ph> + </message> <!-- Finalize device page --> <message name="IDS_SHIMLESS_RMA_FINALIZE_PAGE_TITLE" translateable="false" desc="Title for the page shown when finalizing the device. Finalizing is the process of confirming the device is ready to return to the owner."> Finalizing repair
diff --git a/chromeos/crosapi/mojom/crosapi.mojom b/chromeos/crosapi/mojom/crosapi.mojom index 7a07e8d4..80f87a2 100644 --- a/chromeos/crosapi/mojom/crosapi.mojom +++ b/chromeos/crosapi/mojom/crosapi.mojom
@@ -951,8 +951,8 @@ // parameters here. If a new parameter is added and its value is only known // after the user has logged in, please update BrowserPostLoginParams as well. // -// Next version: 57 -// Next id: 57 +// Next version: 59 +// Next id: 59 [Stable, RenamedFrom="crosapi.mojom.LacrosInitParams"] struct BrowserInitParams { // This is ash-chrome's version of the Crosapi interface. This is used by @@ -1314,6 +1314,16 @@ [MinVersion=57] StandaloneBrowserAppServiceBlockList? standalone_browser_app_service_blocklist@57; + + // When this flag is set to true, CPU-mappable native GpuMemoryBuffers are + // enabled. + // + // TODO(b/278097642): improve this documentation. I think this only refers to + // the ability of renderer processes to obtain such buffers because as far as + // I know, the GPU process can allocate CPU-mappable native GpuMemoryBuffers + // regardless of this flag. + [MinVersion=58] + bool enable_cpu_mappable_native_gpu_memory_buffers@58; }; // BrowserPostLoginParams is the subset of parameters in BrowserInitParams
diff --git a/chromeos/startup/browser_params_proxy.cc b/chromeos/startup/browser_params_proxy.cc index 0331cb6..6d3e9237 100644 --- a/chromeos/startup/browser_params_proxy.cc +++ b/chromeos/startup/browser_params_proxy.cc
@@ -285,4 +285,9 @@ ->standalone_browser_app_service_blocklist.get(); } +bool BrowserParamsProxy::EnableCpuMappableNativeGpuMemoryBuffers() const { + return BrowserInitParams::Get() + ->enable_cpu_mappable_native_gpu_memory_buffers; +} + } // namespace chromeos
diff --git a/chromeos/startup/browser_params_proxy.h b/chromeos/startup/browser_params_proxy.h index 547b146..a703ccf5 100644 --- a/chromeos/startup/browser_params_proxy.h +++ b/chromeos/startup/browser_params_proxy.h
@@ -128,6 +128,8 @@ const crosapi::mojom::StandaloneBrowserAppServiceBlockList* StandaloneBrowserAppServiceBlockList() const; + bool EnableCpuMappableNativeGpuMemoryBuffers() const; + private: friend base::NoDestructor<BrowserParamsProxy>;
diff --git a/components/autofill/core/browser/autofill_test_utils.cc b/components/autofill/core/browser/autofill_test_utils.cc index c9ca8de..f2abfae 100644 --- a/components/autofill/core/browser/autofill_test_utils.cc +++ b/components/autofill/core/browser/autofill_test_utils.cc
@@ -852,6 +852,12 @@ /*challenge_input_length=*/3U, /*cvc_position=*/CvcPosition::kBackOfCard)); break; + case CardUnmaskChallengeOptionType::kEmailOtp: + challenge_options.emplace_back( + CardUnmaskChallengeOption::ChallengeOptionId("345"), type, + /*challenge_info=*/u"a******b@google.com", + /*challenge_input_length=*/6U); + break; default: NOTREACHED(); break;
diff --git a/components/autofill/core/browser/payments/credit_card_access_manager.cc b/components/autofill/core/browser/payments/credit_card_access_manager.cc index e0b8cd25..356d7d1 100644 --- a/components/autofill/core/browser/payments/credit_card_access_manager.cc +++ b/components/autofill/core/browser/payments/credit_card_access_manager.cc
@@ -1250,12 +1250,12 @@ selected_authentication_type = UnmaskAuthFlowType::kCvc; break; case CardUnmaskChallengeOptionType::kSmsOtp: + case CardUnmaskChallengeOptionType::kEmailOtp: selected_authentication_type = unmask_auth_flow_type_ == UnmaskAuthFlowType::kFido ? UnmaskAuthFlowType::kOtpFallbackFromFido : UnmaskAuthFlowType::kOtp; break; - case CardUnmaskChallengeOptionType::kEmailOtp: case CardUnmaskChallengeOptionType::kUnknownType: NOTREACHED(); break;
diff --git a/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc b/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc index c52e48a..ffc7d07 100644 --- a/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc +++ b/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc
@@ -516,13 +516,7 @@ break; } case CardUnmaskChallengeOptionType::kSmsOtp: - DCHECK(otp_authenticator_); - EXPECT_TRUE(otp_authenticator_->on_challenge_option_selected_invoked()); - EXPECT_EQ(otp_authenticator_->card().number(), - base::UTF8ToUTF16(std::string(kTestNumber))); - EXPECT_EQ(otp_authenticator_->card().record_type(), - CreditCard::VIRTUAL_CARD); - EXPECT_EQ(otp_authenticator_->context_token(), "fake_context_token"); + VerifyOnSelectChallengeOptionInvoked(); EXPECT_EQ(otp_authenticator_->selected_challenge_option().id.value(), "123"); EXPECT_EQ(otp_authenticator_->selected_challenge_option().type, @@ -532,12 +526,31 @@ u"xxx-xxx-3547"); break; case CardUnmaskChallengeOptionType::kEmailOtp: + VerifyOnSelectChallengeOptionInvoked(); + EXPECT_EQ(otp_authenticator_->selected_challenge_option().id.value(), + "345"); + EXPECT_EQ(otp_authenticator_->selected_challenge_option().type, + CardUnmaskChallengeOptionType::kEmailOtp); + EXPECT_EQ( + otp_authenticator_->selected_challenge_option().challenge_info, + u"a******b@google.com"); + break; case CardUnmaskChallengeOptionType::kUnknownType: NOTREACHED(); break; } } + void VerifyOnSelectChallengeOptionInvoked() { + DCHECK(otp_authenticator_); + EXPECT_TRUE(otp_authenticator_->on_challenge_option_selected_invoked()); + EXPECT_EQ(otp_authenticator_->card().number(), + base::UTF8ToUTF16(std::string(kTestNumber))); + EXPECT_EQ(otp_authenticator_->card().record_type(), + CreditCard::VIRTUAL_CARD); + EXPECT_EQ(otp_authenticator_->context_token(), "fake_context_token"); + } + protected: TestPersonalDataManager& personal_data() { return *autofill_client_.GetPersonalDataManager(); @@ -2483,7 +2496,8 @@ base::HistogramTester histogram_tester; std::vector<CardUnmaskChallengeOption> challenge_options = test::GetCardUnmaskChallengeOptions( - {CardUnmaskChallengeOptionType::kSmsOtp}); + {CardUnmaskChallengeOptionType::kSmsOtp, + CardUnmaskChallengeOptionType::kEmailOtp}); MockCardUnmaskFlowUpToAuthenticationSelectionDialogAccepted( /*fido_authenticator_is_user_opted_in=*/false, /*is_user_verifiable=*/false, challenge_options, /*selected_index=*/0);
diff --git a/components/autofill/core/browser/payments/payments_requests/select_challenge_option_request.cc b/components/autofill/core/browser/payments/payments_requests/select_challenge_option_request.cc index 158d8ad..9e68cc03 100644 --- a/components/autofill/core/browser/payments/payments_requests/select_challenge_option_request.cc +++ b/components/autofill/core/browser/payments/payments_requests/select_challenge_option_request.cc
@@ -62,6 +62,18 @@ selected_idv_method.Set("sms_otp_challenge_option", std::move(sms_challenge_option)); } + if (request_details_.selected_challenge_option.type == + CardUnmaskChallengeOptionType::kEmailOtp) { + base::Value::Dict email_challenge_option; + // We only get and set the challenge id. + if (!request_details_.selected_challenge_option.id.value().empty()) { + email_challenge_option.Set( + "challenge_id", + request_details_.selected_challenge_option.id.value()); + } + selected_idv_method.Set("email_otp_challenge_option", + std::move(email_challenge_option)); + } request_dict.Set("selected_idv_challenge_option", std::move(selected_idv_method));
diff --git a/components/autofill_payments_strings.grdp b/components/autofill_payments_strings.grdp index 25255f83..ccbf6233 100644 --- a/components/autofill_payments_strings.grdp +++ b/components/autofill_payments_strings.grdp
@@ -708,6 +708,9 @@ <message name="IDS_AUTOFILL_AUTHENTICATION_MODE_TEXT_MESSAGE" desc="The label for the text message authentication mode text shown in the Autofill card unmask authentication selection dialog on Desktop. This dialog lets the user choose the method of authentication when unmasking a server card, including a virtual card."> Text message </message> + <message name="IDS_AUTOFILL_AUTHENTICATION_MODE_GET_EMAIL" desc="The label for the email authentication mode option shown in the Autofill card unmask authentication selection dialog on Desktop. If selected, we will display a new dialog where the user will be prompted to enter the OTP from the email message they received."> + Get an email + </message> <message name="IDS_AUTOFILL_CARD_UNMASK_AUTHENTICATION_SELECTION_DIALOG_CURRENT_INFO_NOT_SEEN_TEXT" desc="The current info not seen text shown in the Autofill card unmask authentication selection dialog on Desktop. It is the footer text on the dialog, and it instructs the user on what to do if they can not see their most up to date authentication information. This dialog lets the user choose the method of authentication when unmasking a server card, including a virtual card."> Not seeing your current info? Contact your bank to update it. </message>
diff --git a/components/autofill_payments_strings_grdp/IDS_AUTOFILL_AUTHENTICATION_MODE_GET_EMAIL.png.sha1 b/components/autofill_payments_strings_grdp/IDS_AUTOFILL_AUTHENTICATION_MODE_GET_EMAIL.png.sha1 new file mode 100644 index 0000000..7789702 --- /dev/null +++ b/components/autofill_payments_strings_grdp/IDS_AUTOFILL_AUTHENTICATION_MODE_GET_EMAIL.png.sha1
@@ -0,0 +1 @@ +80fda7cd77922da0020eeb60b2b568c4820efda7 \ No newline at end of file
diff --git a/components/download/internal/common/download_item_impl.cc b/components/download/internal/common/download_item_impl.cc index 6df35f4..ec71649 100644 --- a/components/download/internal/common/download_item_impl.cc +++ b/components/download/internal/common/download_item_impl.cc
@@ -617,7 +617,6 @@ void DownloadItemImpl::Resume(bool user_resume) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DVLOG(20) << __func__ << "() download = " << DebugString(true); - RecordDownloadResumption(GetLastReason(), user_resume); switch (state_) { case CANCELLED_INTERNAL: // Nothing to resume. @@ -644,7 +643,6 @@ UpdateResumptionInfo(paused_ || user_resume); paused_ = false; if (auto_resume_count_ >= kMaxAutoResumeAttempts) { - RecordAutoResumeCountLimitReached(GetLastReason()); UpdateObservers(); return; } @@ -2465,9 +2463,6 @@ mode == ResumeMode::USER_RESTART) { LOG_IF(ERROR, !GetFullPath().empty()) << "Download full path should be empty before resumption"; - if (destination_info_.received_bytes > 0) { - RecordResumptionRestartReason(last_reason_); - } destination_info_.received_bytes = 0; last_modified_time_.clear(); etag_.clear();
diff --git a/components/download/internal/common/download_stats.cc b/components/download/internal/common/download_stats.cc index 0145790..1a79a81 100644 --- a/components/download/internal/common/download_stats.cc +++ b/components/download/internal/common/download_stats.cc
@@ -207,18 +207,8 @@ "Download.InterruptedReason.ParallelDownload", reason, samples); } - // The maximum should be 2^kBuckets, to have the logarithmic bucket - // boundaries fall on powers of 2. - static const int kBuckets = 30; - static const int64_t kMaxKb = 1 << kBuckets; // One Terabyte, in Kilobytes. int64_t delta_bytes = total - received; bool unknown_size = total <= 0; - int64_t received_kb = received / 1024; - if (is_parallel_download_enabled) { - UMA_HISTOGRAM_CUSTOM_COUNTS( - "Download.InterruptedReceivedSizeK.ParallelDownload", received_kb, 1, - kMaxKb, kBuckets); - } if (!unknown_size) { if (delta_bytes == 0) { @@ -231,15 +221,6 @@ } } -void RecordDownloadResumption(DownloadInterruptReason reason, - bool user_resume) { - std::vector<base::HistogramBase::Sample> samples = - base::CustomHistogram::ArrayToCustomEnumRanges(kAllInterruptReasonCodes); - UMA_HISTOGRAM_CUSTOM_ENUMERATION("Download.Resume.LastReason", reason, - samples); - base::UmaHistogramBoolean("Download.Resume.UserResume", user_resume); -} - void RecordDownloadRetry(DownloadInterruptReason reason) { std::vector<base::HistogramBase::Sample> samples = base::CustomHistogram::ArrayToCustomEnumRanges(kAllInterruptReasonCodes); @@ -247,15 +228,6 @@ samples); } -void RecordAutoResumeCountLimitReached(DownloadInterruptReason reason) { - base::UmaHistogramBoolean("Download.Resume.AutoResumeLimitReached", true); - - std::vector<base::HistogramBase::Sample> samples = - base::CustomHistogram::ArrayToCustomEnumRanges(kAllInterruptReasonCodes); - UMA_HISTOGRAM_CUSTOM_ENUMERATION( - "Download.Resume.AutoResumeLimitReached.LastReason", reason, samples); -} - void RecordDangerousDownloadAccept(DownloadDangerType danger_type, const base::FilePath& file_path) { UMA_HISTOGRAM_ENUMERATION("Download.UserValidatedDangerousDownload", @@ -574,11 +546,6 @@ DownloadContent::MAX); } -void RecordOpensOutstanding(int size) { - UMA_HISTOGRAM_CUSTOM_COUNTS("Download.OpensOutstanding", size, 1 /*min*/, - (1 << 10) /*max*/, 64 /*num_buckets*/); -} - void RecordFileBandwidth(size_t length, base::TimeDelta elapsed_time) { base::UmaHistogramCustomCounts( @@ -670,10 +637,6 @@ UMA_HISTOGRAM_ENUMERATION("Download.InProgressDB.Counts", type); } -void RecordResumptionRestartReason(DownloadInterruptReason reason) { - base::UmaHistogramSparse("Download.ResumptionRestart.Reason", reason); -} - void RecordDownloadLaterEvent(DownloadLaterEvent event) { base::UmaHistogramEnumeration("Download.Later.Events", event); } @@ -696,14 +659,6 @@ base::UmaHistogramEnumeration("Download.InputStreamReadError", error); } -#if BUILDFLAG(IS_ANDROID) -void RecordBackgroundTargetDeterminationResult( - BackgroudTargetDeterminationResultTypes type) { - base::UmaHistogramEnumeration( - "MobileDownload.Background.TargetDeterminationResult", type); -} -#endif // BUILDFLAG(IS_ANDROID) - #if BUILDFLAG(IS_WIN) void RecordWinFileMoveError(int os_error) { base::UmaHistogramSparse("Download.WinFileMoveError", os_error);
diff --git a/components/download/internal/common/in_progress_download_manager.cc b/components/download/internal/common/in_progress_download_manager.cc index 50af9015..d4c495e2 100644 --- a/components/download/internal/common/in_progress_download_manager.cc +++ b/components/download/internal/common/in_progress_download_manager.cc
@@ -177,10 +177,6 @@ } } - RecordBackgroundTargetDeterminationResult( - intermediate_path.empty() - ? BackgroudTargetDeterminationResultTypes::kPathReservationFailed - : BackgroudTargetDeterminationResultTypes::kSuccess); std::move(callback).Run( target_path, DownloadItem::TARGET_DISPOSITION_OVERWRITE, danger_type, insecure_download_status, intermediate_path, base::FilePath(), @@ -407,8 +403,6 @@ download->GetDangerType(), download->GetInsecureDownloadStatus(), target_path, base::FilePath(), std::string() /*mime_type*/, DOWNLOAD_INTERRUPT_REASON_FILE_FAILED); - RecordBackgroundTargetDeterminationResult( - BackgroudTargetDeterminationResultTypes::kTargetPathMissing); return; } @@ -420,8 +414,6 @@ download->GetDangerType(), download->GetInsecureDownloadStatus(), target_path, base::FilePath(), std::string() /*mime_type*/, DOWNLOAD_INTERRUPT_REASON_NONE); - RecordBackgroundTargetDeterminationResult( - BackgroudTargetDeterminationResultTypes::kSuccess); return; }
diff --git a/components/download/public/common/download_stats.h b/components/download/public/common/download_stats.h index d74924ce..73d1cda 100644 --- a/components/download/public/common/download_stats.h +++ b/components/download/public/common/download_stats.h
@@ -220,19 +220,10 @@ DownloadDangerType danger_type, const base::FilePath& file_path); -// Records various metrics at the start of a download resumption. -COMPONENTS_DOWNLOAD_EXPORT void RecordDownloadResumption( - DownloadInterruptReason reason, - bool user_resume); - // Records the interrupt reason when a download is retried. COMPONENTS_DOWNLOAD_EXPORT void RecordDownloadRetry( DownloadInterruptReason reason); -// Records whenever a download hits max auto-resumption limit. -COMPONENTS_DOWNLOAD_EXPORT void RecordAutoResumeCountLimitReached( - DownloadInterruptReason reason); - // Returns the type of download. COMPONENTS_DOWNLOAD_EXPORT DownloadContent DownloadContentFromMimeType(const std::string& mime_type_string, @@ -246,9 +237,6 @@ COMPONENTS_DOWNLOAD_EXPORT void RecordDownloadMimeTypeForNormalProfile( const std::string& mime_type); -// Record the number of completed unopened downloads when a download is opened. -COMPONENTS_DOWNLOAD_EXPORT void RecordOpensOutstanding(int size); - // Record overall bandwidth stats at the file end. // Does not count in any hash computation or file open/close time. COMPONENTS_DOWNLOAD_EXPORT void RecordFileBandwidth( @@ -366,10 +354,6 @@ InProgressDBCountTypes type); // Records the interrupt reason that causes download to restart. -COMPONENTS_DOWNLOAD_EXPORT void RecordResumptionRestartReason( - DownloadInterruptReason reason); - -// Records the interrupt reason that causes download to restart. COMPONENTS_DOWNLOAD_EXPORT void RecordResumptionStrongValidators( DownloadInterruptReason reason); @@ -398,10 +382,6 @@ kMaxValue = kPathReservationFailed }; -// Records whether download target determination is successfully completed in -// reduced mode. -COMPONENTS_DOWNLOAD_EXPORT void RecordBackgroundTargetDeterminationResult( - BackgroudTargetDeterminationResultTypes type); #endif // BUILDFLAG(IS_ANDROID) #if BUILDFLAG(IS_WIN)
diff --git a/components/exo/text_input.cc b/components/exo/text_input.cc index 9739931..97d3fd9 100644 --- a/components/exo/text_input.cc +++ b/components/exo/text_input.cc
@@ -132,7 +132,8 @@ void TextInput::SetSurroundingText(const std::u16string& text, const gfx::Range& cursor_pos) { - surrounding_text_tracker_.Update(text, cursor_pos); + // TODO(crbug.com/1402906): Text range is not currently handled correctly. + surrounding_text_tracker_.Update(text, 0u, cursor_pos); // Convert utf8 grammar fragment to utf16. if (grammar_fragment_at_cursor_utf8_) { @@ -231,7 +232,7 @@ } size_t TextInput::ConfirmCompositionText(bool keep_selection) { - const auto& [surrounding_text, cursor_pos, composition] = + const auto& [surrounding_text, utf16_offset, cursor_pos, composition] = surrounding_text_tracker_.predicted_state(); const size_t composition_text_length = composition.length(); @@ -333,7 +334,7 @@ bool TextInput::GetTextRange(gfx::Range* range) const { DCHECK(range); - const auto& [surrounding_text, selection, unused_composition] = + const auto& [surrounding_text, utf16_offset, selection, unused_composition] = surrounding_text_tracker_.predicted_state(); DCHECK(selection.IsValid()); @@ -362,7 +363,7 @@ } bool TextInput::SetEditableSelectionRange(const gfx::Range& range) { - const auto& [surrounding_text, unused_selection, composition] = + const auto& [surrounding_text, utf16_offset, unused_selection, composition] = surrounding_text_tracker_.predicted_state(); if (surrounding_text.length() < range.GetMax()) return false; @@ -405,7 +406,7 @@ } void TextInput::ExtendSelectionAndDelete(size_t before, size_t after) { - const auto& [surrounding_text, selection, unused_composition] = + const auto& [surrounding_text, utf16_offset, selection, unused_composition] = surrounding_text_tracker_.predicted_state(); DCHECK(selection.IsValid()); @@ -446,7 +447,7 @@ bool TextInput::SetCompositionFromExistingText( const gfx::Range& range, const std::vector<ui::ImeTextSpan>& ui_ime_text_spans) { - const auto& [surrounding_text, selection, unused_composition] = + const auto& [surrounding_text, utf16_offset, selection, unused_composition] = surrounding_text_tracker_.predicted_state(); DCHECK(selection.IsValid()); if (surrounding_text.length() < range.GetMax())
diff --git a/components/omnibox/browser/autocomplete_controller.cc b/components/omnibox/browser/autocomplete_controller.cc index aacd690..c3b1169 100644 --- a/components/omnibox/browser/autocomplete_controller.cc +++ b/components/omnibox/browser/autocomplete_controller.cc
@@ -69,6 +69,7 @@ #include "components/search_engines/template_url_starter_pack_data.h" #include "components/strings/grit/components_strings.h" #include "third_party/abseil-cpp/absl/types/optional.h" +#include "third_party/metrics_proto/omnibox_event.pb.h" #include "third_party/metrics_proto/omnibox_focus_type.pb.h" #include "third_party/omnibox_proto/chrome_searchbox_stats.pb.h" #include "ui/base/device_form_factor.h" @@ -746,11 +747,10 @@ bool search_feature_triggered = provider_client_->GetOmniboxTriggeredFeatureService() ->GetFeatureTriggeredInSession( - OmniboxTriggeredFeatureService::Feature::kRemoteSearchFeature) || + metrics::OmniboxEventProto_Feature_REMOTE_SEARCH_FEATURE) || provider_client_->GetOmniboxTriggeredFeatureService() ->GetFeatureTriggeredInSession( - OmniboxTriggeredFeatureService::Feature:: - kRemoteZeroSuggestFeature); + metrics::OmniboxEventProto_Feature_REMOTE_ZERO_SUGGEST_FEATURE); const std::string experiment_stats = base::StringPrintf( "%" PRId64 "j%dj%d", query_formulation_time.InMilliseconds(), search_feature_triggered, input_.current_page_classification()); @@ -1103,7 +1103,7 @@ if (top_match_rich_autocompletion_type != AutocompleteMatch::RichAutocompletionType::kNone) { provider_client_->GetOmniboxTriggeredFeatureService()->FeatureTriggered( - OmniboxTriggeredFeatureService::Feature::kRichAutocompletion); + metrics::OmniboxEventProto_Feature_RICH_AUTOCOMPLETION); } DelayedNotifyChanged(force_notify_default_match_changed ||
diff --git a/components/omnibox/browser/autocomplete_provider_unittest.cc b/components/omnibox/browser/autocomplete_provider_unittest.cc index f4c58b44..2db5128c 100644 --- a/components/omnibox/browser/autocomplete_provider_unittest.cc +++ b/components/omnibox/browser/autocomplete_provider_unittest.cc
@@ -400,7 +400,7 @@ client_->GetOmniboxTriggeredFeatureService()->ResetSession(); if (value) { client_->GetOmniboxTriggeredFeatureService()->FeatureTriggered( - OmniboxTriggeredFeatureService::Feature::kRemoteSearchFeature); + metrics::OmniboxEventProto_Feature_REMOTE_SEARCH_FEATURE); } }
diff --git a/components/omnibox/browser/bookmark_provider.cc b/components/omnibox/browser/bookmark_provider.cc index 6fdd322..076db5a 100644 --- a/components/omnibox/browser/bookmark_provider.cc +++ b/components/omnibox/browser/bookmark_provider.cc
@@ -23,6 +23,7 @@ #include "components/omnibox/browser/scoring_functor.h" #include "components/omnibox/browser/titled_url_match_utils.h" #include "components/prefs/pref_service.h" +#include "third_party/metrics_proto/omnibox_event.pb.h" #include "third_party/metrics_proto/omnibox_focus_type.pb.h" #include "third_party/metrics_proto/omnibox_input_type.pb.h" #include "ui/base/page_transition_types.h" @@ -164,8 +165,8 @@ OmniboxFieldTrial:: ShortBookmarkSuggestionsByTotalInputLengthThreshold()) { client_->GetOmniboxTriggeredFeatureService()->FeatureTriggered( - OmniboxTriggeredFeatureService::Feature:: - kShortBookmarkSuggestionsByTotalInputLength); + metrics:: + OmniboxEventProto_Feature_SHORT_BOOKMARK_SUGGESTIONS_BY_TOTAL_INPUT_LENGTH); return OmniboxFieldTrial:: kShortBookmarkSuggestionsByTotalInputLengthCounterfactual .Get()
diff --git a/components/omnibox/browser/bookmark_provider_unittest.cc b/components/omnibox/browser/bookmark_provider_unittest.cc index 8050864..0e75cd72 100644 --- a/components/omnibox/browser/bookmark_provider_unittest.cc +++ b/components/omnibox/browser/bookmark_provider_unittest.cc
@@ -547,8 +547,8 @@ // be allowed to prefix match. These tests are trying to match the mock // bookmark "testing short bookmarks". - auto short_feature = OmniboxTriggeredFeatureService::Feature:: - kShortBookmarkSuggestionsByTotalInputLength; + auto short_feature = metrics:: + OmniboxEventProto_Feature_SHORT_BOOKMARK_SUGGESTIONS_BY_TOTAL_INPUT_LENGTH; { SCOPED_TRACE("Default."); @@ -725,8 +725,8 @@ base::test::ScopedFeatureList enable_short_bookmarks( omnibox::kShortBookmarkSuggestionsByTotalInputLength); - auto short_feature = OmniboxTriggeredFeatureService::Feature:: - kShortBookmarkSuggestionsByTotalInputLength; + auto short_feature = metrics:: + OmniboxEventProto_Feature_SHORT_BOOKMARK_SUGGESTIONS_BY_TOTAL_INPUT_LENGTH; // Should return path matched bookmark. SCOPED_TRACE("feature enabled without counterfactual");
diff --git a/components/omnibox/browser/history_cluster_provider.cc b/components/omnibox/browser/history_cluster_provider.cc index 3ec48ec9..9351a5f 100644 --- a/components/omnibox/browser/history_cluster_provider.cc +++ b/components/omnibox/browser/history_cluster_provider.cc
@@ -14,6 +14,8 @@ #include "components/omnibox/browser/autocomplete_match_classification.h" #include "components/omnibox/browser/autocomplete_match_type.h" #include "components/omnibox/browser/autocomplete_provider.h" +#include "third_party/metrics_proto/omnibox_event.pb.h" + #include "components/omnibox/browser/autocomplete_provider_client.h" #include "components/omnibox/browser/autocomplete_provider_listener.h" #include "components/strings/grit/components_strings.h" @@ -133,7 +135,7 @@ base::UTF16ToUTF8(search_match.contents)); if (matched_keyword_data) { client_->GetOmniboxTriggeredFeatureService()->FeatureTriggered( - OmniboxTriggeredFeatureService::Feature::kHistoryClusterSuggestion); + metrics::OmniboxEventProto_Feature_HISTORY_CLUSTER_SUGGESTION); if (!history_clusters::GetConfig() .omnibox_history_cluster_provider_counterfactual) { matches_.push_back(
diff --git a/components/omnibox/browser/history_cluster_provider_unittest.cc b/components/omnibox/browser/history_cluster_provider_unittest.cc index 89edae0..d1eeecb2 100644 --- a/components/omnibox/browser/history_cluster_provider_unittest.cc +++ b/components/omnibox/browser/history_cluster_provider_unittest.cc
@@ -25,6 +25,7 @@ #include "components/prefs/testing_pref_service.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/metrics_proto/omnibox_event.pb.h" #include "third_party/omnibox_proto/groups.pb.h" AutocompleteMatch CreateMatch(std::u16string contents, @@ -99,11 +100,11 @@ } void VerifyFeatureTriggered(bool expected) { - EXPECT_EQ(autocomplete_provider_client_->GetOmniboxTriggeredFeatureService() - ->GetFeatureTriggeredInSession( - OmniboxTriggeredFeatureService::Feature:: - kHistoryClusterSuggestion), - expected); + EXPECT_EQ( + autocomplete_provider_client_->GetOmniboxTriggeredFeatureService() + ->GetFeatureTriggeredInSession( + metrics::OmniboxEventProto_Feature_HISTORY_CLUSTER_SUGGESTION), + expected); } // Tracks `OnProviderUpdate()` invocations.
diff --git a/components/omnibox/browser/history_fuzzy_provider.cc b/components/omnibox/browser/history_fuzzy_provider.cc index 0992b99..98d5bbd 100644 --- a/components/omnibox/browser/history_fuzzy_provider.cc +++ b/components/omnibox/browser/history_fuzzy_provider.cc
@@ -36,6 +36,7 @@ #include "components/omnibox/browser/omnibox_field_trial.h" #include "components/omnibox/browser/omnibox_triggered_feature_service.h" #include "components/url_formatter/elide_url.h" +#include "third_party/metrics_proto/omnibox_event.pb.h" #include "third_party/metrics_proto/omnibox_focus_type.pb.h" #include "url/gurl.h" @@ -545,7 +546,7 @@ }); if (met_threshold) { client()->GetOmniboxTriggeredFeatureService()->FeatureTriggered( - OmniboxTriggeredFeatureService::Feature::kFuzzyUrlSuggestions); + metrics::OmniboxEventProto_Feature_FUZZY_URL_SUGGESTIONS); } // When in the counterfactual group, we do all the work of finding fuzzy
diff --git a/components/omnibox/browser/history_quick_provider.cc b/components/omnibox/browser/history_quick_provider.cc index f121d2c..f1ba7d42 100644 --- a/components/omnibox/browser/history_quick_provider.cc +++ b/components/omnibox/browser/history_quick_provider.cc
@@ -37,6 +37,7 @@ #include "components/prefs/pref_service.h" #include "components/url_formatter/url_formatter.h" #include "net/base/registry_controlled_domains/registry_controlled_domain.h" +#include "third_party/metrics_proto/omnibox_event.pb.h" #include "third_party/metrics_proto/omnibox_focus_type.pb.h" #include "third_party/metrics_proto/omnibox_input_type.pb.h" #include "ui/base/page_transition_types.h" @@ -160,7 +161,7 @@ // suggestions to distinguish them in metrics. if (!host_matches.empty()) { client()->GetOmniboxTriggeredFeatureService()->FeatureTriggered( - OmniboxTriggeredFeatureService::Feature::kDomainSuggestions); + metrics::OmniboxEventProto_Feature_DOMAIN_SUGGESTIONS); static const bool counterfactual = OmniboxFieldTrial::kDomainSuggestionsCounterfactual.Get(); if (!counterfactual)
diff --git a/components/omnibox/browser/history_quick_provider_unittest.cc b/components/omnibox/browser/history_quick_provider_unittest.cc index e02410f..9afdf661 100644 --- a/components/omnibox/browser/history_quick_provider_unittest.cc +++ b/components/omnibox/browser/history_quick_provider_unittest.cc
@@ -33,6 +33,7 @@ #include "components/omnibox/common/omnibox_features.h" #include "components/search_engines/template_url_starter_pack_data.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/metrics_proto/omnibox_event.pb.h" #include "third_party/metrics_proto/omnibox_focus_type.pb.h" using base::ASCIIToUTF16; @@ -1067,12 +1068,11 @@ [](const auto& match) { return match.description; }); EXPECT_THAT(match_titles, testing::ElementsAreArray(expected_matches)); - EXPECT_EQ( - client() - .GetOmniboxTriggeredFeatureService() - ->GetFeatureTriggeredInSession( - OmniboxTriggeredFeatureService::Feature::kDomainSuggestions), - expected_triggered); + EXPECT_EQ(client() + .GetOmniboxTriggeredFeatureService() + ->GetFeatureTriggeredInSession( + metrics::OmniboxEventProto_Feature_DOMAIN_SUGGESTIONS), + expected_triggered); }; // When matching a popular domain, its top 3 suggestions should be suggested
diff --git a/components/omnibox/browser/omnibox_metrics_provider.cc b/components/omnibox/browser/omnibox_metrics_provider.cc index 2f9ca9b2..64371a0 100644 --- a/components/omnibox/browser/omnibox_metrics_provider.cc +++ b/components/omnibox/browser/omnibox_metrics_provider.cc
@@ -223,10 +223,9 @@ if (log.is_query_started_from_tile) omnibox_event->set_is_query_started_from_tile(true); for (auto feature : log.features_triggered) - omnibox_event->add_feature_triggered(static_cast<size_t>(feature)); + omnibox_event->add_feature_triggered(feature); for (auto feature : log.features_triggered_in_session) { - omnibox_event->add_feature_triggered_in_session( - static_cast<size_t>(feature)); + omnibox_event->add_feature_triggered_in_session(feature); } }
diff --git a/components/omnibox/browser/omnibox_triggered_feature_service.h b/components/omnibox/browser/omnibox_triggered_feature_service.h index 61e6828..14335185 100644 --- a/components/omnibox/browser/omnibox_triggered_feature_service.h +++ b/components/omnibox/browser/omnibox_triggered_feature_service.h
@@ -8,30 +8,13 @@ #include <set> #include "components/omnibox/browser/autocomplete_match.h" +#include "third_party/metrics_proto/omnibox_event.pb.h" // Tracks the features that trigger during an omnibox session and records them // to the logs. This is used for counterfactual slicing metrics by feature. class OmniboxTriggeredFeatureService { public: - // The list of features used for counterfactual slicing. - // These values are persisted to logs. Entries should not be renumbered and - // numeric values should never be reused. When adding an entry here, a - // corresponding entry should be added in the UMA histograms. - enum class Feature { - kRichAutocompletion = 0, - // kBookmarkPaths = 1, // Obsolete, launched and logging code removed. - kShortBookmarkSuggestionsByTotalInputLength = 2, - kFuzzyUrlSuggestions = 3, - kHistoryClusterSuggestion = 4, - kDomainSuggestions = 5, - // Whether the `SearchProvider` response included: - // '"google:fieldtrialtriggered":true'. - kRemoteSearchFeature = 6, - // Like `kRemoteSearchFeature`, but for the `ZeroSearchProvider`. - kRemoteZeroSuggestFeature = 7, - kShortcutBoost = 8, - kMaxValue = kShortcutBoost, - }; + using Feature = metrics::OmniboxEventProto_Feature; using Features = std::set<Feature>; OmniboxTriggeredFeatureService();
diff --git a/components/omnibox/browser/omnibox_triggered_feature_service_unittest.cc b/components/omnibox/browser/omnibox_triggered_feature_service_unittest.cc index 5da54b72..8a3faf99 100644 --- a/components/omnibox/browser/omnibox_triggered_feature_service_unittest.cc +++ b/components/omnibox/browser/omnibox_triggered_feature_service_unittest.cc
@@ -8,6 +8,7 @@ #include "components/omnibox/browser/autocomplete_match.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/abseil-cpp/absl/types/optional.h" +#include "third_party/metrics_proto/omnibox_event.pb.h" class OmniboxTriggeredFeatureServiceTest : public testing::Test { public: @@ -45,13 +46,14 @@ TEST_F(OmniboxTriggeredFeatureServiceTest, TwoFeaturesTriggered) { service_.FeatureTriggered( - OmniboxTriggeredFeatureService::Feature::kRemoteSearchFeature); - service_.FeatureTriggered(OmniboxTriggeredFeatureService::Feature:: - kShortBookmarkSuggestionsByTotalInputLength); + metrics::OmniboxEventProto_Feature_REMOTE_SEARCH_FEATURE); + service_.FeatureTriggered( + metrics:: + OmniboxEventProto_Feature_SHORT_BOOKMARK_SUGGESTIONS_BY_TOTAL_INPUT_LENGTH); RecordAndExpectFeatures( - {OmniboxTriggeredFeatureService::Feature::kRemoteSearchFeature, - OmniboxTriggeredFeatureService::Feature:: - kShortBookmarkSuggestionsByTotalInputLength}); + {metrics::OmniboxEventProto_Feature_REMOTE_SEARCH_FEATURE, + metrics:: + OmniboxEventProto_Feature_SHORT_BOOKMARK_SUGGESTIONS_BY_TOTAL_INPUT_LENGTH}); histogram_.ExpectTotalCount("Omnibox.RichAutocompletion.Triggered", 0); histogram_.ExpectUniqueSample("Omnibox.RichAutocompletion.Triggered.Any", @@ -92,7 +94,7 @@ // Simulate 4 updates in the session, 3 of which had rich // autocompletion, of 2 different types. service_.FeatureTriggered( - OmniboxTriggeredFeatureService::Feature::kRichAutocompletion); + metrics::OmniboxEventProto_Feature_RICH_AUTOCOMPLETION); service_.RichAutocompletionTypeTriggered( AutocompleteMatch::RichAutocompletionType::kTitleNonPrefix); service_.RichAutocompletionTypeTriggered( @@ -103,7 +105,7 @@ AutocompleteMatch::RichAutocompletionType::kNone); RecordAndExpectFeatures( - {OmniboxTriggeredFeatureService::Feature::kRichAutocompletion}); + {metrics::OmniboxEventProto_Feature_RICH_AUTOCOMPLETION}); histogram_.ExpectTotalCount("Omnibox.RichAutocompletion.Triggered", 3); histogram_.ExpectBucketCount( @@ -131,14 +133,15 @@ TEST_F(OmniboxTriggeredFeatureServiceTest, ResetInput) { service_.FeatureTriggered( - OmniboxTriggeredFeatureService::Feature::kRemoteSearchFeature); + metrics::OmniboxEventProto_Feature_REMOTE_SEARCH_FEATURE); service_.ResetInput(); - service_.FeatureTriggered(OmniboxTriggeredFeatureService::Feature:: - kShortBookmarkSuggestionsByTotalInputLength); + service_.FeatureTriggered( + metrics:: + OmniboxEventProto_Feature_SHORT_BOOKMARK_SUGGESTIONS_BY_TOTAL_INPUT_LENGTH); RecordAndExpectFeatures( - {OmniboxTriggeredFeatureService::Feature:: - kShortBookmarkSuggestionsByTotalInputLength}, - {OmniboxTriggeredFeatureService::Feature::kRemoteSearchFeature, - OmniboxTriggeredFeatureService::Feature:: - kShortBookmarkSuggestionsByTotalInputLength}); + {metrics:: + OmniboxEventProto_Feature_SHORT_BOOKMARK_SUGGESTIONS_BY_TOTAL_INPUT_LENGTH}, + {metrics::OmniboxEventProto_Feature_REMOTE_SEARCH_FEATURE, + metrics:: + OmniboxEventProto_Feature_SHORT_BOOKMARK_SUGGESTIONS_BY_TOTAL_INPUT_LENGTH}); }
diff --git a/components/omnibox/browser/search_provider.cc b/components/omnibox/browser/search_provider.cc index 1d7cedf..c81a468 100644 --- a/components/omnibox/browser/search_provider.cc +++ b/components/omnibox/browser/search_provider.cc
@@ -457,7 +457,7 @@ if (results_updated) { if (results->field_trial_triggered) { client()->GetOmniboxTriggeredFeatureService()->FeatureTriggered( - OmniboxTriggeredFeatureService::Feature::kRemoteSearchFeature); + metrics::OmniboxEventProto_Feature_REMOTE_SEARCH_FEATURE); } SortResults(is_keyword, results); PrefetchImages(results);
diff --git a/components/omnibox/browser/search_suggestion_parser.cc b/components/omnibox/browser/search_suggestion_parser.cc index ef1eeb52..976905e 100644 --- a/components/omnibox/browser/search_suggestion_parser.cc +++ b/components/omnibox/browser/search_suggestion_parser.cc
@@ -69,26 +69,26 @@ // number of returned matches and will supply empty vector for any item that is // either invalid or missing. // The function will always return a valid and properly sized vector of vectors, -// equal in length to |expected_size|, even if the input |subtypes_value| is not +// equal in length to `expected_size`, even if the input `subtypes_list` is not // valid. std::vector<std::vector<int>> ParseMatchSubtypes( - const base::Value* subtypes_value, + const base::Value::List* subtypes_list, size_t expected_size) { std::vector<std::vector<int>> result(expected_size); - if (subtypes_value == nullptr || !subtypes_value->is_list()) + if (subtypes_list == nullptr) { return result; - const auto& subtypes_list = subtypes_value->GetList(); + } - if (!subtypes_list.empty() && subtypes_list.size() != expected_size) { - LOG(WARNING) << "The length of reported subtypes (" << subtypes_list.size() + if (!subtypes_list->empty() && subtypes_list->size() != expected_size) { + LOG(WARNING) << "The length of reported subtypes (" << subtypes_list->size() << ") does not match the expected length (" << expected_size << ')'; } - const auto num_items = std::min(expected_size, subtypes_list.size()); + const auto num_items = std::min(expected_size, subtypes_list->size()); for (auto index = 0u; index < num_items; index++) { - const auto& subtypes_item = subtypes_list[index]; + const auto& subtypes_item = (*subtypes_list)[index]; // Permissive: ignore subtypes that are not in a form of a list. if (!subtypes_item.is_list()) continue; @@ -554,46 +554,42 @@ // Reset suggested relevance information. results->verbatim_relevance = -1; - const base::Value* suggest_types = nullptr; - const base::Value* suggest_subtypes = nullptr; - const base::Value* relevances = nullptr; - const base::Value* suggestion_details = nullptr; - const base::Value* subtype_identifiers = nullptr; + const base::Value::List* suggest_types = nullptr; + const base::Value::List* suggest_subtypes = nullptr; + const base::Value::List* relevances = nullptr; + const base::Value::List* suggestion_details = nullptr; + const base::Value::List* subtype_identifiers = nullptr; int prefetch_index = -1; int prerender_index = -1; omnibox::GroupsInfo groups_info; if (root_list.size() > 4u && root_list[4].is_dict()) { - const base::Value& extras = root_list[4]; + const base::Value::Dict& extras = root_list[4].GetDict(); - suggest_types = extras.FindListKey("google:suggesttype"); + suggest_types = extras.FindList("google:suggesttype"); - suggest_subtypes = extras.FindListKey("google:suggestsubtypes"); + suggest_subtypes = extras.FindList("google:suggestsubtypes"); - relevances = extras.FindListKey("google:suggestrelevance"); + relevances = extras.FindList("google:suggestrelevance"); // Discard this list if its size does not match that of the suggestions. - if (relevances && relevances->GetList().size() != results_list.size()) { + if (relevances && relevances->size() != results_list.size()) { relevances = nullptr; } if (absl::optional<int> relevance = - extras.FindIntKey("google:verbatimrelevance")) { + extras.FindInt("google:verbatimrelevance")) { results->verbatim_relevance = *relevance; } // Check if the active suggest field trial (if any) has triggered either // for the default provider or keyword provider. absl::optional<bool> field_trial_triggered = - extras.FindBoolKey("google:fieldtrialtriggered"); + extras.FindBool("google:fieldtrialtriggered"); results->field_trial_triggered = field_trial_triggered.value_or(false); results->experiment_stats_v2s.clear(); - const base::Value* experiment_stats_v2s_value = - extras.FindListKey("google:experimentstats"); - const base::Value::List* experiment_stats_v2s_list = nullptr; - if (experiment_stats_v2s_value) { - experiment_stats_v2s_list = experiment_stats_v2s_value->GetIfList(); - } + const base::Value::List* experiment_stats_v2s_list = + extras.FindList("google:experimentstats"); if (experiment_stats_v2s_list) { for (const auto& experiment_stats_v2_value : *experiment_stats_v2s_list) { const base::Value::Dict* experiment_stats_v2_dict = @@ -616,27 +612,27 @@ } } - const auto* groups_info_string = extras.FindStringKey("google:groupsinfo"); + const auto* groups_info_string = extras.FindString("google:groupsinfo"); DecodeProtoFromBase64<omnibox::GroupsInfo>(groups_info_string, groups_info); - const base::Value* client_data = extras.FindDictKey("google:clientdata"); + const base::Value::Dict* client_data = extras.FindDict("google:clientdata"); if (client_data) { - prefetch_index = client_data->FindIntKey("phi").value_or(-1); - prerender_index = client_data->FindIntKey("pre").value_or(-1); + prefetch_index = client_data->FindInt("phi").value_or(-1); + prerender_index = client_data->FindInt("pre").value_or(-1); } - suggestion_details = extras.FindListKey("google:suggestdetail"); + suggestion_details = extras.FindList("google:suggestdetail"); // Discard this list if its size does not match that of the suggestions. if (suggestion_details && - suggestion_details->GetList().size() != results_list.size()) { + suggestion_details->size() != results_list.size()) { suggestion_details = nullptr; } // Legacy code: Get subtype identifiers. - subtype_identifiers = extras.FindListKey("google:subtypeid"); + subtype_identifiers = extras.FindList("google:subtypeid"); // Discard this list if its size does not match that of the suggestions. if (subtype_identifiers && - subtype_identifiers->GetList().size() != results_list.size()) { + subtype_identifiers->size() != results_list.size()) { subtype_identifiers = nullptr; } @@ -673,10 +669,10 @@ // Apply valid suggested relevance scores; discard invalid lists. if (relevances) { - if (!relevances->GetList()[index].is_int()) { + if (!(*relevances)[index].is_int()) { relevances = nullptr; } else { - relevance = relevances->GetList()[index].GetInt(); + relevance = (*relevances)[index].GetInt(); } } @@ -685,23 +681,22 @@ // Legacy code: if the server sends us a single subtype ID, place it beside // other subtypes. - if (subtype_identifiers && index < subtype_identifiers->GetList().size() && - subtype_identifiers->GetList()[index].is_int()) { - subtypes[index].emplace_back( - subtype_identifiers->GetList()[index].GetInt()); + if (subtype_identifiers && index < subtype_identifiers->size() && + (*subtype_identifiers)[index].is_int()) { + subtypes[index].emplace_back((*subtype_identifiers)[index].GetInt()); } - if (suggest_types && index < suggest_types->GetList().size() && - suggest_types->GetList()[index].is_string()) { + if (suggest_types && index < suggest_types->size() && + (*suggest_types)[index].is_string()) { match_type = - GetAutocompleteMatchType(suggest_types->GetList()[index].GetString()); + GetAutocompleteMatchType((*suggest_types)[index].GetString()); } std::string deletion_url; - if (suggestion_details && index < suggestion_details->GetList().size() && - suggestion_details->GetList()[index].is_dict()) { + if (suggestion_details && index < suggestion_details->size() && + (*suggestion_details)[index].is_dict()) { const base::Value::Dict& suggestion_detail = - suggestion_details->GetList()[index].GetDict(); + (*suggestion_details)[index].GetDict(); deletion_url = FindStringOrEmpty(suggestion_detail, "du"); } @@ -757,11 +752,10 @@ absl::optional<int> suggestion_group_id; omnibox::EntityInfo entity_info; - if (suggestion_details && - suggestion_details->GetList()[index].is_dict() && - !suggestion_details->GetList()[index].GetDict().empty()) { + if (suggestion_details && (*suggestion_details)[index].is_dict() && + !(*suggestion_details)[index].GetDict().empty()) { const base::Value::Dict& suggestion_detail = - suggestion_details->GetList()[index].GetDict(); + (*suggestion_details)[index].GetDict(); const auto* entity_info_string = suggestion_detail.FindString("google:entityinfo");
diff --git a/components/omnibox/browser/shortcuts_provider.cc b/components/omnibox/browser/shortcuts_provider.cc index d387d4e..135e6f9 100644 --- a/components/omnibox/browser/shortcuts_provider.cc +++ b/components/omnibox/browser/shortcuts_provider.cc
@@ -40,6 +40,7 @@ #include "components/prefs/pref_service.h" #include "components/search_engines/template_url_service.h" #include "components/url_formatter/url_fixer.h" +#include "third_party/metrics_proto/omnibox_event.pb.h" #include "third_party/metrics_proto/omnibox_focus_type.pb.h" #include "third_party/metrics_proto/omnibox_input_type.pb.h" #include "third_party/omnibox_proto/groups.pb.h" @@ -313,7 +314,7 @@ : OmniboxFieldTrial::kShortcutBoostUrlScore.Get(); if (boost_score > best_match->relevance) { client_->GetOmniboxTriggeredFeatureService()->FeatureTriggered( - OmniboxTriggeredFeatureService::Feature::kShortcutBoost); + metrics::OmniboxEventProto_Feature_SHORTCUT_BOOST); if (!OmniboxFieldTrial::kShortcutBoostCounterfactual.Get()) { max_relevance = boost_score; best_match->relevance = max_relevance;
diff --git a/components/omnibox/browser/shortcuts_provider_unittest.cc b/components/omnibox/browser/shortcuts_provider_unittest.cc index 4383962..c325cb32 100644 --- a/components/omnibox/browser/shortcuts_provider_unittest.cc +++ b/components/omnibox/browser/shortcuts_provider_unittest.cc
@@ -880,7 +880,7 @@ OmniboxTriggeredFeatureService* trigger_service = client_->GetOmniboxTriggeredFeatureService(); OmniboxTriggeredFeatureService::Feature trigger_feature = - OmniboxTriggeredFeatureService::Feature::kShortcutBoost; + metrics::OmniboxEventProto_Feature_SHORTCUT_BOOST; scoped_feature_list_.Reset(); scoped_feature_list_.InitAndEnableFeatureWithParameters(
diff --git a/components/omnibox/browser/url_index_private_data.cc b/components/omnibox/browser/url_index_private_data.cc index c8ce05d..41e37198 100644 --- a/components/omnibox/browser/url_index_private_data.cc +++ b/components/omnibox/browser/url_index_private_data.cc
@@ -41,6 +41,7 @@ #include "components/omnibox/common/omnibox_features.h" #include "components/search_engines/template_url_service.h" #include "components/url_formatter/url_formatter.h" +#include "third_party/metrics_proto/omnibox_event.pb.h" namespace { @@ -704,7 +705,7 @@ if (new_scored_match.raw_score_before_domain_boosting < new_scored_match.raw_score_after_domain_boosting) { triggered_feature_service->FeatureTriggered( - OmniboxTriggeredFeatureService::Feature::kDomainSuggestions); + metrics::OmniboxEventProto_Feature_DOMAIN_SUGGESTIONS); } // Filter new matches that ended up scoring 0. (These are usually matches
diff --git a/components/omnibox/browser/zero_suggest_provider.cc b/components/omnibox/browser/zero_suggest_provider.cc index 6e5b9a1..e591cbb 100644 --- a/components/omnibox/browser/zero_suggest_provider.cc +++ b/components/omnibox/browser/zero_suggest_provider.cc
@@ -711,7 +711,7 @@ if (results.field_trial_triggered) { client()->GetOmniboxTriggeredFeatureService()->FeatureTriggered( - OmniboxTriggeredFeatureService::Feature::kRemoteZeroSuggestFeature); + metrics::OmniboxEventProto_Feature_REMOTE_ZERO_SUGGEST_FEATURE); } // Add all the SuggestResults to the map. We display all ZeroSuggest search
diff --git a/components/omnibox/browser/zero_suggest_provider.h b/components/omnibox/browser/zero_suggest_provider.h index dc885f4..b394307b 100644 --- a/components/omnibox/browser/zero_suggest_provider.h +++ b/components/omnibox/browser/zero_suggest_provider.h
@@ -15,7 +15,6 @@ #include "base/gtest_prod_util.h" #include "components/omnibox/browser/base_search_provider.h" #include "components/omnibox/browser/search_provider.h" -#include "third_party/metrics_proto/omnibox_event.pb.h" class AutocompleteProviderListener; class PrefRegistrySimple;
diff --git a/components/onc/docs/onc_spec.md b/components/onc/docs/onc_spec.md index f69d8c7..345a2d1c 100644 --- a/components/onc/docs/onc_spec.md +++ b/components/onc/docs/onc_spec.md
@@ -1374,21 +1374,21 @@ * **SubjectMatch** * (optional) - **string** - * WiFi only. A substring which a remote RADIUS service certificate subject - name must contain in order to connect. + * A substring which a remote RADIUS service certificate subject name must + contain in order to connect. * **SubjectAlternativeNameMatch** * (optional) - [array of AlternativeSubjectName](#AlternativeSubjectName-type) - * WiFi only. A list of alternative subject names to be matched against the - alternative subject name of an authentication server certificate. + * A list of alternative subject names to be matched against the alternative + subject name of an authentication server certificate. * **DomainSuffixMatch** * (optional) - **array of string** - * WiFi only. A list of constraints for the server domain name. If set, the - entries will be used as suffix match requirements against the DNS name - element(s) of the alternative subject name of an authentication server - certificate. When multiple match strings are specified, a match with any one - of the values is considered a sufficient match for the server certificate. + * A list of constraints for the server domain name. If set, the entries will + be used as suffix match requirements against the DNS name element(s) of + the alternative subject name of an authentication server certificate. + When multiple match strings are specified, a match with any one of the + values is considered a sufficient match for the server certificate. * **TLSVersionMax** * (optional) - **string**
diff --git a/components/policy/proto/device_management_backend.proto b/components/policy/proto/device_management_backend.proto index 75879fa88..2258140c8 100644 --- a/components/policy/proto/device_management_backend.proto +++ b/components/policy/proto/device_management_backend.proto
@@ -1637,6 +1637,9 @@ // Root device size as displayed in the device UI. optional int64 root_device_total_storage_bytes = 47; + + // Flag whether LaCros is the primary browser. + optional bool is_lacros_primary_browser = 48; } message OsUpdateStatus {
diff --git a/components/variations/service/variations_field_trial_creator.cc b/components/variations/service/variations_field_trial_creator.cc index 022d86a..ac34e13 100644 --- a/components/variations/service/variations_field_trial_creator.cc +++ b/components/variations/service/variations_field_trial_creator.cc
@@ -640,9 +640,9 @@ base::UmaHistogramEnumeration("Variations.PolicyRestriction", client_filterable_state->policy_restriction); - const SeedType seed_type = safe_seed_manager->GetSeedType(); + seed_type_ = safe_seed_manager->GetSeedType(); // If we have tried safe seed and we still get crashes, try null seed. - if (seed_type == SeedType::kNullSeed) { + if (seed_type_ == SeedType::kNullSeed) { RecordVariationsSeedUsage(SeedUsage::kNullSeedUsed); return false; } @@ -651,7 +651,7 @@ std::string seed_data; // Only set if not in safe mode. std::string base64_seed_signature; // Only set if not in safe mode. - const bool run_in_safe_mode = seed_type == SeedType::kSafeSeed; + const bool run_in_safe_mode = seed_type_ == SeedType::kSafeSeed; const bool seed_loaded = run_in_safe_mode ? GetSeedStore()->LoadSafeSeed(&seed, client_filterable_state.get())
diff --git a/components/variations/service/variations_field_trial_creator.h b/components/variations/service/variations_field_trial_creator.h index 9fc6b88..0c9ba43a 100644 --- a/components/variations/service/variations_field_trial_creator.h +++ b/components/variations/service/variations_field_trial_creator.h
@@ -23,6 +23,7 @@ #include "components/variations/proto/study.pb.h" #include "components/variations/seed_response.h" #include "components/variations/service/buildflags.h" +#include "components/variations/service/safe_seed_manager.h" #include "components/variations/service/ui_string_overrider.h" #include "components/variations/variations_seed_store.h" #include "components/version_info/channel.h" @@ -186,6 +187,8 @@ // Returns the locale that was used for evaluating trials. const std::string& application_locale() const { return application_locale_; } + SeedType seed_type() const { return seed_type_; } + protected: // Get the platform we're running on, respecting OverrideVariationsPlatform(). // Protected for testing. @@ -253,6 +256,9 @@ std::unique_ptr<VariationsSeedStore> seed_store_; + // Seed type used for variations. + SeedType seed_type_ = SeedType::kNullSeed; + // Tracks whether |CreateTrialsFromSeed| has been called, to ensure that it is // called at most once. bool create_trials_from_seed_called_;
diff --git a/components/variations/service/variations_service.cc b/components/variations/service/variations_service.cc index 685da72c..6fab05b 100644 --- a/components/variations/service/variations_service.cc +++ b/components/variations/service/variations_service.cc
@@ -937,6 +937,10 @@ &safe_seed_manager_, /*add_entropy_source_to_variations_ids=*/true); } +SeedType VariationsService::GetSeedType() const { + return field_trial_creator_.seed_type(); +} + void VariationsService::OverrideCachedUIStrings() { field_trial_creator_.OverrideCachedUIStrings(); }
diff --git a/components/variations/service/variations_service.h b/components/variations/service/variations_service.h index b90a1f0b..696659f 100644 --- a/components/variations/service/variations_service.h +++ b/components/variations/service/variations_service.h
@@ -196,6 +196,9 @@ std::unique_ptr<base::FeatureList> feature_list, PlatformFieldTrials* platform_field_trials); + // The seed type used. + SeedType GetSeedType() const; + // Overrides cached UI strings on the resource bundle once it is initialized. void OverrideCachedUIStrings();
diff --git a/components/version_ui/BUILD.gn b/components/version_ui/BUILD.gn index e7cc8251..913cf913 100644 --- a/components/version_ui/BUILD.gn +++ b/components/version_ui/BUILD.gn
@@ -15,5 +15,6 @@ "//build:chromeos_buildflags", "//components/variations", "//components/variations/net", + "//components/variations/service", ] }
diff --git a/components/version_ui/resources/about_version.html b/components/version_ui/resources/about_version.html index 080e71ea..f56fdb9 100644 --- a/components/version_ui/resources/about_version.html +++ b/components/version_ui/resources/about_version.html
@@ -187,6 +187,10 @@ <td class="version" id="linker">$i18n{linker}</td> </tr> </if> + <tr id="variations-seed-section" hidden> + <td class="label">$i18n{variations_seed_name}</td> + <td class="version" id="variations-seed">$i18n{variations_seed}</td> + </tr> <tr id="variations-section"> <td class="label">$i18n{variations_name}</td> <td class="version" id="variations-list"></td>
diff --git a/components/version_ui/resources/about_version.ts b/components/version_ui/resources/about_version.ts index bc7f0f8..230ab5e 100644 --- a/components/version_ui/resources/about_version.ts +++ b/components/version_ui/resources/about_version.ts
@@ -157,6 +157,10 @@ .then(returnCustomizationId); // </if> + if (getRequiredElement('variations-seed').textContent !== '') { + getRequiredElement('variations-seed-section').hidden = false; + } + if (getRequiredElement('sanitizer').textContent !== '') { getRequiredElement('sanitizer-section').hidden = false; }
diff --git a/components/version_ui/version_handler_helper.cc b/components/version_ui/version_handler_helper.cc index 1b38fff..98c1607 100644 --- a/components/version_ui/version_handler_helper.cc +++ b/components/version_ui/version_handler_helper.cc
@@ -13,9 +13,22 @@ #include "base/strings/string_util.h" #include "components/variations/active_field_trials.h" #include "components/variations/net/variations_command_line.h" +#include "components/variations/service/safe_seed_manager.h" namespace version_ui { +std::string SeedTypeToUiString(variations::SeedType seed_type) { + switch (seed_type) { + case variations::SeedType::kRegularSeed: + // We only display if Safe or Null seed is used. + return std::string(); + case variations::SeedType::kSafeSeed: + return "Safe"; + case variations::SeedType::kNullSeed: + return "Null"; + } +} + base::Value::List GetVariationsList() { std::vector<std::string> variations; #if !defined(NDEBUG)
diff --git a/components/version_ui/version_handler_helper.h b/components/version_ui/version_handler_helper.h index ab6493e57e..bb367bf 100644 --- a/components/version_ui/version_handler_helper.h +++ b/components/version_ui/version_handler_helper.h
@@ -7,8 +7,16 @@ #include "base/values.h" +namespace variations { +enum class SeedType; +} + namespace version_ui { +// Returns the variation seed type to be displayed on the chrome://version page. +// Returns empty for Regular seed which should not be shown. +std::string SeedTypeToUiString(variations::SeedType seed_type); + // Returns the list of variations to be displayed on the chrome:://version page. base::Value::List GetVariationsList();
diff --git a/components/version_ui/version_ui_constants.cc b/components/version_ui/version_ui_constants.cc index c8eda8a9..1ace5fe 100644 --- a/components/version_ui/version_ui_constants.cc +++ b/components/version_ui/version_ui_constants.cc
@@ -92,6 +92,8 @@ const char kUserAgentName[] = "user_agent_name"; const char kVariationsCmdName[] = "variations_cmd_name"; const char kVariationsName[] = "variations_name"; +const char kVariationsSeed[] = "variations_seed"; +const char kVariationsSeedName[] = "variations_seed_name"; const char kVersion[] = "version"; const char kVersionModifier[] = "version_modifier"; const char kVersionProcessorVariation[] = "version_processor_variation";
diff --git a/components/version_ui/version_ui_constants.h b/components/version_ui/version_ui_constants.h index 4fe9af7..1ffcca2 100644 --- a/components/version_ui/version_ui_constants.h +++ b/components/version_ui/version_ui_constants.h
@@ -95,6 +95,8 @@ extern const char kUserAgentName[]; extern const char kVariationsCmdName[]; extern const char kVariationsName[]; +extern const char kVariationsSeed[]; +extern const char kVariationsSeedName[]; extern const char kVersion[]; extern const char kVersionModifier[]; extern const char kVersionProcessorVariation[];
diff --git a/components/version_ui_strings.grdp b/components/version_ui_strings.grdp index 6a643c6..c7b40ac 100644 --- a/components/version_ui_strings.grdp +++ b/components/version_ui_strings.grdp
@@ -79,6 +79,9 @@ <message name="IDS_VERSION_UI_VARIATIONS" desc="label for the variations list on the about:version page"> Active Variations </message> + <message name="IDS_VERSION_UI_VARIATIONS_SEED_NAME" desc="label for the variations seed type on the about:version page"> + Variations Seed Type + </message> <message name="IDS_VERSION_UI_VARIATIONS_CMD" desc="label for the variations information in command-line format on the about:version page"> Command-line variations </message>
diff --git a/components/version_ui_strings_grdp/IDS_VERSION_UI_VARIATIONS_SEED_NAME.png.sha1 b/components/version_ui_strings_grdp/IDS_VERSION_UI_VARIATIONS_SEED_NAME.png.sha1 new file mode 100644 index 0000000..7ffcb5a --- /dev/null +++ b/components/version_ui_strings_grdp/IDS_VERSION_UI_VARIATIONS_SEED_NAME.png.sha1
@@ -0,0 +1 @@ +930bc92d80971d9a3c3791403b96e88835e50a6e \ No newline at end of file
diff --git a/components/viz/service/BUILD.gn b/components/viz/service/BUILD.gn index 395917cd..96fe556 100644 --- a/components/viz/service/BUILD.gn +++ b/components/viz/service/BUILD.gn
@@ -189,6 +189,8 @@ "hit_test/hit_test_aggregator_delegate.h", "hit_test/hit_test_manager.cc", "hit_test/hit_test_manager.h", + "layers/layer_context_impl.cc", + "layers/layer_context_impl.h", "performance_hint/hint_session.cc", "performance_hint/hint_session.h", "performance_hint/utils.cc", @@ -246,6 +248,7 @@ "//media", "//media/capture:capture_lib", "//media/mojo/services", + "//services/metrics/public/mojom", "//services/tracing/public/cpp:cpp", "//services/viz/privileged/mojom", "//skia", @@ -257,6 +260,8 @@ public_deps = [ "//base", + "//cc", + "//cc/animation", "//cc/debug", "//components/viz/common", "//gpu/command_buffer/service:gles2", @@ -264,6 +269,7 @@ "//gpu/vulkan:buildflags", "//media/gpu/ipc/service", "//media/mojo/services", + "//services/metrics/public/cpp:metrics_cpp", "//services/viz/privileged/mojom/compositing", "//services/viz/privileged/mojom/gl", "//services/viz/public/mojom",
diff --git a/components/viz/service/frame_sinks/DEPS b/components/viz/service/frame_sinks/DEPS index b62ceac..163224a3 100644 --- a/components/viz/service/frame_sinks/DEPS +++ b/components/viz/service/frame_sinks/DEPS
@@ -6,6 +6,7 @@ "+components/viz/service/display", "+components/viz/service/display_embedder", "+components/viz/service/hit_test", + "+components/viz/service/layers", "+components/viz/service/performance_hint", "+components/viz/service/surfaces", "+components/viz/service/transitions",
diff --git a/components/viz/service/frame_sinks/compositor_frame_sink_impl.cc b/components/viz/service/frame_sinks/compositor_frame_sink_impl.cc index a9c7bb4..eeec1ba 100644 --- a/components/viz/service/frame_sinks/compositor_frame_sink_impl.cc +++ b/components/viz/service/frame_sinks/compositor_frame_sink_impl.cc
@@ -16,6 +16,7 @@ #include "build/build_config.h" #include "components/viz/service/frame_sinks/frame_sink_bundle_impl.h" #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h" +#include "services/viz/public/mojom/compositing/layer_context.mojom.h" #include "ui/gfx/overlay_transform.h" namespace viz { @@ -199,6 +200,11 @@ support_->InitializeCompositorFrameSinkType(type); } +void CompositorFrameSinkImpl::BindLayerContext( + mojom::PendingLayerContextPtr context) { + support_->BindLayerContext(*context); +} + #if BUILDFLAG(IS_ANDROID) void CompositorFrameSinkImpl::SetThreadIds( const std::vector<int32_t>& thread_ids) {
diff --git a/components/viz/service/frame_sinks/compositor_frame_sink_impl.h b/components/viz/service/frame_sinks/compositor_frame_sink_impl.h index 90af1827..3df7c43 100644 --- a/components/viz/service/frame_sinks/compositor_frame_sink_impl.h +++ b/components/viz/service/frame_sinks/compositor_frame_sink_impl.h
@@ -61,6 +61,7 @@ void DidDeleteSharedBitmap(const SharedBitmapId& id) override; void InitializeCompositorFrameSinkType( mojom::CompositorFrameSinkType type) override; + void BindLayerContext(mojom::PendingLayerContextPtr context) override; #if BUILDFLAG(IS_ANDROID) void SetThreadIds(const std::vector<int32_t>& thread_ids) override; #endif
diff --git a/components/viz/service/frame_sinks/compositor_frame_sink_support.cc b/components/viz/service/frame_sinks/compositor_frame_sink_support.cc index 966f54b..e55a674 100644 --- a/components/viz/service/frame_sinks/compositor_frame_sink_support.cc +++ b/components/viz/service/frame_sinks/compositor_frame_sink_support.cc
@@ -459,6 +459,11 @@ } } +void CompositorFrameSinkSupport::BindLayerContext( + mojom::PendingLayerContext& context) { + layer_context_impl_ = std::make_unique<LayerContextImpl>(context); +} + void CompositorFrameSinkSupport::SetThreadIds( bool from_untrusted_client, base::flat_set<base::PlatformThreadId> unverified_thread_ids) {
diff --git a/components/viz/service/frame_sinks/compositor_frame_sink_support.h b/components/viz/service/frame_sinks/compositor_frame_sink_support.h index c8350efc..b55a8d8 100644 --- a/components/viz/service/frame_sinks/compositor_frame_sink_support.h +++ b/components/viz/service/frame_sinks/compositor_frame_sink_support.h
@@ -29,11 +29,13 @@ #include "components/viz/service/frame_sinks/surface_resource_holder_client.h" #include "components/viz/service/frame_sinks/video_capture/capturable_frame_sink.h" #include "components/viz/service/hit_test/hit_test_aggregator.h" +#include "components/viz/service/layers/layer_context_impl.h" #include "components/viz/service/surfaces/frame_index_constants.h" #include "components/viz/service/surfaces/surface_client.h" #include "components/viz/service/transitions/surface_animation_manager.h" #include "components/viz/service/viz_service_export.h" #include "services/viz/public/mojom/compositing/compositor_frame_sink.mojom.h" +#include "services/viz/public/mojom/compositing/layer_context.mojom.h" #include "services/viz/public/mojom/hit_test/hit_test_region_list.mojom.h" #include "third_party/abseil-cpp/absl/types/optional.h" @@ -41,6 +43,7 @@ class FrameSinkManagerImpl; class LatestLocalSurfaceIdLookupDelegate; +class LayerContextImpl; class Surface; class SurfaceManager; @@ -132,6 +135,7 @@ base::TimeDelta GetPreferredFrameInterval( mojom::CompositorFrameSinkType* type) const; void InitializeCompositorFrameSinkType(mojom::CompositorFrameSinkType type); + void BindLayerContext(mojom::PendingLayerContext& context); void SetThreadIds( bool from_untrusted_client, base::flat_set<base::PlatformThreadId> unverified_thread_ids); @@ -455,6 +459,10 @@ // Region capture bounds associated with the last surface that was aggregated. RegionCaptureBounds current_capture_bounds_; + // In LayerContext mode only, this is the Viz LayerContext implementation + // which owns the backend layer tree for this frame sink. + std::unique_ptr<LayerContextImpl> layer_context_impl_; + base::WeakPtrFactory<CompositorFrameSinkSupport> weak_factory_{this}; };
diff --git a/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc b/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc index b2dec27..0110919 100644 --- a/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc +++ b/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc
@@ -25,6 +25,7 @@ #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h" #include "components/viz/service/frame_sinks/gpu_vsync_begin_frame_source.h" #include "components/viz/service/hit_test/hit_test_aggregator.h" +#include "services/viz/public/mojom/compositing/layer_context.mojom.h" #include "ui/gfx/geometry/skia_conversions.h" #if BUILDFLAG(IS_ANDROID) @@ -493,6 +494,11 @@ support_->InitializeCompositorFrameSinkType(type); } +void RootCompositorFrameSinkImpl::BindLayerContext( + mojom::PendingLayerContextPtr context) { + support_->BindLayerContext(*context); +} + #if BUILDFLAG(IS_ANDROID) void RootCompositorFrameSinkImpl::SetThreadIds( const std::vector<int32_t>& thread_ids) {
diff --git a/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.h b/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.h index 559a8cc..c3c15f9c 100644 --- a/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.h +++ b/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.h
@@ -121,6 +121,7 @@ SubmitCompositorFrameSyncCallback callback) override; void InitializeCompositorFrameSinkType( mojom::CompositorFrameSinkType type) override; + void BindLayerContext(mojom::PendingLayerContextPtr context) override; #if BUILDFLAG(IS_ANDROID) void SetThreadIds(const std::vector<int32_t>& thread_ids) override; #endif
diff --git a/components/viz/service/gl/gpu_service_impl.cc b/components/viz/service/gl/gpu_service_impl.cc index 5a81df28..2e19fa3bd 100644 --- a/components/viz/service/gl/gpu_service_impl.cc +++ b/components/viz/service/gl/gpu_service_impl.cc
@@ -823,6 +823,9 @@ CHECK(vea_thread_->StartWithOptions(std::move(thread_options))); } runner = vea_thread_->task_runner(); +#elif BUILDFLAG(IS_WIN) + // Windows hardware encoder requires a COM STA thread. + runner = base::ThreadPool::CreateCOMSTATaskRunner({base::MayBlock()}); #else // MayBlock() because MF VEA can take long time running GetSupportedProfiles() if (base::FeatureList::IsEnabled(
diff --git a/components/viz/service/layers/DEPS b/components/viz/service/layers/DEPS new file mode 100644 index 0000000..27a6d9aea --- /dev/null +++ b/components/viz/service/layers/DEPS
@@ -0,0 +1,4 @@ +include_rules = [ + "+components/viz/service/frame_sinks", + "+mojo/public", +]
diff --git a/components/viz/service/layers/layer_context_impl.cc b/components/viz/service/layers/layer_context_impl.cc new file mode 100644 index 0000000..5992805 --- /dev/null +++ b/components/viz/service/layers/layer_context_impl.cc
@@ -0,0 +1,37 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/viz/service/layers/layer_context_impl.h" + +#include <utility> + +#include "cc/trees/commit_state.h" +#include "cc/trees/layer_tree_host.h" +#include "components/viz/service/frame_sinks/compositor_frame_sink_support.h" + +namespace viz { + +LayerContextImpl::LayerContextImpl(mojom::PendingLayerContext& context) + : receiver_(this, std::move(context.receiver)), + client_(std::move(context.client)) {} + +LayerContextImpl::~LayerContextImpl() = default; + +void LayerContextImpl::SetTargetLocalSurfaceId(const LocalSurfaceId& id) { + context_.SetTargetLocalSurfaceId(id); +} + +void LayerContextImpl::SetVisible(bool visible) { + context_.SetVisible(visible); +} + +void LayerContextImpl::Commit(mojom::LayerTreeUpdatePtr update) { + cc::CommitState state; + state.device_viewport_rect = update->device_viewport; + state.device_scale_factor = update->device_scale_factor; + state.local_surface_id_from_parent = update->local_surface_id_from_parent; + context_.Commit(state); +} + +} // namespace viz
diff --git a/components/viz/service/layers/layer_context_impl.h b/components/viz/service/layers/layer_context_impl.h new file mode 100644 index 0000000..31b6cd4 --- /dev/null +++ b/components/viz/service/layers/layer_context_impl.h
@@ -0,0 +1,43 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_VIZ_SERVICE_LAYERS_LAYER_CONTEXT_IMPL_H_ +#define COMPONENTS_VIZ_SERVICE_LAYERS_LAYER_CONTEXT_IMPL_H_ + +#include <memory> + +#include "cc/animation/animation_host.h" +#include "cc/trees/local_layer_context.h" +#include "mojo/public/cpp/bindings/associated_receiver.h" +#include "mojo/public/cpp/bindings/associated_remote.h" +#include "services/viz/public/mojom/compositing/layer_context.mojom.h" + +namespace viz { + +// Implements the Viz LayerContext API backed by a LocalLayerContext. This +// provides the service backend for a client-side VizLayerContext. +class LayerContextImpl : public mojom::LayerContext { + public: + // Constructs a new LayerContextImpl with client connection details given by + // `context`. + explicit LayerContextImpl(mojom::PendingLayerContext& context); + ~LayerContextImpl() override; + + private: + // mojom::LayerContext: + void SetTargetLocalSurfaceId(const LocalSurfaceId& id) override; + void SetVisible(bool visible) override; + void Commit(mojom::LayerTreeUpdatePtr update) override; + + const std::unique_ptr<cc::AnimationHost> animation_host_{ + cc::AnimationHost::CreateMainInstance()}; + cc::LocalLayerContext context_{animation_host_.get()}; + + mojo::AssociatedReceiver<mojom::LayerContext> receiver_; + mojo::AssociatedRemote<mojom::LayerContextClient> client_; +}; + +} // namespace viz + +#endif // COMPONENTS_VIZ_SERVICE_LAYERS_LAYER_CONTEXT_IMPL_H_
diff --git a/content/browser/download/download_manager_impl.cc b/content/browser/download/download_manager_impl.cc index b04fb81..baed1e53 100644 --- a/content/browser/download/download_manager_impl.cc +++ b/content/browser/download/download_manager_impl.cc
@@ -1264,16 +1264,6 @@ } void DownloadManagerImpl::OpenDownload(download::DownloadItemImpl* download) { - int num_unopened = 0; - for (const auto& it : downloads_by_guid_) { - download::DownloadItemImpl* item = it.second; - if (item != nullptr && - (item->GetState() == download::DownloadItem::COMPLETE) && - !item->GetOpened()) - ++num_unopened; - } - download::RecordOpensOutstanding(num_unopened); - if (delegate_) delegate_->OpenDownload(download); }
diff --git a/content/browser/media/audio_stream_monitor.cc b/content/browser/media/audio_stream_monitor.cc index a5431ec..d4827090 100644 --- a/content/browser/media/audio_stream_monitor.cc +++ b/content/browser/media/audio_stream_monitor.cc
@@ -29,13 +29,14 @@ } // namespace AudioStreamMonitor::AudibleClientRegistration::AudibleClientRegistration( + GlobalRenderFrameHostId host_id, AudioStreamMonitor* audio_stream_monitor) - : audio_stream_monitor_(audio_stream_monitor) { - audio_stream_monitor_->AddAudibleClient(); + : host_id_(host_id), audio_stream_monitor_(audio_stream_monitor) { + audio_stream_monitor_->AddAudibleClient(host_id_); } AudioStreamMonitor::AudibleClientRegistration::~AudibleClientRegistration() { - audio_stream_monitor_->RemoveAudibleClient(); + audio_stream_monitor_->RemoveAudibleClient(host_id_); } bool AudioStreamMonitor::StreamID::operator<(const StreamID& other) const { @@ -58,7 +59,7 @@ } AudioStreamMonitor::~AudioStreamMonitor() { - DCHECK_EQ(audible_clients_, 0); + DCHECK(audible_clients_.empty()); } bool AudioStreamMonitor::WasRecentlyAudible() const { @@ -90,23 +91,32 @@ } std::unique_ptr<AudioStreamMonitor::AudibleClientRegistration> -AudioStreamMonitor::RegisterAudibleClient() { +AudioStreamMonitor::RegisterAudibleClient(GlobalRenderFrameHostId host_id) { DCHECK(thread_checker_.CalledOnValidThread()); - return std::make_unique<AudibleClientRegistration>(this); + return std::make_unique<AudibleClientRegistration>(host_id, this); } -void AudioStreamMonitor::AddAudibleClient() { +void AudioStreamMonitor::AddAudibleClient(GlobalRenderFrameHostId host_id) { DCHECK(thread_checker_.CalledOnValidThread()); - DCHECK_GE(audible_clients_, 0); - ++audible_clients_; + + audible_clients_[host_id]++; UpdateStreams(); } -void AudioStreamMonitor::RemoveAudibleClient() { +void AudioStreamMonitor::RemoveAudibleClient(GlobalRenderFrameHostId host_id) { DCHECK(thread_checker_.CalledOnValidThread()); - DCHECK_GE(audible_clients_, 0); - --audible_clients_; + DCHECK(!audible_clients_.empty()); + + auto it = audible_clients_.find(host_id); + CHECK(it != audible_clients_.end()); + CHECK_GT(it->second, 0u); + it->second--; + UpdateStreams(); + + if (it->second == 0) { + audible_clients_.erase(it); + } } // static @@ -192,36 +202,43 @@ bool was_audible = is_audible_; is_audible_ = false; - // Record whether or not a RenderFrameHost is audible. - base::flat_map<RenderFrameHostImpl*, bool> audible_frame_map; - audible_frame_map.reserve(streams_.size()); + // Determine whether a RenderFrameHost is audible based on + // stream and non-stream client states. + base::flat_map<GlobalRenderFrameHostId, bool> audible_frames; + audible_frames.reserve(streams_.size() + audible_clients_.size()); + for (auto& kv : streams_) { const bool is_stream_audible = kv.second; is_audible_ |= is_stream_audible; - - // Record whether or not the RenderFrame is audible. A RenderFrame is - // audible when it has at least one audio stream that is audible. - auto* render_frame_host_impl = - static_cast<RenderFrameHostImpl*>(RenderFrameHost::FromID( - kv.first.render_process_id, kv.first.render_frame_id)); - // This may be nullptr in tests. - if (!render_frame_host_impl) - continue; - audible_frame_map[render_frame_host_impl] |= is_stream_audible; + GlobalRenderFrameHostId host_id(kv.first.render_process_id, + kv.first.render_frame_id); + audible_frames[host_id] |= is_stream_audible; } - // Check non-stream audible clients. - is_audible_ |= (audible_clients_ > 0); + for (auto& kv : audible_clients_) { + const bool is_client_audible = kv.second > 0; + is_audible_ |= is_client_audible; + audible_frames[kv.first] |= is_client_audible; + } - if (was_audible && !is_audible_) + if (was_audible && !is_audible_) { last_became_silent_time_ = clock_->NowTicks(); + } - // Update RenderFrameHost audible state only when state changed. - for (auto& kv : audible_frame_map) { - auto* render_frame_host_impl = kv.first; + // Update RenderFrameHostImpl audible state if state has changed. + for (const auto& kv : audible_frames) { + auto* render_frame_host_impl = + static_cast<RenderFrameHostImpl*>(RenderFrameHost::FromID(kv.first)); + + // RenderFrameHostImpl may be null in some tests. + if (!render_frame_host_impl) { + continue; + } + bool is_frame_audible = kv.second; - if (is_frame_audible != render_frame_host_impl->is_audible()) + if (is_frame_audible != render_frame_host_impl->is_audible()) { render_frame_host_impl->OnAudibleStateChanged(is_frame_audible); + } } if (is_audible_ != was_audible) {
diff --git a/content/browser/media/audio_stream_monitor.h b/content/browser/media/audio_stream_monitor.h index a69531a37..09536e4 100644 --- a/content/browser/media/audio_stream_monitor.h +++ b/content/browser/media/audio_stream_monitor.h
@@ -90,17 +90,19 @@ // Class to help automatically remove audible client. class CONTENT_EXPORT AudibleClientRegistration { public: - explicit AudibleClientRegistration( - AudioStreamMonitor* audio_stream_monitor); + AudibleClientRegistration(GlobalRenderFrameHostId host_id, + AudioStreamMonitor* audio_stream_monitor); ~AudibleClientRegistration(); private: + GlobalRenderFrameHostId host_id_; raw_ptr<AudioStreamMonitor> audio_stream_monitor_; }; // Registers an audible client, which will be unregistered when the returned // AudibleClientRegistration is released. - std::unique_ptr<AudibleClientRegistration> RegisterAudibleClient(); + std::unique_ptr<AudibleClientRegistration> RegisterAudibleClient( + GlobalRenderFrameHostId host_id); private: friend class AudioStreamMonitorTest; @@ -136,10 +138,10 @@ void UpdateStreams(); // Adds/Removes Audible clients. - void AddAudibleClient(); - void RemoveAudibleClient(); + void AddAudibleClient(GlobalRenderFrameHostId host_id); + void RemoveAudibleClient(GlobalRenderFrameHostId host_id); - // The WebContents instance to receive indicator toggle notifications. This + // The WebContents instance to receive indicator toggle notifications. This // pointer should be valid for the lifetime of AudioStreamMonitor. const raw_ptr<WebContents> web_contents_; @@ -156,8 +158,11 @@ // streams will have an entry in this map. base::flat_map<StreamID, bool> streams_; - // Number of non-stream audible clients, e.g. players not using AudioServices. - int audible_clients_ = 0; + // Map of non-stream audible clients, e.g. players not using AudioServices. + // size_t is the number of audible clients associated with the + // GlobalRenderFrameHostId. If size_t count reaches 0 there are no + // remaining audible clients for the associated host id. + base::flat_map<GlobalRenderFrameHostId, size_t> audible_clients_; // Records the last time at which all streams became silent. base::TimeTicks last_became_silent_time_;
diff --git a/content/browser/media/audio_stream_monitor_unittest.cc b/content/browser/media/audio_stream_monitor_unittest.cc index 49090bc..d8e656c 100644 --- a/content/browser/media/audio_stream_monitor_unittest.cc +++ b/content/browser/media/audio_stream_monitor_unittest.cc
@@ -17,6 +17,7 @@ #include "content/browser/web_contents/web_contents_impl.h" #include "content/public/browser/invalidate_type.h" #include "content/public/browser/web_contents_delegate.h" +#include "content/public/test/navigation_simulator.h" #include "content/public/test/test_renderer_host.h" #include "media/base/audio_power_monitor.h" #include "testing/gmock/include/gmock/gmock.h" @@ -400,9 +401,13 @@ TEST_F(AudioStreamMonitorTest, OneAudibleClient) { ExpectNotCurrentlyAudible(); + auto* render_frame_host_impl = + static_cast<RenderFrameHostImpl*>(web_contents()->GetPrimaryMainFrame()); + GlobalRenderFrameHostId host_id = render_frame_host_impl->GetGlobalId(); + ExpectRecentlyAudibleChangeNotification(true); ExpectCurrentlyAudibleChangeNotification(true); - auto registration = monitor_->RegisterAudibleClient(); + auto registration = monitor_->RegisterAudibleClient(host_id); ExpectIsCurrentlyAudible(); ExpectCurrentlyAudibleChangeNotification(false); @@ -413,14 +418,56 @@ TEST_F(AudioStreamMonitorTest, MultipleAudibleClients) { ExpectNotCurrentlyAudible(); + auto* render_frame_host_impl = + static_cast<RenderFrameHostImpl*>(web_contents()->GetPrimaryMainFrame()); + GlobalRenderFrameHostId host_id = render_frame_host_impl->GetGlobalId(); + // Add one client and the tab becomes audible. ExpectRecentlyAudibleChangeNotification(true); ExpectCurrentlyAudibleChangeNotification(true); - auto registration1 = monitor_->RegisterAudibleClient(); + auto registration1 = monitor_->RegisterAudibleClient(host_id); ExpectIsCurrentlyAudible(); // Add another client and the tab remains audible. - auto registration2 = monitor_->RegisterAudibleClient(); + auto registration2 = monitor_->RegisterAudibleClient(host_id); + ExpectIsCurrentlyAudible(); + + // Removes one client and the tab remains audible. + registration1.reset(); + ExpectIsCurrentlyAudible(); + + // Removes another client and the tab is not audible. + ExpectCurrentlyAudibleChangeNotification(false); + registration2.reset(); + ExpectNotCurrentlyAudible(); +} + +TEST_F(AudioStreamMonitorTest, MultipleAudibleClientsMultipleRenderFrames) { + ExpectNotCurrentlyAudible(); + // We need to navigate once before we can add child frames. + const char kDefaultTestUrl[] = "https://google.com/"; + content::NavigationSimulator::NavigateAndCommitFromBrowser( + web_contents(), GURL(kDefaultTestUrl)); + + auto* render_frame_host_tester = + RenderFrameHostTester::For(web_contents()->GetPrimaryMainFrame()); + + auto* render_frame_host_impl_1 = static_cast<RenderFrameHostImpl*>( + render_frame_host_tester->AppendChild("child_1")); + auto* render_frame_host_impl_2 = static_cast<RenderFrameHostImpl*>( + render_frame_host_tester->AppendChild("child_2")); + + GlobalRenderFrameHostId host_id1 = render_frame_host_impl_1->GetGlobalId(); + GlobalRenderFrameHostId host_id2 = render_frame_host_impl_2->GetGlobalId(); + + // Add one client and the tab becomes audible. + ExpectRecentlyAudibleChangeNotification(true); + ExpectCurrentlyAudibleChangeNotification(true); + auto registration1 = monitor_->RegisterAudibleClient(host_id1); + ExpectIsCurrentlyAudible(); + + // Add another client and the tab remains audible. + auto registration2 = monitor_->RegisterAudibleClient(host_id2); ExpectIsCurrentlyAudible(); // Removes one client and the tab remains audible. @@ -437,10 +484,14 @@ StartMonitoring(kRenderProcessId, kRenderFrameId, kStreamId); ExpectNotCurrentlyAudible(); + auto* render_frame_host_impl = + static_cast<RenderFrameHostImpl*>(web_contents()->GetPrimaryMainFrame()); + GlobalRenderFrameHostId host_id = render_frame_host_impl->GetGlobalId(); + // Add one client and the tab becomes audible. ExpectRecentlyAudibleChangeNotification(true); ExpectCurrentlyAudibleChangeNotification(true); - auto registration = monitor_->RegisterAudibleClient(); + auto registration = monitor_->RegisterAudibleClient(host_id); ExpectIsCurrentlyAudible(); // The stream becomes audible and the tab remains audible.
diff --git a/content/browser/media/media_web_contents_observer.cc b/content/browser/media/media_web_contents_observer.cc index 936f262..1402164 100644 --- a/content/browser/media/media_web_contents_observer.cc +++ b/content/browser/media/media_web_contents_observer.cc
@@ -86,6 +86,8 @@ bool IsAudible() const { return has_audio_ && is_playing_ && !muted_; } + GlobalRenderFrameHostId GetHostId() { return id_.frame_routing_id; } + private: void NotifyPlayerStarted() { observer_->web_contents_impl()->MediaStartedPlaying( @@ -500,7 +502,8 @@ media_web_contents_observer_->web_contents_impl()->audio_stream_monitor(); if (should_add_client && !audio_client_registration_) { - audio_client_registration_ = audio_stream_monitor->RegisterAudibleClient(); + audio_client_registration_ = + audio_stream_monitor->RegisterAudibleClient(player_info->GetHostId()); } else if (!should_add_client && audio_client_registration_) { audio_client_registration_.reset(); }
diff --git a/content/browser/media/session/media_session_impl_unittest.cc b/content/browser/media/session/media_session_impl_unittest.cc index 703426f..ec5de0a 100644 --- a/content/browser/media/session/media_session_impl_unittest.cc +++ b/content/browser/media/session/media_session_impl_unittest.cc
@@ -123,11 +123,17 @@ // it. GetMediaSessionService().BindAudioFocusManager( audio_focus_remote_.BindNewPipeAndPassReceiver()); + audio_focus_remote_->SetEnforcementMode( + media_session::mojom::EnforcementMode::kDefault); } void TearDown() override { mock_media_session_service_.reset(); + scoped_feature_list_.Reset(); + audio_focus_remote_->SetEnforcementMode( + media_session::mojom::EnforcementMode::kDefault); + RenderViewHostTestHarness::TearDown(); }
diff --git a/content/browser/renderer_host/input/passthrough_touch_event_queue.cc b/content/browser/renderer_host/input/passthrough_touch_event_queue.cc index 7079e8b..7e626cf7 100644 --- a/content/browser/renderer_host/input/passthrough_touch_event_queue.cc +++ b/content/browser/renderer_host/input/passthrough_touch_event_queue.cc
@@ -287,8 +287,6 @@ if (timeout_handler_) timeout_handler_->StartIfNecessary(*touch); - touch->event.GetModifiableEventLatencyMetadata().dispatched_to_renderer = - base::TimeTicks::Now(); if (wait_for_ack) outstanding_touches_.insert(*touch); client_->SendTouchEventImmediately(*touch);
diff --git a/content/browser/renderer_host/input/render_widget_host_latency_tracker.cc b/content/browser/renderer_host/input/render_widget_host_latency_tracker.cc index f1aa2eb4..e706e1e5 100644 --- a/content/browser/renderer_host/input/render_widget_host_latency_tracker.cc +++ b/content/browser/renderer_host/input/render_widget_host_latency_tracker.cc
@@ -94,8 +94,7 @@ void RenderWidgetHostLatencyTracker::OnInputEvent( const blink::WebInputEvent& event, - LatencyInfo* latency, - ui::EventLatencyMetadata* event_latency_metadata) { + LatencyInfo* latency) { DCHECK(latency); DCHECK_CURRENTLY_ON(BrowserThread::UI); @@ -136,12 +135,9 @@ ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, timestamp_original); } - base::TimeTicks begin_rwh_timestamp = base::TimeTicks::Now(); latency->AddLatencyNumberWithTraceName( ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, - GetTraceNameFromType(event.GetType()), begin_rwh_timestamp); - event_latency_metadata->arrived_in_browser_main_timestamp = - begin_rwh_timestamp; + GetTraceNameFromType(event.GetType())); if (event.GetType() == blink::WebInputEvent::Type::kGestureScrollBegin) { has_seen_first_gesture_scroll_update_ = false;
diff --git a/content/browser/renderer_host/input/render_widget_host_latency_tracker.h b/content/browser/renderer_host/input/render_widget_host_latency_tracker.h index c1cca70..a6acd1f9 100644 --- a/content/browser/renderer_host/input/render_widget_host_latency_tracker.h +++ b/content/browser/renderer_host/input/render_widget_host_latency_tracker.h
@@ -35,8 +35,7 @@ // Called when an event is received by the RenderWidgetHost, prior to // that event being forwarded to the renderer (via the InputRouter). void OnInputEvent(const blink::WebInputEvent& event, - ui::LatencyInfo* latency, - ui::EventLatencyMetadata* event_latency_metadata); + ui::LatencyInfo* latency); // Populates the LatencyInfo with relevant entries for latency tracking, also // terminating latency tracking for events that did not trigger rendering and
diff --git a/content/browser/renderer_host/input/render_widget_host_latency_tracker_unittest.cc b/content/browser/renderer_host/input/render_widget_host_latency_tracker_unittest.cc index 39b431f..38c9e175 100644 --- a/content/browser/renderer_host/input/render_widget_host_latency_tracker_unittest.cc +++ b/content/browser/renderer_host/input/render_widget_host_latency_tracker_unittest.cc
@@ -222,22 +222,16 @@ blink::WebMouseWheelEvent::kPhaseChanged); base::TimeTicks now = base::TimeTicks::Now(); wheel.SetTimeStamp(now); - ui::EventLatencyMetadata event_latency_metadata; ui::LatencyInfo wheel_latency(ui::SourceEventType::WHEEL); wheel_latency.AddLatencyNumberWithTimestamp( ui::INPUT_EVENT_LATENCY_FIRST_SCROLL_UPDATE_ORIGINAL_COMPONENT, now); AddFakeComponentsWithTimeStamp(*tracker(), &wheel_latency, now); AddRenderingScheduledComponent(&wheel_latency, rendering_on_main, now); - tracker()->OnInputEvent(wheel, &wheel_latency, &event_latency_metadata); - base::TimeTicks begin_rwh_timestamp; + tracker()->OnInputEvent(wheel, &wheel_latency); EXPECT_TRUE(wheel_latency.FindLatency( - ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, &begin_rwh_timestamp)); + ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, nullptr)); EXPECT_TRUE(wheel_latency.FindLatency( ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, nullptr)); - EXPECT_FALSE( - event_latency_metadata.arrived_in_browser_main_timestamp.is_null()); - EXPECT_EQ(event_latency_metadata.arrived_in_browser_main_timestamp, - begin_rwh_timestamp); tracker()->OnInputEventAck( wheel, &wheel_latency, blink::mojom::InputEventResultState::kNotConsumed); @@ -293,22 +287,16 @@ blink::WebMouseWheelEvent::kPhaseChanged); base::TimeTicks now = base::TimeTicks::Now(); wheel.SetTimeStamp(now); - ui::EventLatencyMetadata event_latency_metadata; ui::LatencyInfo wheel_latency(ui::SourceEventType::WHEEL); wheel_latency.AddLatencyNumberWithTimestamp( ui::INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT, now); AddFakeComponentsWithTimeStamp(*tracker(), &wheel_latency, now); AddRenderingScheduledComponent(&wheel_latency, rendering_on_main, now); - tracker()->OnInputEvent(wheel, &wheel_latency, &event_latency_metadata); - base::TimeTicks begin_rwh_timestamp; + tracker()->OnInputEvent(wheel, &wheel_latency); EXPECT_TRUE(wheel_latency.FindLatency( - ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, &begin_rwh_timestamp)); + ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, nullptr)); EXPECT_TRUE(wheel_latency.FindLatency( ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, nullptr)); - EXPECT_FALSE( - event_latency_metadata.arrived_in_browser_main_timestamp.is_null()); - EXPECT_EQ(event_latency_metadata.arrived_in_browser_main_timestamp, - begin_rwh_timestamp); tracker()->OnInputEventAck( wheel, &wheel_latency, blink::mojom::InputEventResultState::kNotConsumed); @@ -362,19 +350,13 @@ base::TimeTicks now = base::TimeTicks::Now(); scroll.SetTimeStamp(now); ui::LatencyInfo scroll_latency(ui::SourceEventType::INERTIAL); - ui::EventLatencyMetadata event_latency_metadata; AddFakeComponentsWithTimeStamp(*tracker(), &scroll_latency, now); AddRenderingScheduledComponent(&scroll_latency, rendering_on_main, now); - tracker()->OnInputEvent(scroll, &scroll_latency, &event_latency_metadata); - base::TimeTicks begin_rwh_timestamp; + tracker()->OnInputEvent(scroll, &scroll_latency); EXPECT_TRUE(scroll_latency.FindLatency( - ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, &begin_rwh_timestamp)); + ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, nullptr)); EXPECT_TRUE(scroll_latency.FindLatency( ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, nullptr)); - EXPECT_FALSE( - event_latency_metadata.arrived_in_browser_main_timestamp.is_null()); - EXPECT_EQ(event_latency_metadata.arrived_in_browser_main_timestamp, - begin_rwh_timestamp); tracker()->OnInputEventAck( scroll, &scroll_latency, blink::mojom::InputEventResultState::kNotConsumed); @@ -414,19 +396,13 @@ base::TimeTicks now = base::TimeTicks::Now(); scroll.SetTimeStamp(now); ui::LatencyInfo scroll_latency; - ui::EventLatencyMetadata event_latency_metadata; AddFakeComponentsWithTimeStamp(*tracker(), &scroll_latency, now); AddRenderingScheduledComponent(&scroll_latency, rendering_on_main, now); - tracker()->OnInputEvent(scroll, &scroll_latency, &event_latency_metadata); - base::TimeTicks begin_rwh_timestamp; + tracker()->OnInputEvent(scroll, &scroll_latency); EXPECT_TRUE(scroll_latency.FindLatency( - ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, &begin_rwh_timestamp)); + ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, nullptr)); EXPECT_TRUE(scroll_latency.FindLatency( ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, nullptr)); - EXPECT_FALSE( - event_latency_metadata.arrived_in_browser_main_timestamp.is_null()); - EXPECT_EQ(event_latency_metadata.arrived_in_browser_main_timestamp, - begin_rwh_timestamp); tracker()->OnInputEventAck( scroll, &scroll_latency, blink::mojom::InputEventResultState::kNotConsumed); @@ -436,23 +412,17 @@ blink::SyntheticWebTouchEvent touch; touch.PressPoint(0, 0); touch.PressPoint(1, 1); - ui::EventLatencyMetadata event_latency_metadata; ui::LatencyInfo touch_latency(ui::SourceEventType::TOUCH); base::TimeTicks now = base::TimeTicks::Now(); touch_latency.AddLatencyNumberWithTimestamp( ui::INPUT_EVENT_LATENCY_FIRST_SCROLL_UPDATE_ORIGINAL_COMPONENT, now); AddFakeComponentsWithTimeStamp(*tracker(), &touch_latency, now); AddRenderingScheduledComponent(&touch_latency, rendering_on_main, now); - tracker()->OnInputEvent(touch, &touch_latency, &event_latency_metadata); - base::TimeTicks begin_rwh_timestamp; + tracker()->OnInputEvent(touch, &touch_latency); EXPECT_TRUE(touch_latency.FindLatency( - ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, &begin_rwh_timestamp)); + ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, nullptr)); EXPECT_TRUE(touch_latency.FindLatency( ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, nullptr)); - EXPECT_FALSE( - event_latency_metadata.arrived_in_browser_main_timestamp.is_null()); - EXPECT_EQ(event_latency_metadata.arrived_in_browser_main_timestamp, - begin_rwh_timestamp); tracker()->OnInputEventAck( touch, &touch_latency, blink::mojom::InputEventResultState::kNotConsumed); @@ -506,10 +476,9 @@ base::TimeTicks now = base::TimeTicks::Now(); scroll.SetTimeStamp(now); ui::LatencyInfo scroll_latency; - ui::EventLatencyMetadata event_latency_metadata; AddFakeComponentsWithTimeStamp(*tracker(), &scroll_latency, now); AddRenderingScheduledComponent(&scroll_latency, rendering_on_main, now); - tracker()->OnInputEvent(scroll, &scroll_latency, &event_latency_metadata); + tracker()->OnInputEvent(scroll, &scroll_latency); EXPECT_TRUE(scroll_latency.FindLatency( ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, nullptr)); EXPECT_TRUE(scroll_latency.FindLatency( @@ -524,22 +493,16 @@ touch.PressPoint(0, 0); touch.PressPoint(1, 1); ui::LatencyInfo touch_latency(ui::SourceEventType::TOUCH); - ui::EventLatencyMetadata event_latency_metadata; base::TimeTicks now = base::TimeTicks::Now(); touch_latency.AddLatencyNumberWithTimestamp( ui::INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT, now); AddFakeComponentsWithTimeStamp(*tracker(), &touch_latency, now); AddRenderingScheduledComponent(&touch_latency, rendering_on_main, now); - tracker()->OnInputEvent(touch, &touch_latency, &event_latency_metadata); - base::TimeTicks begin_rwh_timestamp; + tracker()->OnInputEvent(touch, &touch_latency); EXPECT_TRUE(touch_latency.FindLatency( - ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, &begin_rwh_timestamp)); + ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, nullptr)); EXPECT_TRUE(touch_latency.FindLatency( ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, nullptr)); - EXPECT_FALSE( - event_latency_metadata.arrived_in_browser_main_timestamp.is_null()); - EXPECT_EQ(event_latency_metadata.arrived_in_browser_main_timestamp, - begin_rwh_timestamp); tracker()->OnInputEventAck( touch, &touch_latency, blink::mojom::InputEventResultState::kNotConsumed); @@ -595,21 +558,14 @@ const bool on_main[] = {true, false}; for (bool on_main_thread : on_main) { ui::LatencyInfo scrollbar_latency(ui::SourceEventType::SCROLLBAR); - ui::EventLatencyMetadata event_latency_metadata; AddFakeComponentsWithTimeStamp(*tracker(), &scrollbar_latency, now); scrollbar_latency.AddLatencyNumberWithTimestamp(component, now); AddRenderingScheduledComponent(&scrollbar_latency, on_main_thread, now); - tracker()->OnInputEvent(mouse_move, &scrollbar_latency, - &event_latency_metadata); - base::TimeTicks begin_rwh_timestamp; + tracker()->OnInputEvent(mouse_move, &scrollbar_latency); EXPECT_TRUE(scrollbar_latency.FindLatency( - ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, &begin_rwh_timestamp)); + ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, nullptr)); EXPECT_TRUE(scrollbar_latency.FindLatency( ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, nullptr)); - EXPECT_FALSE( - event_latency_metadata.arrived_in_browser_main_timestamp.is_null()); - EXPECT_EQ(event_latency_metadata.arrived_in_browser_main_timestamp, - begin_rwh_timestamp); tracker()->OnInputEventAck( mouse_move, &scrollbar_latency, blink::mojom::InputEventResultState::kNotConsumed); @@ -638,14 +594,13 @@ base::TimeTicks now = base::TimeTicks::Now(); scroll.SetTimeStamp(now); ui::LatencyInfo scroll_latency; - ui::EventLatencyMetadata event_latency_metadata; scroll_latency.set_source_event_type( source_device == blink::WebGestureDevice::kTouchscreen ? ui::SourceEventType::TOUCH : ui::SourceEventType::WHEEL); AddFakeComponentsWithTimeStamp(*tracker(), &scroll_latency, now); AddRenderingScheduledComponent(&scroll_latency, rendering_on_main, now); - tracker()->OnInputEvent(scroll, &scroll_latency, &event_latency_metadata); + tracker()->OnInputEvent(scroll, &scroll_latency); tracker()->OnInputEventAck( scroll, &scroll_latency, blink::mojom::InputEventResultState::kNoConsumerExists); @@ -658,18 +613,11 @@ auto scroll_begin = blink::SyntheticWebGestureEventBuilder::BuildScrollBegin( 5, -5, blink::WebGestureDevice::kTouchscreen); ui::LatencyInfo scroll_latency; - ui::EventLatencyMetadata event_latency_metadata; scroll_latency.AddLatencyNumber(ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT); - tracker()->OnInputEvent(scroll_begin, &scroll_latency, - &event_latency_metadata); - base::TimeTicks begin_rwh_timestamp; + tracker()->OnInputEvent(scroll_begin, &scroll_latency); EXPECT_TRUE(scroll_latency.FindLatency( - ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, &begin_rwh_timestamp)); + ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, nullptr)); EXPECT_EQ(2U, scroll_latency.latency_components().size()); - EXPECT_FALSE( - event_latency_metadata.arrived_in_browser_main_timestamp.is_null()); - EXPECT_EQ(event_latency_metadata.arrived_in_browser_main_timestamp, - begin_rwh_timestamp); // The first GestureScrollUpdate should be provided with // INPUT_EVENT_LATENCY_FIRST_SCROLL_UPDATE_ORIGINAL_COMPONENT. @@ -677,22 +625,15 @@ blink::SyntheticWebGestureEventBuilder::BuildScrollUpdate( 5.f, -5.f, 0, blink::WebGestureDevice::kTouchscreen); scroll_latency = ui::LatencyInfo(); - event_latency_metadata = ui::EventLatencyMetadata(); scroll_latency.AddLatencyNumber(ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT); - tracker()->OnInputEvent(first_scroll_update, &scroll_latency, - &event_latency_metadata); - begin_rwh_timestamp = base::TimeTicks(); + tracker()->OnInputEvent(first_scroll_update, &scroll_latency); EXPECT_TRUE(scroll_latency.FindLatency( - ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, &begin_rwh_timestamp)); + ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, nullptr)); EXPECT_TRUE(scroll_latency.FindLatency( ui::INPUT_EVENT_LATENCY_FIRST_SCROLL_UPDATE_ORIGINAL_COMPONENT, nullptr)); EXPECT_FALSE(scroll_latency.FindLatency( ui::INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT, nullptr)); EXPECT_EQ(3U, scroll_latency.latency_components().size()); - EXPECT_FALSE( - event_latency_metadata.arrived_in_browser_main_timestamp.is_null()); - EXPECT_EQ(event_latency_metadata.arrived_in_browser_main_timestamp, - begin_rwh_timestamp); // Subsequent GestureScrollUpdates should be provided with // INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT. @@ -700,22 +641,15 @@ blink::SyntheticWebGestureEventBuilder::BuildScrollUpdate( -5.f, 5.f, 0, blink::WebGestureDevice::kTouchscreen); scroll_latency = ui::LatencyInfo(); - event_latency_metadata = ui::EventLatencyMetadata(); scroll_latency.AddLatencyNumber(ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT); - tracker()->OnInputEvent(scroll_update, &scroll_latency, - &event_latency_metadata); - begin_rwh_timestamp = base::TimeTicks(); + tracker()->OnInputEvent(scroll_update, &scroll_latency); EXPECT_TRUE(scroll_latency.FindLatency( - ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, &begin_rwh_timestamp)); + ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, nullptr)); EXPECT_FALSE(scroll_latency.FindLatency( ui::INPUT_EVENT_LATENCY_FIRST_SCROLL_UPDATE_ORIGINAL_COMPONENT, nullptr)); EXPECT_TRUE(scroll_latency.FindLatency( ui::INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT, nullptr)); EXPECT_EQ(3U, scroll_latency.latency_components().size()); - EXPECT_FALSE( - event_latency_metadata.arrived_in_browser_main_timestamp.is_null()); - EXPECT_EQ(event_latency_metadata.arrived_in_browser_main_timestamp, - begin_rwh_timestamp); } TEST_F(RenderWidgetHostLatencyTrackerTest, KeyEndToEndLatency) {
diff --git a/content/browser/renderer_host/input/synthetic_gesture.cc b/content/browser/renderer_host/input/synthetic_gesture.cc index 6f956504c..017e821 100644 --- a/content/browser/renderer_host/input/synthetic_gesture.cc +++ b/content/browser/renderer_host/input/synthetic_gesture.cc
@@ -63,7 +63,7 @@ void SyntheticGesture::DidQueue( base::WeakPtr<SyntheticGestureController> controller) { - DCHECK(controller); + CHECK(controller); dispatching_controller_ = controller; }
diff --git a/content/browser/renderer_host/input/synthetic_pointer_action.cc b/content/browser/renderer_host/input/synthetic_pointer_action.cc index daf594e9..07ca80ee 100644 --- a/content/browser/renderer_host/input/synthetic_pointer_action.cc +++ b/content/browser/renderer_host/input/synthetic_pointer_action.cc
@@ -18,7 +18,13 @@ SyntheticGesture::Result SyntheticPointerAction::ForwardInputEvents( const base::TimeTicks& timestamp, SyntheticGestureTarget* target) { - DCHECK(dispatching_controller_); + CHECK(dispatching_controller_); + + // Keep this on the stack so we can check if the forwarded event caused the + // deletion of the controller (which owns `this`). + base::WeakPtr<SyntheticGestureController> weak_controller = + dispatching_controller_; + if (state_ == GestureState::UNINITIALIZED) { gesture_source_type_ = params_.gesture_source_type; if (gesture_source_type_ == @@ -40,7 +46,7 @@ return SyntheticGesture::GESTURE_SOURCE_TYPE_NOT_IMPLEMENTED; GestureState state = ForwardTouchOrMouseInputEvents(timestamp, target); - if (!dispatching_controller_) { + if (!weak_controller) { // A pointer gesture can cause the controller (and therefore `this`) to be // synchronously deleted (e.g. clicking tab-close). Return immediately in // this case. @@ -83,6 +89,12 @@ SyntheticPointerActionListParams::ParamList& param_list = params_.params[num_actions_dispatched_]; + // CAUTION: Forwarding a pointer input can cause `this` to be deleted. + // Keep this on the stack so we can check if the forwarded event caused the + // deletion of the controller (which owns `this`). + base::WeakPtr<SyntheticGestureController> weak_controller = + dispatching_controller_; + for (const SyntheticPointerActionParams& param : param_list) { if (!PointerDriver()->UserInputCheck(param)) { return GestureState::INVALID; @@ -123,8 +135,7 @@ param.timestamp().is_null() ? timestamp : param.timestamp(); PointerDriver()->DispatchEvent(target, dispatch_timestamp); - // CAUTION: Forwarding a pointer input can cause `this` to be deleted. - if (!dispatching_controller_) { + if (!weak_controller) { // Return value is unused because the caller returns immediately in this // condition as well. return GestureState::DONE;
diff --git a/content/browser/renderer_host/input/synthetic_smooth_move_gesture.cc b/content/browser/renderer_host/input/synthetic_smooth_move_gesture.cc index 5e2ecb96..bce6260 100644 --- a/content/browser/renderer_host/input/synthetic_smooth_move_gesture.cc +++ b/content/browser/renderer_host/input/synthetic_smooth_move_gesture.cc
@@ -57,7 +57,13 @@ SyntheticGesture::Result SyntheticSmoothMoveGesture::ForwardInputEvents( const base::TimeTicks& timestamp, SyntheticGestureTarget* target) { - DCHECK(dispatching_controller_); + CHECK(dispatching_controller_); + + // Keep this on the stack so we can check if the forwarded event caused the + // deletion of the controller (which owns `this`). + base::WeakPtr<SyntheticGestureController> weak_controller = + dispatching_controller_; + if (state_ == SETUP) { state_ = STARTED; current_move_segment_ = -1; @@ -82,12 +88,12 @@ case SyntheticSmoothMoveGestureParams::MOUSE_WHEEL_INPUT: ForwardMouseWheelInputEvents(timestamp, target); // A mousewheel should not be able to close the WebContents. - DCHECK(dispatching_controller_); + CHECK(weak_controller); break; default: return SyntheticGesture::GESTURE_SOURCE_TYPE_NOT_IMPLEMENTED; } - if (!dispatching_controller_) { + if (!weak_controller) { // A pointer gesture can cause the controller (and therefore `this`) to be // synchronously deleted (e.g. clicking tab-close). Return immediately in // this case. @@ -108,6 +114,10 @@ void SyntheticSmoothMoveGesture::ForwardTouchInputEvents( const base::TimeTicks& timestamp, SyntheticGestureTarget* target) { + // Keep this on the stack so we can check if the forwarded event caused the + // deletion of the controller (which owns `this`). + base::WeakPtr<SyntheticGestureController> weak_controller = + dispatching_controller_; switch (state_) { case STARTED: if (MoveIsNoOp()) { @@ -118,7 +128,7 @@ AddTouchSlopToFirstDistance(target); ComputeNextMoveSegment(); PressPoint(target, timestamp); - if (!dispatching_controller_) { + if (!weak_controller) { return; } state_ = MOVING; @@ -127,6 +137,8 @@ base::TimeTicks event_timestamp = ClampTimestamp(timestamp); gfx::Vector2dF delta = GetPositionDeltaAtTime(event_timestamp); MovePoint(target, delta, event_timestamp); + // A move should never be able to cause deletion of the controller. + CHECK(weak_controller); if (FinishedCurrentMoveSegment(event_timestamp)) { if (!IsLastMoveSegment()) { @@ -137,7 +149,7 @@ state_ = STOPPING; } else { ReleasePoint(target, event_timestamp); - if (!dispatching_controller_) { + if (!weak_controller) { return; } state_ = DONE; @@ -150,7 +162,7 @@ base::TimeTicks event_timestamp = current_move_segment_stop_time_ + target->PointerAssumedStoppedTime(); ReleasePoint(target, event_timestamp); - if (!dispatching_controller_) { + if (!weak_controller) { return; } state_ = DONE; @@ -234,6 +246,10 @@ void SyntheticSmoothMoveGesture::ForwardMouseClickInputEvents( const base::TimeTicks& timestamp, SyntheticGestureTarget* target) { + // Keep this on the stack so we can check if the forwarded event caused the + // deletion of the controller (which owns `this`). + base::WeakPtr<SyntheticGestureController> weak_controller = + dispatching_controller_; switch (state_) { case STARTED: if (MoveIsNoOp()) { @@ -242,7 +258,7 @@ } ComputeNextMoveSegment(); PressPoint(target, timestamp); - if (!dispatching_controller_) { + if (!weak_controller) { return; } state_ = MOVING; @@ -259,7 +275,7 @@ ComputeNextMoveSegment(); } else { ReleasePoint(target, event_timestamp); - if (!dispatching_controller_) { + if (!weak_controller) { return; } state_ = DONE;
diff --git a/content/browser/renderer_host/input/synthetic_tap_gesture.cc b/content/browser/renderer_host/input/synthetic_tap_gesture.cc index 7618a7d..9513d4e 100644 --- a/content/browser/renderer_host/input/synthetic_tap_gesture.cc +++ b/content/browser/renderer_host/input/synthetic_tap_gesture.cc
@@ -27,7 +27,12 @@ SyntheticGesture::Result SyntheticTapGesture::ForwardInputEvents( const base::TimeTicks& timestamp, SyntheticGestureTarget* target) { - DCHECK(dispatching_controller_); + CHECK(dispatching_controller_); + // Keep this on the stack so we can check if the forwarded event caused the + // deletion of the controller (which owns `this`). + base::WeakPtr<SyntheticGestureController> weak_controller = + dispatching_controller_; + if (state_ == SETUP) { gesture_source_type_ = params_.gesture_source_type; if (gesture_source_type_ == @@ -48,7 +53,7 @@ gesture_source_type_ == content::mojom::GestureSourceType::kMouseInput) { ForwardTouchOrMouseInputEvents(timestamp, target); - if (!dispatching_controller_) { + if (!weak_controller) { // ForwardTouchOrMouseInputEvents may cause the controller (and therefore // `this`) to be synchronously deleted (e.g. tapping tab-close). Return // immediately in this case. @@ -76,19 +81,23 @@ // CAUTION: Dispatching press/release events can cause `this` to be deleted. void SyntheticTapGesture::ForwardTouchOrMouseInputEvents( const base::TimeTicks& timestamp, SyntheticGestureTarget* target) { + // Keep this on the stack so we can check if the forwarded event caused the + // deletion of the controller (which owns `this`). + base::WeakPtr<SyntheticGestureController> weak_controller = + dispatching_controller_; switch (state_) { case PRESS: synthetic_pointer_driver_->Press(params_.position.x(), params_.position.y()); synthetic_pointer_driver_->DispatchEvent(target, timestamp); - if (!dispatching_controller_) { + if (!weak_controller) { return; } // Release immediately if duration is 0. if (params_.duration_ms == 0) { synthetic_pointer_driver_->Release(); synthetic_pointer_driver_->DispatchEvent(target, timestamp); - if (!dispatching_controller_) { + if (!weak_controller) { return; } state_ = DONE; @@ -102,7 +111,7 @@ synthetic_pointer_driver_->Release(); synthetic_pointer_driver_->DispatchEvent(target, start_time_ + GetDuration()); - if (!dispatching_controller_) { + if (!weak_controller) { return; } state_ = DONE;
diff --git a/content/browser/renderer_host/input/synthetic_touchpad_pinch_gesture.cc b/content/browser/renderer_host/input/synthetic_touchpad_pinch_gesture.cc index 342b5ab7..294ab64b 100644 --- a/content/browser/renderer_host/input/synthetic_touchpad_pinch_gesture.cc +++ b/content/browser/renderer_host/input/synthetic_touchpad_pinch_gesture.cc
@@ -39,7 +39,11 @@ SyntheticGesture::Result SyntheticTouchpadPinchGesture::ForwardInputEvents( const base::TimeTicks& timestamp, SyntheticGestureTarget* target) { - DCHECK(dispatching_controller_); + CHECK(dispatching_controller_); + // Keep this on the stack so we can check if the forwarded event caused the + // deletion of the controller (which owns `this`). + base::WeakPtr<SyntheticGestureController> weak_controller = + dispatching_controller_; if (state_ == SETUP) { gesture_source_type_ = params_.gesture_source_type; if (gesture_source_type_ == @@ -56,7 +60,7 @@ ForwardGestureEvents(timestamp, target); // A pinch gesture cannot cause `this` to be destroyed. - DCHECK(dispatching_controller_); + CHECK(weak_controller); } else { // Touch input should be using SyntheticTouchscreenPinchGesture. return SyntheticGesture::GESTURE_SOURCE_TYPE_NOT_IMPLEMENTED;
diff --git a/content/browser/renderer_host/input/synthetic_touchscreen_pinch_gesture.cc b/content/browser/renderer_host/input/synthetic_touchscreen_pinch_gesture.cc index dc5011b..31d08507 100644 --- a/content/browser/renderer_host/input/synthetic_touchscreen_pinch_gesture.cc +++ b/content/browser/renderer_host/input/synthetic_touchscreen_pinch_gesture.cc
@@ -37,7 +37,11 @@ SyntheticGesture::Result SyntheticTouchscreenPinchGesture::ForwardInputEvents( const base::TimeTicks& timestamp, SyntheticGestureTarget* target) { - DCHECK(dispatching_controller_); + CHECK(dispatching_controller_); + // Keep this on the stack so we can check if the forwarded event caused the + // deletion of the controller (which owns `this`). + base::WeakPtr<SyntheticGestureController> weak_controller = + dispatching_controller_; if (state_ == SETUP) { gesture_source_type_ = params_.gesture_source_type; if (gesture_source_type_ == @@ -58,7 +62,7 @@ if (gesture_source_type_ == content::mojom::GestureSourceType::kTouchInput) { ForwardTouchInputEvents(timestamp, target); // A pinch gesture cannot cause `this` to be destroyed. - DCHECK(dispatching_controller_); + CHECK(weak_controller); } else { return SyntheticGesture::GESTURE_SOURCE_TYPE_NOT_IMPLEMENTED; }
diff --git a/content/browser/renderer_host/media/fuchsia_media_codec_provider_impl.cc b/content/browser/renderer_host/media/fuchsia_media_codec_provider_impl.cc index 029b852..61b4927 100644 --- a/content/browser/renderer_host/media/fuchsia_media_codec_provider_impl.cc +++ b/content/browser/renderer_host/media/fuchsia_media_codec_provider_impl.cc
@@ -4,6 +4,7 @@ #include "content/browser/renderer_host/media/fuchsia_media_codec_provider_impl.h" +#include <fuchsia/media/cpp/fidl.h> #include <fuchsia/mediacodec/cpp/fidl.h> #include <lib/fit/function.h> #include <lib/sys/cpp/component_context.h> @@ -11,8 +12,8 @@ #include "base/command_line.h" #include "base/fuchsia/fuchsia_logging.h" #include "base/fuchsia/process_context.h" -#include "media/base/media_switches.h" #include "media/base/supported_video_decoder_config.h" +#include "media/base/video_codecs.h" #include "third_party/abseil-cpp/absl/types/optional.h" namespace content { @@ -47,38 +48,110 @@ return absl::nullopt; } -// fuchsia::mediacodec::CodecDescription does not provide enough codec info -// to determine if a media::VideoDecoderConfig is supported. The constant and -// the helper function below is to make a safe assumption that converts the type -// to media::SupportedVideoDecoderConfigs. -// TODO(fxbug.dev/85214): Remove the constant and the helper function below -// after more details are added to mediacodec.CodecDescription. -constexpr gfx::Size kFuchsiaDecodeSizeMax(1920, 1080); // 1080p +media::VideoCodecProfile ConvertToVideoCodecProfile( + const fuchsia::media::CodecProfile& profile) { + switch (profile) { + case fuchsia::media::CodecProfile::H264PROFILE_BASELINE: + return media::VideoCodecProfile::H264PROFILE_BASELINE; + case fuchsia::media::CodecProfile::H264PROFILE_MAIN: + return media::VideoCodecProfile::H264PROFILE_MAIN; + case fuchsia::media::CodecProfile::H264PROFILE_EXTENDED: + return media::VideoCodecProfile::H264PROFILE_EXTENDED; + case fuchsia::media::CodecProfile::H264PROFILE_HIGH: + return media::VideoCodecProfile::H264PROFILE_HIGH; + case fuchsia::media::CodecProfile::H264PROFILE_HIGH10PROFILE: + return media::VideoCodecProfile::H264PROFILE_HIGH10PROFILE; + case fuchsia::media::CodecProfile::H264PROFILE_HIGH422PROFILE: + return media::VideoCodecProfile::H264PROFILE_HIGH422PROFILE; + case fuchsia::media::CodecProfile::H264PROFILE_HIGH444PREDICTIVEPROFILE: + return media::VideoCodecProfile::H264PROFILE_HIGH444PREDICTIVEPROFILE; + case fuchsia::media::CodecProfile::H264PROFILE_SCALABLEBASELINE: + return media::VideoCodecProfile::H264PROFILE_SCALABLEBASELINE; + case fuchsia::media::CodecProfile::H264PROFILE_SCALABLEHIGH: + return media::VideoCodecProfile::H264PROFILE_SCALABLEHIGH; + case fuchsia::media::CodecProfile::H264PROFILE_STEREOHIGH: + return media::VideoCodecProfile::H264PROFILE_STEREOHIGH; + case fuchsia::media::CodecProfile::H264PROFILE_MULTIVIEWHIGH: + return media::VideoCodecProfile::H264PROFILE_MULTIVIEWHIGH; + case fuchsia::media::CodecProfile::VP8PROFILE_ANY: + return media::VideoCodecProfile::VP8PROFILE_ANY; + case fuchsia::media::CodecProfile::VP9PROFILE_PROFILE0: + return media::VideoCodecProfile::VP9PROFILE_PROFILE0; + case fuchsia::media::CodecProfile::VP9PROFILE_PROFILE1: + return media::VideoCodecProfile::VP9PROFILE_PROFILE1; + case fuchsia::media::CodecProfile::VP9PROFILE_PROFILE2: + return media::VideoCodecProfile::VP9PROFILE_PROFILE2; + case fuchsia::media::CodecProfile::VP9PROFILE_PROFILE3: + return media::VideoCodecProfile::VP9PROFILE_PROFILE3; + case fuchsia::media::CodecProfile::HEVCPROFILE_MAIN: + return media::VideoCodecProfile::HEVCPROFILE_MAIN; + case fuchsia::media::CodecProfile::HEVCPROFILE_MAIN10: + return media::VideoCodecProfile::HEVCPROFILE_MAIN10; + case fuchsia::media::CodecProfile::HEVCPROFILE_MAIN_STILL_PICTURE: + return media::VideoCodecProfile::HEVCPROFILE_MAIN_STILL_PICTURE; + default: + NOTIMPLEMENTED() << "Unknown codec profile: " << profile; + return media::VideoCodecProfile::VIDEO_CODEC_PROFILE_UNKNOWN; + } +} + media::SupportedVideoDecoderConfigs GetSupportedVideoDecoderConfigsForCodecList( - const std::vector<fuchsia::mediacodec::CodecDescription>& codec_list) { + const std::vector<fuchsia::mediacodec::DetailedCodecDescription>& + detailed_codec_list) { media::SupportedVideoDecoderConfigs configs; - for (const auto& codec_description : codec_list) { - if (codec_description.mime_type == "video/h264" || - codec_description.mime_type == "video/h264-muti") { - configs.emplace_back(media::VideoCodecProfile::H264PROFILE_MIN, - media::VideoCodecProfile::H264PROFILE_STEREOHIGH, - media::kDefaultSwDecodeSizeMin, - kFuchsiaDecodeSizeMax, codec_description.is_hw, - false); - } else if (codec_description.mime_type == "video/vp8") { - configs.emplace_back(media::VideoCodecProfile::VP8PROFILE_MIN, - media::VideoCodecProfile::VP8PROFILE_MAX, - media::kDefaultSwDecodeSizeMin, - kFuchsiaDecodeSizeMax, codec_description.is_hw, - false); - } else if (codec_description.mime_type == "video/vp9") { - // Only SD profiles are supported for VP9. HDR profiles (2 and 3) are not - // supported. - configs.emplace_back(media::VideoCodecProfile::VP9PROFILE_MIN, - media::VideoCodecProfile::VP9PROFILE_PROFILE1, - media::kDefaultSwDecodeSizeMin, - kFuchsiaDecodeSizeMax, codec_description.is_hw, - false); + + for (const auto& codec_description : detailed_codec_list) { + if (!codec_description.has_codec_type() || !codec_description.has_is_hw() || + !codec_description.has_mime_type() || + !codec_description.has_profile_descriptions()) { + LOG(WARNING) << "Missing required fields when parsing the " + "DetailedCodecDescription. Skipped."; + continue; + } + + if ( + // Only use platform codecs that are accelerated. + !codec_description.is_hw() || + // Exclude non-video codecs. + codec_description.mime_type().find("video") != 0 || + // Exclude non-decoder codecs. + codec_description.codec_type() != + fuchsia::mediacodec::CodecType::DECODER || + !codec_description.profile_descriptions() + .is_decoder_profile_descriptions()) { + continue; + } + + for (const auto& profile_description : + codec_description.profile_descriptions() + .decoder_profile_descriptions()) { + if (!profile_description.has_profile() || + !profile_description.has_min_image_size() || + !profile_description.has_max_image_size()) { + LOG(WARNING) << "Missing required fields when parsing the " + "DecoderProfileDescription. Skipped."; + continue; + } + + const auto video_codec_profile = + ConvertToVideoCodecProfile(profile_description.profile()); + if (video_codec_profile == + media::VideoCodecProfile::VIDEO_CODEC_PROFILE_UNKNOWN) { + continue; + } + + configs.emplace_back( + video_codec_profile, video_codec_profile, + gfx::Size(profile_description.min_image_size().width, + profile_description.min_image_size().height), + gfx::Size(profile_description.max_image_size().width, + profile_description.max_image_size().height), + profile_description.has_allow_encryption() + ? profile_description.allow_encryption() + : false, + profile_description.has_require_encryption() + ? profile_description.require_encryption() + : false); } } @@ -170,8 +243,8 @@ codec_factory_.set_error_handler(fit::bind_member( this, &FuchsiaMediaCodecProviderImpl::OnCodecFactoryDisconnected)); - codec_factory_.events().OnCodecList = - fit::bind_member(this, &FuchsiaMediaCodecProviderImpl::OnCodecList); + codec_factory_->GetDetailedCodecDescriptions(fit::bind_member( + this, &FuchsiaMediaCodecProviderImpl::OnGetDetailedCodecDescriptions)); } void FuchsiaMediaCodecProviderImpl::OnCodecFactoryDisconnected( @@ -182,24 +255,26 @@ RunPendingGetSupportedVideoDecoderConfigsCallbacks(); } -void FuchsiaMediaCodecProviderImpl::OnCodecList( - std::vector<::fuchsia::mediacodec::CodecDescription> codec_list) { - supported_video_decoder_configs_.emplace( - GetSupportedVideoDecoderConfigsForCodecList(codec_list)); +void FuchsiaMediaCodecProviderImpl::OnGetDetailedCodecDescriptions( + fuchsia::mediacodec::CodecFactoryGetDetailedCodecDescriptionsResponse + response) { + if (response.has_codecs()) { + supported_video_decoder_configs_.emplace( + GetSupportedVideoDecoderConfigsForCodecList(response.codecs())); + } RunPendingGetSupportedVideoDecoderConfigsCallbacks(); } void FuchsiaMediaCodecProviderImpl:: RunPendingGetSupportedVideoDecoderConfigsCallbacks() { - media::SupportedVideoDecoderConfigs configs = {}; - if (supported_video_decoder_configs_) { - configs = supported_video_decoder_configs_.value(); - } + media::SupportedVideoDecoderConfigs configs = + supported_video_decoder_configs_.value_or( + std::vector<media::SupportedVideoDecoderConfig>{}); - for (auto& callback : pending_get_supported_vd_configs_callbacks_) { + for (auto& callback : + std::exchange(pending_get_supported_vd_configs_callbacks_, {})) { std::move(callback).Run(configs); } - pending_get_supported_vd_configs_callbacks_.clear(); } } // namespace content
diff --git a/content/browser/renderer_host/media/fuchsia_media_codec_provider_impl.h b/content/browser/renderer_host/media/fuchsia_media_codec_provider_impl.h index c83f706..a93e184 100644 --- a/content/browser/renderer_host/media/fuchsia_media_codec_provider_impl.h +++ b/content/browser/renderer_host/media/fuchsia_media_codec_provider_impl.h
@@ -48,8 +48,8 @@ // Handlers for events on the codec factory API channel. void OnCodecFactoryDisconnected(zx_status_t status); - void OnCodecList( - std::vector<fuchsia::mediacodec::CodecDescription> codec_list); + void OnGetDetailedCodecDescriptions( + fuchsia::mediacodec::CodecFactoryGetDetailedCodecDescriptionsResponse); void RunPendingGetSupportedVideoDecoderConfigsCallbacks();
diff --git a/content/browser/renderer_host/media/fuchsia_media_codec_provider_impl_unittest.cc b/content/browser/renderer_host/media/fuchsia_media_codec_provider_impl_unittest.cc index 9d691261e..4ac2e1e 100644 --- a/content/browser/renderer_host/media/fuchsia_media_codec_provider_impl_unittest.cc +++ b/content/browser/renderer_host/media/fuchsia_media_codec_provider_impl_unittest.cc
@@ -4,10 +4,13 @@ #include "content/browser/renderer_host/media/fuchsia_media_codec_provider_impl.h" +#include <fuchsia/media/cpp/fidl.h> +#include <fuchsia/mediacodec/cpp/fidl.h> #include <fuchsia/mediacodec/cpp/fidl_test_base.h> #include <lib/fidl/cpp/binding.h> #include <algorithm> #include <memory> +#include <vector> #include "base/fuchsia/scoped_service_binding.h" #include "base/fuchsia/test_component_context_for_process.h" @@ -23,70 +26,303 @@ namespace { -static const gfx::Size kCodedSize(320, 240); +static const gfx::Size k320CodecSize(568, 320); +static const gfx::Size k1080CodecSize(1920, 1080); +static const gfx::Size k4kCodecSize(3840, 2160); static const gfx::Rect kVisibleRect(320, 240); static const gfx::Size kNaturalSize(320, 240); -const media::VideoDecoderConfig kH264BaseConfig( +// Encrypted VideoDecoderConfig +const media::VideoDecoderConfig kEncryptedH264Base1080Config( media::VideoCodec::kH264, media::H264PROFILE_MIN, media::VideoDecoderConfig::AlphaMode::kIsOpaque, media::VideoColorSpace(), media::kNoTransformation, - kCodedSize, + k1080CodecSize, kVisibleRect, kNaturalSize, media::EmptyExtraData(), - media::EncryptionScheme::kUnencrypted); + media::EncryptionScheme::kCbcs); -const media::VideoDecoderConfig kVP9BaseConfig( +const media::VideoDecoderConfig kEncryptedVP9BaseConfig( media::VideoCodec::kVP9, media::VP9PROFILE_MIN, media::VideoDecoderConfig::AlphaMode::kIsOpaque, media::VideoColorSpace(), media::kNoTransformation, - kCodedSize, + k1080CodecSize, + kVisibleRect, + kNaturalSize, + media::EmptyExtraData(), + media::EncryptionScheme::kCbcs); + +const media::VideoDecoderConfig kEncryptedVP9MaxConfig( + media::VideoCodec::kVP9, + media::VP9PROFILE_MAX, + media::VideoDecoderConfig::AlphaMode::kIsOpaque, + media::VideoColorSpace(), + media::kNoTransformation, + k4kCodecSize, + kVisibleRect, + kNaturalSize, + media::EmptyExtraData(), + media::EncryptionScheme::kCbcs); + +// Unencrypted VideoDecoderConfig +const media::VideoDecoderConfig kUnencryptedH264Base320Config( + media::VideoCodec::kH264, + media::H264PROFILE_MIN, + media::VideoDecoderConfig::AlphaMode::kIsOpaque, + media::VideoColorSpace(), + media::kNoTransformation, + k320CodecSize, kVisibleRect, kNaturalSize, media::EmptyExtraData(), media::EncryptionScheme::kUnencrypted); -const fuchsia::mediacodec::CodecDescription kH264DecoderCodec = { - .codec_type = fuchsia::mediacodec::CodecType::DECODER, - .mime_type = "video/h264", - .is_hw = true, +const media::VideoDecoderConfig kUnencryptedH264Base1080Config( + media::VideoCodec::kH264, + media::H264PROFILE_MIN, + media::VideoDecoderConfig::AlphaMode::kIsOpaque, + media::VideoColorSpace(), + media::kNoTransformation, + k1080CodecSize, + kVisibleRect, + kNaturalSize, + media::EmptyExtraData(), + media::EncryptionScheme::kUnencrypted); + +const media::VideoDecoderConfig kUnencryptedH264Base4kConfig( + media::VideoCodec::kH264, + media::H264PROFILE_MIN, + media::VideoDecoderConfig::AlphaMode::kIsOpaque, + media::VideoColorSpace(), + media::kNoTransformation, + k4kCodecSize, + kVisibleRect, + kNaturalSize, + media::EmptyExtraData(), + media::EncryptionScheme::kUnencrypted); + +const media::VideoDecoderConfig kUnencryptedH264High4kConfig( + media::VideoCodec::kH264, + media::H264PROFILE_HIGH, + media::VideoDecoderConfig::AlphaMode::kIsOpaque, + media::VideoColorSpace(), + media::kNoTransformation, + k4kCodecSize, + kVisibleRect, + kNaturalSize, + media::EmptyExtraData(), + media::EncryptionScheme::kUnencrypted); + +const media::VideoDecoderConfig kUnencryptedVP9BaseConfig( + media::VideoCodec::kVP9, + media::VP9PROFILE_MIN, + media::VideoDecoderConfig::AlphaMode::kIsOpaque, + media::VideoColorSpace(), + media::kNoTransformation, + k1080CodecSize, + kVisibleRect, + kNaturalSize, + media::EmptyExtraData(), + media::EncryptionScheme::kUnencrypted); + +const media::VideoDecoderConfig kUnknownConfig( + media::VideoCodec::kUnknown, + media::VIDEO_CODEC_PROFILE_UNKNOWN, + media::VideoDecoderConfig::AlphaMode::kIsOpaque, + media::VideoColorSpace(), + media::kNoTransformation, + k4kCodecSize, + kVisibleRect, + kNaturalSize, + media::EmptyExtraData(), + media::EncryptionScheme::kUnencrypted); + +const fuchsia::math::SizeU k320CodedSize = { + .width = 568, + .height = 320, }; -const fuchsia::mediacodec::CodecDescription kVP9DecoderCodec = { - .codec_type = fuchsia::mediacodec::CodecType::DECODER, - .mime_type = "video/vp9", - .is_hw = true, +const fuchsia::math::SizeU k480CodedSize = { + .width = 852, + .height = 480, }; -// Partial fake implementation of a CodecFactory -class FakeCodecFactory +const fuchsia::math::SizeU k1080CodedSize = { + .width = 1920, + .height = 1080, +}; + +const fuchsia::math::SizeU k4kCodedSize = { + .width = 3840, + .height = 2160, +}; + +class FakeCodecFactoryWithNoCodecs : public fuchsia::mediacodec::testing::CodecFactory_TestBase { public: - explicit FakeCodecFactory(sys::OutgoingDirectory* outgoing_services) + explicit FakeCodecFactoryWithNoCodecs( + sys::OutgoingDirectory* outgoing_services) : binding_(outgoing_services, this) {} - FakeCodecFactory(const FakeCodecFactory&) = delete; - FakeCodecFactory& operator=(const FakeCodecFactory&) = delete; - ~FakeCodecFactory() override = default; + FakeCodecFactoryWithNoCodecs(const FakeCodecFactoryWithNoCodecs&) = delete; + FakeCodecFactoryWithNoCodecs& operator=(const FakeCodecFactoryWithNoCodecs&) = + delete; + ~FakeCodecFactoryWithNoCodecs() override = default; - void TriggerOnCodecListEvent( - std::vector<fuchsia::mediacodec::CodecDescription> codec_list) { - binding_.events().OnCodecList(codec_list); + void GetDetailedCodecDescriptions( + GetDetailedCodecDescriptionsCallback callback) override { + callback(std::move( + fuchsia::mediacodec::CodecFactoryGetDetailedCodecDescriptionsResponse() + .set_codecs({}))); } void NotImplemented_(const std::string& name) override { ADD_FAILURE() << "Unimplemented function called: " << name; } - private: + protected: base::ScopedSingleClientServiceBinding<fuchsia::mediacodec::CodecFactory> binding_; }; +class FakeCodecFactory : public FakeCodecFactoryWithNoCodecs { + public: + explicit FakeCodecFactory(sys::OutgoingDirectory* outgoing_services) + : FakeCodecFactoryWithNoCodecs(outgoing_services) {} + + void GetDetailedCodecDescriptions( + GetDetailedCodecDescriptionsCallback callback) override { + requested_count_++; + std::vector<fuchsia::mediacodec::DetailedCodecDescription> codec_list; + codec_list.push_back(GetAudioDetailedCodecDescription()); + codec_list.push_back(GetSwDetailedCodecDescription()); + codec_list.push_back(GetUnknownDetailedCodecDescription()); + codec_list.push_back(GetUnencryptedH264DetailedCodecDescription()); + codec_list.push_back(GetEncryptedVP9DetailedCodecDescription()); + callback(std::move( + fuchsia::mediacodec::CodecFactoryGetDetailedCodecDescriptionsResponse() + .set_codecs(std::move(codec_list)))); + } + + // Gets the number of calls to `GetDetailedCodecDescriptions`. + int GetRequestedCount() { return requested_count_; } + + private: + fuchsia::mediacodec::DetailedCodecDescription + GetAudioDetailedCodecDescription() { + std::vector<fuchsia::mediacodec::DecoderProfileDescription> profile_list; + + profile_list.push_back( + std::move(fuchsia::mediacodec::DecoderProfileDescription() + .set_split_header_handling(false))); + + return std::move( + fuchsia::mediacodec::DetailedCodecDescription() + .set_codec_type(fuchsia::mediacodec::CodecType::DECODER) + .set_mime_type("audio/aac") + .set_is_hw(true) + .set_profile_descriptions( + std::move(fuchsia::mediacodec::ProfileDescriptions() + .set_decoder_profile_descriptions( + std::move(profile_list))))); + } + + // Returns a software decoder codec that has a higher profile and a larger + // image size range than `GetUnencryptedH264DetailedCodecDescription` returns. + fuchsia::mediacodec::DetailedCodecDescription + GetSwDetailedCodecDescription() { + std::vector<fuchsia::mediacodec::DecoderProfileDescription> profile_list; + + profile_list.push_back(std::move( + fuchsia::mediacodec::DecoderProfileDescription() + .set_profile(fuchsia::media::CodecProfile::H264PROFILE_HIGH) + .set_max_image_size(k4kCodedSize) + .set_min_image_size(k320CodedSize))); + + return std::move( + fuchsia::mediacodec::DetailedCodecDescription() + .set_codec_type(fuchsia::mediacodec::CodecType::DECODER) + .set_mime_type("video/h264") + .set_is_hw(false) + .set_profile_descriptions( + std::move(fuchsia::mediacodec::ProfileDescriptions() + .set_decoder_profile_descriptions( + std::move(profile_list))))); + } + + fuchsia::mediacodec::DetailedCodecDescription + GetUnknownDetailedCodecDescription() { + std::vector<fuchsia::mediacodec::DecoderProfileDescription> profile_list; + + profile_list.push_back( + std::move(fuchsia::mediacodec::DecoderProfileDescription() + .set_profile(fuchsia::media::CodecProfile::MJPEG_BASELINE) + .set_max_image_size(k4kCodedSize) + .set_min_image_size(k320CodedSize))); + + return std::move( + fuchsia::mediacodec::DetailedCodecDescription() + .set_codec_type(fuchsia::mediacodec::CodecType::DECODER) + .set_mime_type("video/unknown") + .set_is_hw(true) + .set_profile_descriptions( + std::move(fuchsia::mediacodec::ProfileDescriptions() + .set_decoder_profile_descriptions( + std::move(profile_list))))); + } + + fuchsia::mediacodec::DetailedCodecDescription + GetUnencryptedH264DetailedCodecDescription() { + std::vector<fuchsia::mediacodec::DecoderProfileDescription> profile_list; + + profile_list.push_back(std::move( + fuchsia::mediacodec::DecoderProfileDescription() + .set_profile(fuchsia::media::CodecProfile::H264PROFILE_BASELINE) + .set_max_image_size(k1080CodedSize) + .set_min_image_size(k480CodedSize))); + + return std::move( + fuchsia::mediacodec::DetailedCodecDescription() + .set_codec_type(fuchsia::mediacodec::CodecType::DECODER) + .set_mime_type("video/h264") + .set_is_hw(true) + .set_profile_descriptions( + std::move(fuchsia::mediacodec::ProfileDescriptions() + .set_decoder_profile_descriptions( + std::move(profile_list))))); + } + + fuchsia::mediacodec::DetailedCodecDescription + GetEncryptedVP9DetailedCodecDescription() { + std::vector<fuchsia::mediacodec::DecoderProfileDescription> profile_list; + + profile_list.push_back(std::move( + fuchsia::mediacodec::DecoderProfileDescription() + .set_profile(fuchsia::media::CodecProfile::VP9PROFILE_PROFILE0) + .set_max_image_size(k1080CodedSize) + .set_min_image_size(k480CodedSize) + .set_allow_encryption(true) + .set_require_encryption(true))); + + return std::move( + fuchsia::mediacodec::DetailedCodecDescription() + .set_codec_type(fuchsia::mediacodec::CodecType::DECODER) + .set_mime_type("video/vp9") + .set_is_hw(true) + .set_profile_descriptions( + std::move(fuchsia::mediacodec::ProfileDescriptions() + .set_decoder_profile_descriptions( + std::move(profile_list))))); + } + + // Number of calls to `GetDetailedCodecDescriptions`. + int requested_count_ = 0; +}; + } // namespace class FuchsiaMediaCodecProviderImplTest : public testing::Test { @@ -99,114 +335,136 @@ ~FuchsiaMediaCodecProviderImplTest() override = default; protected: - std::unique_ptr<FuchsiaMediaCodecProviderImpl> CreateMediaCodecProvider() { - auto* media_codec_provider = new FuchsiaMediaCodecProviderImpl(); - // Wait until event bindings are done. - task_enviornment_.RunUntilIdle(); - return base::WrapUnique(media_codec_provider); + mojo::Remote<media::mojom::FuchsiaMediaCodecProvider> GetProviderRemote() { + mojo::Remote<media::mojom::FuchsiaMediaCodecProvider> + media_codec_provider_remote; + media_codec_provider_.emplace(); + media_codec_provider_->AddReceiver( + media_codec_provider_remote.BindNewPipeAndPassReceiver()); + return media_codec_provider_remote; } base::test::SingleThreadTaskEnvironment task_enviornment_{ base::test::SingleThreadTaskEnvironment::MainThreadType::IO}; base::TestComponentContextForProcess component_context_; + absl::optional<FuchsiaMediaCodecProviderImpl> media_codec_provider_; }; -TEST_F(FuchsiaMediaCodecProviderImplTest, NoMediaCodecConnection) { - auto media_codec_provider = CreateMediaCodecProvider(); - base::test::TestFuture<const media::SupportedVideoDecoderConfigs&> future; +TEST_F(FuchsiaMediaCodecProviderImplTest, MissingCodecFactory_ReportsNoCodecs) { + // No `CodecFactory` is published hence there will be no successful media + // codec connection. + auto provider_remote = GetProviderRemote(); + base::test::TestFuture<const media::SupportedVideoDecoderConfigs&> + get_configs_future; - media_codec_provider->GetSupportedVideoDecoderConfigs(future.GetCallback()); - EXPECT_TRUE(future.Wait()); - EXPECT_TRUE(future.Get().empty()); + provider_remote->GetSupportedVideoDecoderConfigs( + get_configs_future.GetCallback()); + EXPECT_TRUE(get_configs_future.Get().empty()); } -TEST_F(FuchsiaMediaCodecProviderImplTest, DisconnectWhileGettingCodecList) { +TEST_F(FuchsiaMediaCodecProviderImplTest, + DisconnectCodecFactoryDuringQuery_ReportsNoCodecs) { auto codec_factory_ptr = std::make_unique<FakeCodecFactory>( component_context_.additional_services()); - auto media_codec_provider = CreateMediaCodecProvider(); - base::test::TestFuture<const media::SupportedVideoDecoderConfigs&> future; + auto provider_remote = GetProviderRemote(); - codec_factory_ptr->TriggerOnCodecListEvent({kH264DecoderCodec}); - // Wait until the event is handled. - task_enviornment_.RunUntilIdle(); + base::test::TestFuture<const media::SupportedVideoDecoderConfigs&> + get_configs_future; + provider_remote->GetSupportedVideoDecoderConfigs( + get_configs_future.GetCallback()); // Disconnect the service. codec_factory_ptr.reset(); - media_codec_provider->GetSupportedVideoDecoderConfigs(future.GetCallback()); - EXPECT_TRUE(future.Wait()); - EXPECT_TRUE(future.Get().empty()); + EXPECT_TRUE(get_configs_future.Get().empty()); +} + +TEST_F(FuchsiaMediaCodecProviderImplTest, + CodecFactoryWithNoCodecs_ReportsNoCodecs) { + FakeCodecFactoryWithNoCodecs codec_factory( + component_context_.additional_services()); + auto provider_remote = GetProviderRemote(); + base::test::TestFuture<const media::SupportedVideoDecoderConfigs&> + get_configs_future; + + provider_remote->GetSupportedVideoDecoderConfigs( + get_configs_future.GetCallback()); + EXPECT_TRUE(get_configs_future.Get().empty()); } TEST_F(FuchsiaMediaCodecProviderImplTest, GetSupportedVideoDecoderConfigs) { FakeCodecFactory codec_factory(component_context_.additional_services()); - auto media_codec_provider = CreateMediaCodecProvider(); - base::test::TestFuture<const media::SupportedVideoDecoderConfigs&> future; + auto provider_remote = GetProviderRemote(); + base::test::TestFuture<const media::SupportedVideoDecoderConfigs&> + get_configs_future; - media_codec_provider->GetSupportedVideoDecoderConfigs(future.GetCallback()); - // Wait until the callback is queued up. - task_enviornment_.RunUntilIdle(); + provider_remote->GetSupportedVideoDecoderConfigs( + get_configs_future.GetCallback()); - codec_factory.TriggerOnCodecListEvent({kH264DecoderCodec}); - // Wait until the event is handled. - task_enviornment_.RunUntilIdle(); + // Only the VP9 codec config from `GetEncryptedVP9DetailedCodecDescription` + // and the H264 codec config from `GetUnencryptedH264DetailedCodecDescription` + // are supported by the FakeCodecFactory. Ensure that entries are not added + // for the audio, unknown and software codecs. + const size_t kExpectedNumSupportedConfigs = 2; + EXPECT_EQ(get_configs_future.Get().size(), kExpectedNumSupportedConfigs); - EXPECT_TRUE( - media::IsVideoDecoderConfigSupported(future.Get(), kH264BaseConfig)); + // The H264 codec config from `GetUnencryptedH264DetailedCodecDescription` + // does not support encryption. + EXPECT_TRUE(media::IsVideoDecoderConfigSupported( + get_configs_future.Get(), kUnencryptedH264Base1080Config)); + EXPECT_FALSE(media::IsVideoDecoderConfigSupported( + get_configs_future.Get(), kEncryptedH264Base1080Config)); + + // The VP9 codec config from `GetEncryptedVP9DetailedCodecDescription` + // requires (not just supports) encryption. + EXPECT_TRUE(media::IsVideoDecoderConfigSupported(get_configs_future.Get(), + kEncryptedVP9BaseConfig)); + EXPECT_FALSE(media::IsVideoDecoderConfigSupported(get_configs_future.Get(), + kUnencryptedVP9BaseConfig)); + + // FakeCodecFactory does not support hardware-accelerated H264 High profile + // video codec or VP9 max codec is supported. + EXPECT_FALSE(media::IsVideoDecoderConfigSupported( + get_configs_future.Get(), kUnencryptedH264High4kConfig)); + EXPECT_FALSE(media::IsVideoDecoderConfigSupported(get_configs_future.Get(), + kEncryptedVP9MaxConfig)); + + // FakeCodecFactory only supports H264 Base profile from 480p to 1080p. + // It supports a software H264 Base profile from 320p to 4k, but it should be + // ignored. + EXPECT_FALSE(media::IsVideoDecoderConfigSupported( + get_configs_future.Get(), kUnencryptedH264Base320Config)); + EXPECT_FALSE(media::IsVideoDecoderConfigSupported( + get_configs_future.Get(), kUnencryptedH264Base4kConfig)); + + // Unknown video decoder config should not be supported. + EXPECT_FALSE(media::IsVideoDecoderConfigSupported(get_configs_future.Get(), + kUnknownConfig)); } TEST_F(FuchsiaMediaCodecProviderImplTest, GetSupportedVideoDecoderConfigsInAQueue) { FakeCodecFactory codec_factory(component_context_.additional_services()); - auto media_codec_provider = CreateMediaCodecProvider(); + auto provider_remote = GetProviderRemote(); base::test::TestFuture<const media::SupportedVideoDecoderConfigs&> future_1; base::test::TestFuture<const media::SupportedVideoDecoderConfigs&> future_2; - media_codec_provider->GetSupportedVideoDecoderConfigs(future_1.GetCallback()); - media_codec_provider->GetSupportedVideoDecoderConfigs(future_2.GetCallback()); - // Wait until the callbacks are queued up. - task_enviornment_.RunUntilIdle(); + // No RunLoop is spun until `TestFuture::Get()` is called. + provider_remote->GetSupportedVideoDecoderConfigs(future_1.GetCallback()); + provider_remote->GetSupportedVideoDecoderConfigs(future_2.GetCallback()); - codec_factory.TriggerOnCodecListEvent({kH264DecoderCodec}); - // Wait until the event is handled. - task_enviornment_.RunUntilIdle(); + // Makes sure the callbacks are queued up before any completion from the + // CodecFactory. + EXPECT_EQ(codec_factory.GetRequestedCount(), 0); - EXPECT_TRUE( - media::IsVideoDecoderConfigSupported(future_1.Get(), kH264BaseConfig)); - EXPECT_TRUE( - media::IsVideoDecoderConfigSupported(future_2.Get(), kH264BaseConfig)); -} - -TEST_F(FuchsiaMediaCodecProviderImplTest, - CodecListUpdatesWhileGettingSupportedVideoDecoderConfigs) { - FakeCodecFactory codec_factory(component_context_.additional_services()); - auto media_codec_provider = CreateMediaCodecProvider(); - base::test::TestFuture<const media::SupportedVideoDecoderConfigs&> future_1; - base::test::TestFuture<const media::SupportedVideoDecoderConfigs&> future_2; - - media_codec_provider->GetSupportedVideoDecoderConfigs(future_1.GetCallback()); - // Wait until the callback is queued up. - task_enviornment_.RunUntilIdle(); - - codec_factory.TriggerOnCodecListEvent({kH264DecoderCodec}); - // Wait until the event is handled. - task_enviornment_.RunUntilIdle(); - - codec_factory.TriggerOnCodecListEvent({kVP9DecoderCodec}); - // Wait until the event is handled. - task_enviornment_.RunUntilIdle(); - media_codec_provider->GetSupportedVideoDecoderConfigs(future_2.GetCallback()); - EXPECT_TRUE(future_2.Wait()); - - EXPECT_TRUE( - media::IsVideoDecoderConfigSupported(future_1.Get(), kH264BaseConfig)); - EXPECT_FALSE( - media::IsVideoDecoderConfigSupported(future_1.Get(), kVP9BaseConfig)); - EXPECT_TRUE( - media::IsVideoDecoderConfigSupported(future_2.Get(), kVP9BaseConfig)); - EXPECT_FALSE( - media::IsVideoDecoderConfigSupported(future_2.Get(), kH264BaseConfig)); + // The `RunLoop` in the `TestFuture`s will not spin and process the + // `CodecFactory` call, until the `TestFuture`s are resolved via `Get()`. + EXPECT_TRUE(media::IsVideoDecoderConfigSupported( + future_1.Get(), kUnencryptedH264Base1080Config)); + EXPECT_TRUE(media::IsVideoDecoderConfigSupported( + future_2.Get(), kUnencryptedH264Base1080Config)); + EXPECT_EQ(codec_factory.GetRequestedCount(), 1); } } // namespace content
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc index 5e8403e..f6c7102 100644 --- a/content/browser/renderer_host/render_widget_host_impl.cc +++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -1497,9 +1497,7 @@ } MouseEventWithLatencyInfo mouse_with_latency(mouse_event, latency); - DispatchInputEventWithLatencyInfo( - mouse_with_latency.event, &mouse_with_latency.latency, - &mouse_with_latency.event.GetModifiableEventLatencyMetadata()); + DispatchInputEventWithLatencyInfo(mouse_event, &mouse_with_latency.latency); input_router_->SendMouseEvent( mouse_with_latency, base::BindOnce(&RenderWidgetHostImpl::OnMouseEventAck, weak_factory_.GetWeakPtr())); @@ -1525,9 +1523,7 @@ return; MouseWheelEventWithLatencyInfo wheel_with_latency(wheel_event, latency); - DispatchInputEventWithLatencyInfo( - wheel_with_latency.event, &wheel_with_latency.latency, - &wheel_with_latency.event.GetModifiableEventLatencyMetadata()); + DispatchInputEventWithLatencyInfo(wheel_event, &wheel_with_latency.latency); input_router_->SendWheelEvent(wheel_with_latency); } @@ -1647,9 +1643,8 @@ return; GestureEventWithLatencyInfo gesture_with_latency(gesture_event, latency); - DispatchInputEventWithLatencyInfo( - gesture_with_latency.event, &gesture_with_latency.latency, - &gesture_with_latency.event.GetModifiableEventLatencyMetadata()); + DispatchInputEventWithLatencyInfo(gesture_event, + &gesture_with_latency.latency); input_router_->SendGestureEvent(gesture_with_latency); } @@ -1667,9 +1662,7 @@ // ignored if appropriate in FilterInputEvent(). TouchEventWithLatencyInfo touch_with_latency(touch_event, latency); - DispatchInputEventWithLatencyInfo( - touch_with_latency.event, &touch_with_latency.latency, - &touch_with_latency.event.GetModifiableEventLatencyMetadata()); + DispatchInputEventWithLatencyInfo(touch_event, &touch_with_latency.latency); input_router_->SendTouchEvent(touch_with_latency); } @@ -1778,9 +1771,7 @@ NativeWebKeyboardEventWithLatencyInfo key_event_with_latency(key_event, latency); key_event_with_latency.event.is_browser_shortcut = is_shortcut; - DispatchInputEventWithLatencyInfo( - key_event_with_latency.event, &key_event_with_latency.latency, - &key_event_with_latency.event.GetModifiableEventLatencyMetadata()); + DispatchInputEventWithLatencyInfo(key_event, &key_event_with_latency.latency); // TODO(foolip): |InputRouter::SendKeyboardEvent()| may filter events, in // which the commands will be treated as belonging to the next key event. // WidgetInputHandler::SetEditCommandsForNextKeyEvent should only be sent if @@ -3254,9 +3245,8 @@ void RenderWidgetHostImpl::DispatchInputEventWithLatencyInfo( const blink::WebInputEvent& event, - ui::LatencyInfo* latency, - ui::EventLatencyMetadata* event_latency_metadata) { - latency_tracker_.OnInputEvent(event, latency, event_latency_metadata); + ui::LatencyInfo* latency) { + latency_tracker_.OnInputEvent(event, latency); AddPendingUserActivation(event); for (auto& observer : input_event_observers_) observer.OnInputEvent(event);
diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h index 4338bc5..dd25d63 100644 --- a/content/browser/renderer_host/render_widget_host_impl.h +++ b/content/browser/renderer_host/render_widget_host_impl.h
@@ -1079,10 +1079,8 @@ void OnInvalidInputEventSource() override; // Dispatch input events with latency information - void DispatchInputEventWithLatencyInfo( - const blink::WebInputEvent& event, - ui::LatencyInfo* latency, - ui::EventLatencyMetadata* event_latency_metadata); + void DispatchInputEventWithLatencyInfo(const blink::WebInputEvent& event, + ui::LatencyInfo* latency); void WindowSnapshotReachedScreen(int snapshot_id); @@ -1360,6 +1358,10 @@ 1] = {false}; bool is_in_touchpad_gesture_fling_ = false; + // TODO(crbug.com/1432355): The gesture controller can cause synchronous + // destruction of the page (sending a click to the tab close button). Since + // that'll destroy the RenderWidgetHostImpl, having it own the controller is + // awkward. std::unique_ptr<SyntheticGestureController> synthetic_gesture_controller_; // Must be declared before `input_router_`. The latter is constructed by
diff --git a/content/browser/renderer_host/render_widget_host_unittest.cc b/content/browser/renderer_host/render_widget_host_unittest.cc index 539a8b0..68d74a9 100644 --- a/content/browser/renderer_host/render_widget_host_unittest.cc +++ b/content/browser/renderer_host/render_widget_host_unittest.cc
@@ -2351,10 +2351,8 @@ NativeWebKeyboardEvent native_event(WebInputEvent::Type::kChar, 0, GetNextSimulatedEventTime()); ui::LatencyInfo latency_info = ui::LatencyInfo(); - ui::EventLatencyMetadata event_latency_metadata; EXPECT_CALL(observer, OnInputEvent(_)).Times(1); - host_->DispatchInputEventWithLatencyInfo(native_event, &latency_info, - &event_latency_metadata); + host_->DispatchInputEventWithLatencyInfo(native_event, &latency_info); // Remove InputEventObserver. host_->RemoveInputEventObserver(&observer); @@ -2362,9 +2360,7 @@ // Confirm InputEventObserver is removed. EXPECT_CALL(observer, OnInputEvent(_)).Times(0); latency_info = ui::LatencyInfo(); - event_latency_metadata = ui::EventLatencyMetadata(); - host_->DispatchInputEventWithLatencyInfo(native_event, &latency_info, - &event_latency_metadata); + host_->DispatchInputEventWithLatencyInfo(native_event, &latency_info); } #if BUILDFLAG(IS_ANDROID)
diff --git a/content/browser/renderer_host/render_widget_host_view_android.cc b/content/browser/renderer_host/render_widget_host_view_android.cc index 5adf34a..178efd7 100644 --- a/content/browser/renderer_host/render_widget_host_view_android.cc +++ b/content/browser/renderer_host/render_widget_host_view_android.cc
@@ -2112,20 +2112,9 @@ blink::mojom::InputEventResultState ack_result) { const bool event_consumed = ack_result == blink::mojom::InputEventResultState::kConsumed; - // |is_source_touch_event_set_non_blocking| defines a blocking behaviour of - // the future inputs. - const bool is_source_touch_event_set_non_blocking = - InputEventResultStateIsSetNonBlocking(ack_result); - // |was_touch_blocked| indicates whether the current event was dispatched - // blocking to the Renderer. - const bool was_touch_blocked = - ui::WebInputEventTraits::ShouldBlockEventStream(touch.event); gesture_provider_.OnTouchEventAck( touch.event.unique_touch_event_id, event_consumed, - is_source_touch_event_set_non_blocking, - was_touch_blocked - ? absl::make_optional(touch.event.GetEventLatencyMetadata()) - : absl::nullopt); + InputEventResultStateIsSetNonBlocking(ack_result)); if (touch.event.touch_start_or_first_touch_move && event_consumed && host()->delegate() && host()->delegate()->GetInputEventRouter()) { host()
diff --git a/content/browser/shared_storage/shared_storage_worklet_host.cc b/content/browser/shared_storage/shared_storage_worklet_host.cc index 41301f0..4ebbc32 100644 --- a/content/browser/shared_storage/shared_storage_worklet_host.cc +++ b/content/browser/shared_storage/shared_storage_worklet_host.cc
@@ -24,8 +24,8 @@ #include "content/common/renderer.mojom.h" #include "content/public/browser/browser_context.h" #include "mojo/public/cpp/bindings/pending_remote.h" -#include "services/network/public/cpp/is_potentially_trustworthy.h" #include "third_party/blink/public/common/features.h" +#include "third_party/blink/public/common/shared_storage/shared_storage_utils.h" #include "third_party/blink/public/mojom/private_aggregation/private_aggregation_host.mojom.h" #include "third_party/blink/public/mojom/shared_storage/shared_storage_worklet_service.mojom.h" #include "third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom.h" @@ -90,14 +90,6 @@ std::move(fenced_frame_reporter)); } -bool ShouldDefinePrivateAggregationObject( - const url::Origin& shared_storage_origin) { - return network::IsOriginPotentiallyTrustworthy(shared_storage_origin) && - base::FeatureList::IsEnabled( - blink::features::kPrivateAggregationApi) && - blink::features::kPrivateAggregationApiEnabledInSharedStorage.Get(); -} - } // namespace SharedStorageWorkletHost::SharedStorageWorkletHost( @@ -200,7 +192,6 @@ GetAndConnectToSharedStorageWorkletService()->AddModule( std::move(url_loader_factory), script_source_url, - ShouldDefinePrivateAggregationObject(shared_storage_origin_), base::BindOnce(&SharedStorageWorkletHost::OnAddModuleOnWorkletFinished, weak_ptr_factory_.GetWeakPtr(), std::move(callback))); } @@ -912,7 +903,7 @@ SharedStorageWorkletHost::MaybeBindPrivateAggregationHost() { DCHECK(browser_context_); - if (!ShouldDefinePrivateAggregationObject(shared_storage_origin_)) { + if (!blink::ShouldDefinePrivateAggregationInSharedStorage()) { return mojo::PendingRemote<blink::mojom::PrivateAggregationHost>(); }
diff --git a/content/browser/theme_helper_mac.h b/content/browser/theme_helper_mac.h index ebb8cb55..41048dc 100644 --- a/content/browser/theme_helper_mac.h +++ b/content/browser/theme_helper_mac.h
@@ -5,6 +5,8 @@ #ifndef CONTENT_BROWSER_THEME_HELPER_MAC_H_ #define CONTENT_BROWSER_THEME_HELPER_MAC_H_ +#include <memory> + #include "base/containers/span.h" #include "base/memory/read_only_shared_memory_region.h" #include "base/memory/writable_shared_memory_region.h" @@ -13,12 +15,6 @@ #include "third_party/blink/public/platform/mac/web_scrollbar_theme.h" #include "third_party/skia/include/core/SkColor.h" -#if __OBJC__ -@class SystemThemeObserver; -#else -class SystemThemeObserver; -#endif - namespace content { // This class is used to monitor macOS system appearance changes and to notify @@ -55,9 +51,6 @@ // Overridden from content::RenderProcessHostCreationObserver: void OnRenderProcessHostCreated(content::RenderProcessHost* host) override; - // ObjC object that observes notifications from the system. - SystemThemeObserver* theme_observer_; // strong - // Writable and mapped array of SkColor values, indexed by MacSystemColorID // for a light appearance. Colors for a dark appearance in indexed by // MacSystemColorID starting at index MacSystemColorID::kCount. @@ -66,6 +59,9 @@ // Read-only handle to the |writable_color_map_| that can be duplicated for // sharing to child processes. base::ReadOnlySharedMemoryRegion read_only_color_map_; + + struct ObjCStorage; + std::unique_ptr<ObjCStorage> objc_storage_; }; } // namespace content
diff --git a/content/browser/theme_helper_mac.mm b/content/browser/theme_helper_mac.mm index a25efb0d..479566b 100644 --- a/content/browser/theme_helper_mac.mm +++ b/content/browser/theme_helper_mac.mm
@@ -254,6 +254,11 @@ namespace content { +struct ThemeHelperMac::ObjCStorage { + // ObjC object that observes notifications from the system. + base::scoped_nsobject<SystemThemeObserver> theme_observer_; +}; + // static ThemeHelperMac* ThemeHelperMac::GetInstance() { static ThemeHelperMac* instance = new ThemeHelperMac(); @@ -265,27 +270,29 @@ return read_only_color_map_.Duplicate(); } -ThemeHelperMac::ThemeHelperMac() { +ThemeHelperMac::ThemeHelperMac() + : objc_storage_(std::make_unique<ObjCStorage>()) { // Allocate a region for the SkColor value table and map it. auto writable_region = base::WritableSharedMemoryRegion::Create( sizeof(SkColor) * blink::kMacSystemColorIDCount * blink::kMacSystemColorSchemeCount); writable_color_map_ = writable_region.Map(); + // Downgrade the region to read-only after it has been mapped. read_only_color_map_ = base::WritableSharedMemoryRegion::ConvertToReadOnly( std::move(writable_region)); + // Store the current color scheme into the table. LoadSystemColors(); - theme_observer_ = [[SystemThemeObserver alloc] + // Start observing for changes. + objc_storage_->theme_observer_.reset([[SystemThemeObserver alloc] initWithColorsChangedCallback:base::BindRepeating( &ThemeHelperMac::LoadSystemColors, - base::Unretained(this))]; + base::Unretained(this))]); } -ThemeHelperMac::~ThemeHelperMac() { - [theme_observer_ release]; -} +ThemeHelperMac::~ThemeHelperMac() = default; void ThemeHelperMac::LoadSystemColorsForCurrentAppearance( base::span<SkColor> values) {
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn index a164080..a92d133 100644 --- a/content/common/BUILD.gn +++ b/content/common/BUILD.gn
@@ -628,7 +628,6 @@ "//ui/color:mojom", "//ui/display/mojom", "//ui/events/mojom", - "//ui/events/mojom:event_latency_metadata_mojom", "//ui/gfx/geometry/mojom", "//ui/gfx/image/mojom", "//ui/gfx/mojom",
diff --git a/content/services/shared_storage_worklet/shared_storage_worklet_global_scope.cc b/content/services/shared_storage_worklet/shared_storage_worklet_global_scope.cc index e62ed14..7e4dabc8 100644 --- a/content/services/shared_storage_worklet/shared_storage_worklet_global_scope.cc +++ b/content/services/shared_storage_worklet/shared_storage_worklet_global_scope.cc
@@ -26,6 +26,7 @@ #include "gin/v8_initializer.h" #include "mojo/public/cpp/bindings/remote.h" #include "third_party/blink/public/common/shared_storage/module_script_downloader.h" +#include "third_party/blink/public/common/shared_storage/shared_storage_utils.h" #include "third_party/blink/public/mojom/private_aggregation/private_aggregation_host.mojom.h" #include "v8/include/v8-context.h" #include "v8/include/v8-function.h" @@ -63,7 +64,6 @@ pending_url_loader_factory, blink::mojom::SharedStorageWorkletServiceClient* client, const GURL& script_source_url, - bool should_define_private_aggregation_object, blink::mojom::SharedStorageWorkletService::AddModuleCallback callback) { mojo::Remote<network::mojom::URLLoaderFactory> url_loader_factory( std::move(pending_url_loader_factory)); @@ -72,14 +72,12 @@ url_loader_factory.get(), script_source_url, base::BindOnce(&SharedStorageWorkletGlobalScope::OnModuleScriptDownloaded, weak_ptr_factory_.GetWeakPtr(), client, script_source_url, - should_define_private_aggregation_object, std::move(callback))); } void SharedStorageWorkletGlobalScope::OnModuleScriptDownloaded( blink::mojom::SharedStorageWorkletServiceClient* client, const GURL& script_source_url, - bool should_define_private_aggregation_object, blink::mojom::SharedStorageWorkletService::AddModuleCallback callback, std::unique_ptr<std::string> response_body, std::string error_message) { @@ -154,7 +152,7 @@ shared_storage_->GetWrapper(Isolate()).ToLocalChecked()) .Check(); - if (should_define_private_aggregation_object) { + if (blink::ShouldDefinePrivateAggregationInSharedStorage()) { private_aggregation_ = std::make_unique<PrivateAggregation>( *client, private_aggregation_permissions_policy_allowed_, *this); global
diff --git a/content/services/shared_storage_worklet/shared_storage_worklet_global_scope.h b/content/services/shared_storage_worklet/shared_storage_worklet_global_scope.h index 0981d65..761b708 100644 --- a/content/services/shared_storage_worklet/shared_storage_worklet_global_scope.h +++ b/content/services/shared_storage_worklet/shared_storage_worklet_global_scope.h
@@ -50,13 +50,11 @@ pending_url_loader_factory, blink::mojom::SharedStorageWorkletServiceClient* client, const GURL& script_source_url, - bool should_define_private_aggregation_object, blink::mojom::SharedStorageWorkletService::AddModuleCallback callback); void OnModuleScriptDownloaded( blink::mojom::SharedStorageWorkletServiceClient* client, const GURL& script_source_url, - bool should_define_private_aggregation_object, blink::mojom::SharedStorageWorkletService::AddModuleCallback callback, std::unique_ptr<std::string> response_body, std::string error_message);
diff --git a/content/services/shared_storage_worklet/shared_storage_worklet_global_scope_unittest.cc b/content/services/shared_storage_worklet/shared_storage_worklet_global_scope_unittest.cc index 490544c..32ccbdf 100644 --- a/content/services/shared_storage_worklet/shared_storage_worklet_global_scope_unittest.cc +++ b/content/services/shared_storage_worklet/shared_storage_worklet_global_scope_unittest.cc
@@ -8,6 +8,7 @@ #include "base/task/single_thread_task_runner.h" #include "base/test/bind.h" #include "base/test/metrics/histogram_tester.h" +#include "base/test/scoped_feature_list.h" #include "base/test/task_environment.h" #include "content/services/shared_storage_worklet/worklet_v8_helper.h" #include "gin/arguments.h" @@ -20,6 +21,8 @@ #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/abseil-cpp/absl/numeric/int128.h" +#include "third_party/blink/public/common/features.h" +#include "third_party/blink/public/common/shared_storage/shared_storage_utils.h" #include "third_party/blink/public/mojom/private_aggregation/aggregatable_report.mojom.h" #include "third_party/blink/public/mojom/private_aggregation/private_aggregation_host.mojom.h" #include "third_party/blink/public/mojom/shared_storage/shared_storage_worklet_service.mojom.h" @@ -416,9 +419,11 @@ mojo::PendingRemote<blink::mojom::PrivateAggregationHost> InitNewRemotePAHost() { mojo::PendingRemote<blink::mojom::PrivateAggregationHost> remote; - mock_private_aggregation_host_receiver_set_.Add( - mock_private_aggregation_host_.get(), - remote.InitWithNewPipeAndPassReceiver()); + if (blink::ShouldDefinePrivateAggregationInSharedStorage()) { + mock_private_aggregation_host_receiver_set_.Add( + mock_private_aggregation_host_.get(), + remote.InitWithNewPipeAndPassReceiver()); + } return remote; } @@ -440,8 +445,7 @@ TEST_F(SharedStorageWorkletGlobalScopeTest, OnModuleScriptDownloadedSuccess) { global_scope_->OnModuleScriptDownloaded( - test_client_.get(), GURL("https://example.test"), - /*should_define_private_aggregation_object=*/true, base::DoNothing(), + test_client_.get(), GURL("https://example.test"), base::DoNothing(), /*response_body=*/std::make_unique<std::string>(), /*error_message=*/{}); @@ -461,8 +465,7 @@ EXPECT_EQ(GetTypeOf("sharedStorage.length"), "function"); EXPECT_EQ(GetTypeOf("sharedStorage.remainingBudget"), "function"); EXPECT_EQ(GetTypeOf("sharedStorage.context"), "undefined"); - EXPECT_EQ(GetTypeOf("privateAggregation"), "object"); - EXPECT_EQ(GetTypeOf("privateAggregation.sendHistogramReport"), "function"); + EXPECT_EQ(GetTypeOf("privateAggregation"), "undefined"); } TEST_F(SharedStorageWorkletGlobalScopeTest, OnModuleScriptDownloadedWithError) { @@ -474,10 +477,9 @@ callback_called = true; }); - global_scope_->OnModuleScriptDownloaded( - test_client_.get(), GURL("https://example.test"), - /*should_define_private_aggregation_object=*/true, std::move(cb), nullptr, - "error1"); + global_scope_->OnModuleScriptDownloaded(test_client_.get(), + GURL("https://example.test"), + std::move(cb), nullptr, "error1"); EXPECT_FALSE(IsolateInitialized()); EXPECT_TRUE(callback_called); @@ -486,8 +488,7 @@ TEST_F(SharedStorageWorkletGlobalScopeTest, OnModuleScriptDownloadedWithoutPrivateAggregationHost) { global_scope_->OnModuleScriptDownloaded( - test_client_.get(), GURL("https://example.test"), - /*should_define_private_aggregation_object=*/false, base::DoNothing(), + test_client_.get(), GURL("https://example.test"), base::DoNothing(), /*response_body=*/std::make_unique<std::string>(), /*error_message=*/{}); @@ -498,8 +499,7 @@ class SharedStorageAddModuleTest : public SharedStorageWorkletGlobalScopeTest { public: - void SimulateAddModule(const std::string& script_body, - bool define_private_aggregation_host = true) { + void SimulateAddModule(const std::string& script_body) { bool callback_called = false; auto cb = base::BindLambdaForTesting( @@ -511,8 +511,7 @@ }); global_scope_->OnModuleScriptDownloaded( - test_client_.get(), GURL("https://example.test"), - define_private_aggregation_host, std::move(cb), + test_client_.get(), GURL("https://example.test"), std::move(cb), std::make_unique<std::string>(script_body), /*error_message=*/{}); ASSERT_TRUE(callback_called); @@ -714,8 +713,7 @@ } register("test-operation", TestClass); - )", - /*define_private_aggregation_host=*/false); + )"); EXPECT_TRUE(success()); EXPECT_TRUE(error_message().empty()); @@ -742,8 +740,7 @@ public: // The caller should provide a valid module script. The purpose of this test // suite is to test RunOperation. - void SimulateAddModule(const std::string& script_body, - bool define_private_aggregation_host = true) { + void SimulateAddModule(const std::string& script_body) { bool add_module_callback_called = false; auto add_module_callback = base::BindLambdaForTesting( @@ -754,7 +751,7 @@ global_scope_->OnModuleScriptDownloaded( test_client_.get(), GURL("https://example.test"), - define_private_aggregation_host, std::move(add_module_callback), + std::move(add_module_callback), std::make_unique<std::string>(script_body), /*error_message=*/{}); ASSERT_TRUE(add_module_callback_called); @@ -763,8 +760,7 @@ } void SimulateRunOperation(const std::string& name, - const std::vector<uint8_t>& serialized_data, - bool should_pass_private_aggregation_host = true) { + const std::vector<uint8_t>& serialized_data) { auto run_operation_callback = base::BindLambdaForTesting( [&](bool success, const std::string& error_message) { unnamed_operation_finished_ = true; @@ -772,12 +768,8 @@ unnamed_operation_error_message_ = error_message; }); - global_scope_->RunOperation( - name, serialized_data, - should_pass_private_aggregation_host - ? InitNewRemotePAHost() - : mojo::PendingRemote<blink::mojom::PrivateAggregationHost>(), - std::move(run_operation_callback)); + global_scope_->RunOperation(name, serialized_data, InitNewRemotePAHost(), + std::move(run_operation_callback)); } void SimulateRunURLSelectionOperation( @@ -1472,70 +1464,6 @@ } TEST_F(SharedStorageRunOperationTest, - UnnamedOperationWithPrivateAggregationCall_Success) { - EXPECT_CALL(*mock_private_aggregation_host(), SendHistogramReport) - .WillOnce(testing::Invoke( - [](std::vector< - blink::mojom::AggregatableReportHistogramContributionPtr> - contributions, - blink::mojom::AggregationServiceMode aggregation_mode, - blink::mojom::DebugModeDetailsPtr debug_mode_details) { - ASSERT_EQ(contributions.size(), 1u); - EXPECT_EQ(contributions[0]->bucket, 1); - EXPECT_EQ(contributions[0]->value, 2); - EXPECT_EQ(aggregation_mode, - blink::mojom::AggregationServiceMode::kDefault); - ASSERT_FALSE(debug_mode_details.is_null()); - EXPECT_EQ(*debug_mode_details, blink::mojom::DebugModeDetails()); - })); - - SimulateAddModule(R"( - class TestClass { - async run() { - privateAggregation.sendHistogramReport({bucket: 1n, value: 2}); - } - } - - register("test-operation", TestClass); - )"); - - SimulateRunOperation("test-operation", /*serialized_data=*/{}); - - EXPECT_TRUE(unnamed_operation_finished()); - EXPECT_TRUE(unnamed_operation_success()); - EXPECT_TRUE(unnamed_operation_error_message().empty()); - - mock_private_aggregation_host_receiver_set_.FlushForTesting(); -} - -TEST_F(SharedStorageRunOperationTest, - UnnamedOperationWithPrivateAggregationCall_PAPermissionsPolicyDisabled) { - OverrideGlobalScope(std::make_unique<SharedStorageWorkletGlobalScope>( - /*private_aggregation_permissions_policy_allowed=*/false, - /*embedder_context=*/absl::nullopt)); - - SimulateAddModule(R"( - class TestClass { - async run() { - privateAggregation.sendHistogramReport({bucket: 1n, value: 2}); - } - } - - register("test-operation", TestClass); - )"); - - SimulateRunOperation("test-operation", /*serialized_data=*/{}); - - EXPECT_TRUE(unnamed_operation_finished()); - EXPECT_FALSE(unnamed_operation_success()); - - EXPECT_EQ(unnamed_operation_error_message(), - "TypeError: The \"private-aggregation\" Permissions Policy denied " - "the method on privateAggregation"); - EXPECT_TRUE(test_client()->observed_record_use_counter_call()); -} - -TEST_F(SharedStorageRunOperationTest, UnnamedOperationWithPrivateAggregationCall_PAHostNotDefined) { EXPECT_CALL(*mock_private_aggregation_host(), SendHistogramReport).Times(0); @@ -1547,11 +1475,9 @@ } register("test-operation", TestClass); - )", - /*define_private_aggregation_host=*/false); + )"); - SimulateRunOperation("test-operation", /*serialized_data=*/{}, - /*should_pass_private_aggregation_host=*/false); + SimulateRunOperation("test-operation", /*serialized_data=*/{}); EXPECT_TRUE(unnamed_operation_finished()); EXPECT_FALSE(unnamed_operation_success()); @@ -2358,6 +2284,14 @@ : public SharedStorageRunOperationTest { public: SharedStoragePrivateAggregationTest() { + private_aggregation_feature_.InitWithFeaturesAndParameters( + /*enabled_features=*/ + {{blink::features::kPrivateAggregationApi, + {{"enabled_in_shared_storage", "true"}}}}, + /*disabled_features=*/{}); + } + + void SetUp() override { // Run AddModule so that `privateAggregation` is exposed. SimulateAddModule(R"()"); } @@ -2428,6 +2362,8 @@ std::move(operation_completion_closure).Run(); } + + base::test::ScopedFeatureList private_aggregation_feature_; }; TEST_F(SharedStoragePrivateAggregationTest, BasicTest) { @@ -2722,4 +2658,25 @@ mock_private_aggregation_host_receiver_set_.FlushForTesting(); } +class SharedStoragePrivateAggregationPermissionsPolicyDisabledTest + : public SharedStoragePrivateAggregationTest { + public: + void SetUp() override { + OverrideGlobalScope(std::make_unique<SharedStorageWorkletGlobalScope>( + /*private_aggregation_permissions_policy_allowed=*/false, + /*embedder_context=*/absl::nullopt)); + SharedStoragePrivateAggregationTest::SetUp(); + } +}; + +TEST_F(SharedStoragePrivateAggregationPermissionsPolicyDisabledTest, Rejected) { + std::string error_str = ExecuteScriptReturningError( + "privateAggregation.sendHistogramReport({bucket: 1, value: 2});"); + + EXPECT_EQ( + error_str, + "https://example.test/:1 Uncaught TypeError: The \"private-aggregation\" " + "Permissions Policy denied the method on privateAggregation."); +} + } // namespace shared_storage_worklet
diff --git a/content/services/shared_storage_worklet/shared_storage_worklet_service_impl.cc b/content/services/shared_storage_worklet/shared_storage_worklet_service_impl.cc index 4ff0195..6e76c461 100644 --- a/content/services/shared_storage_worklet/shared_storage_worklet_service_impl.cc +++ b/content/services/shared_storage_worklet/shared_storage_worklet_service_impl.cc
@@ -38,12 +38,11 @@ mojo::PendingRemote<network::mojom::URLLoaderFactory> pending_url_loader_factory, const GURL& script_source_url, - bool should_define_private_aggregation_object, AddModuleCallback callback) { DCHECK(!global_scope_); - GetGlobalScope()->AddModule( - std::move(pending_url_loader_factory), client_.get(), script_source_url, - should_define_private_aggregation_object, std::move(callback)); + GetGlobalScope()->AddModule(std::move(pending_url_loader_factory), + client_.get(), script_source_url, + std::move(callback)); } void SharedStorageWorkletServiceImpl::RunURLSelectionOperation(
diff --git a/content/services/shared_storage_worklet/shared_storage_worklet_service_impl.h b/content/services/shared_storage_worklet/shared_storage_worklet_service_impl.h index f17ef86..8dcd42e 100644 --- a/content/services/shared_storage_worklet/shared_storage_worklet_service_impl.h +++ b/content/services/shared_storage_worklet/shared_storage_worklet_service_impl.h
@@ -38,7 +38,6 @@ void AddModule(mojo::PendingRemote<network::mojom::URLLoaderFactory> pending_url_loader_factory, const GURL& script_source_url, - bool should_define_private_aggregation_object, AddModuleCallback callback) override; void RunURLSelectionOperation( const std::string& name,
diff --git a/content/test/data/media/bear.flac b/content/test/data/media/bear.flac index 1db13f91..c9cc8c37 100644 --- a/content/test/data/media/bear.flac +++ b/content/test/data/media/bear.flac Binary files differ
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 36e5b73..359f1f5c 100644 --- a/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
@@ -381,6 +381,7 @@ crbug.com/1382332 [ android-pixel-4 android-r no-clang-coverage qualcomm renderer-skia-gl target-cpu-32 ] Pixel_MediaRecorderFromVideoElementWithOoprCanvasDisabled [ Failure ] crbug.com/1382332 [ fuchsia ] Pixel_MediaRecorderFromVideoElementWithOoprCanvasDisabled [ Failure ] crbug.com/1382332 [ linux nvidia-0x2184 passthrough debug angle-vulkan ] Pixel_MediaRecorderFromVideoElementWithOoprCanvasDisabled [ Failure ] +crbug.com/1382332 [ linux nvidia-0x2184 passthrough debug angle-vulkan ] Pixel_MediaRecorderFromVideoElement [ Failure ] # Pixel_MediaRecorderFromVideoElement flakes on several Linux/Lacros FYI bots crbug.com/1382332 [ linux release renderer-skia-vulkan intel-0x9bc5 ] Pixel_MediaRecorderFromVideoElement [ RetryOnFailure ]
diff --git a/device/bluetooth/floss/fake_floss_socket_manager.cc b/device/bluetooth/floss/fake_floss_socket_manager.cc index 2b6c46a6..43f80854 100644 --- a/device/bluetooth/floss/fake_floss_socket_manager.cc +++ b/device/bluetooth/floss/fake_floss_socket_manager.cc
@@ -105,6 +105,15 @@ base::unexpected(Error(kNotImplemented, "ListenUsingL2Cap"))); } +void FakeFlossSocketManager::ListenUsingL2capLe( + const Security security_level, + ResponseCallback<BtifStatus> callback, + ConnectionStateChanged ready_cb, + ConnectionAccepted new_connection_cb) { + std::move(callback).Run( + base::unexpected(Error(kNotImplemented, "ListenUsingL2CapLe"))); +} + void FakeFlossSocketManager::ListenUsingRfcomm( const std::string& name, const device::BluetoothUUID& uuid, @@ -135,6 +144,14 @@ std::move(callback).Run(BtifStatus::kFail, /*socket=*/absl::nullopt); } +void FakeFlossSocketManager::ConnectUsingL2capLe( + const FlossDeviceId& remote_device, + const int psm, + const Security security_level, + ConnectionCompleted callback) { + std::move(callback).Run(BtifStatus::kFail, /*socket=*/absl::nullopt); +} + void FakeFlossSocketManager::ConnectUsingRfcomm( const FlossDeviceId& remote_device, const device::BluetoothUUID& uuid,
diff --git a/device/bluetooth/floss/fake_floss_socket_manager.h b/device/bluetooth/floss/fake_floss_socket_manager.h index 505fc7b..5cc6a11 100644 --- a/device/bluetooth/floss/fake_floss_socket_manager.h +++ b/device/bluetooth/floss/fake_floss_socket_manager.h
@@ -34,6 +34,10 @@ ResponseCallback<BtifStatus> callback, ConnectionStateChanged ready_cb, ConnectionAccepted new_connection_cb) override; + void ListenUsingL2capLe(const Security security_level, + ResponseCallback<BtifStatus> callback, + ConnectionStateChanged ready_cb, + ConnectionAccepted new_connection_cb) override; void ListenUsingRfcomm(const std::string& name, const device::BluetoothUUID& uuid, const Security security_level, @@ -44,6 +48,10 @@ const int psm, const Security security_level, ConnectionCompleted callback) override; + void ConnectUsingL2capLe(const FlossDeviceId& remote_device, + const int psm, + const Security security_level, + ConnectionCompleted callback) override; void ConnectUsingRfcomm(const FlossDeviceId& remote_device, const device::BluetoothUUID& uuid, const Security security_level,
diff --git a/device/bluetooth/floss/floss_adapter_client.cc b/device/bluetooth/floss/floss_adapter_client.cc index e56923e..77edd851 100644 --- a/device/bluetooth/floss/floss_adapter_client.cc +++ b/device/bluetooth/floss/floss_adapter_client.cc
@@ -613,6 +613,10 @@ observers_.AddObserver(observer); } +bool FlossAdapterClient::HasObserver(FlossAdapterClient::Observer* observer) { + return observers_.HasObserver(observer); +} + void FlossAdapterClient::RemoveObserver( FlossAdapterClient::Observer* observer) { observers_.RemoveObserver(observer);
diff --git a/device/bluetooth/floss/floss_adapter_client.h b/device/bluetooth/floss/floss_adapter_client.h index 3594fad..0afd336 100644 --- a/device/bluetooth/floss/floss_adapter_client.h +++ b/device/bluetooth/floss/floss_adapter_client.h
@@ -162,6 +162,7 @@ // Manage observers. void AddObserver(Observer* observer); + bool HasObserver(Observer* observer); void RemoveObserver(Observer* observer); // Get the address of this adapter.
diff --git a/device/bluetooth/floss/floss_dbus_client.cc b/device/bluetooth/floss/floss_dbus_client.cc index c2bbd37..0e70d64 100644 --- a/device/bluetooth/floss/floss_dbus_client.cc +++ b/device/bluetooth/floss/floss_dbus_client.cc
@@ -125,16 +125,21 @@ const char kRegisterCallback[] = "RegisterCallback"; const char kListenUsingInsecureL2capChannel[] = "ListenUsingInsecureL2capChannel"; +const char kListenUsingInsecureL2capLeChannel[] = + "ListenUsingInsecureL2capLeChannel"; const char kListenUsingInsecureRfcommWithServiceRecord[] = "ListenUsingInsecureRfcommWithServiceRecord"; const char kListenUsingL2capChannel[] = "ListenUsingL2capChannel"; +const char kListenUsingL2capLeChannel[] = "ListenUsingL2capLeChannel"; const char kListenUsingRfcomm[] = "ListenUsingRfcomm"; const char kListenUsingRfcommWithServiceRecord[] = "ListenUsingRfcommWithServiceRecord"; const char kCreateInsecureL2capChannel[] = "CreateInsecureL2capChannel"; +const char kCreateInsecureL2capLeChannel[] = "CreateInsecureL2capLeChannel"; const char kCreateInsecureRfcommSocketToServiceRecord[] = "CreateInsecureRfcommSocketToServiceRecord"; const char kCreateL2capChannel[] = "CreateL2capChannel"; +const char kCreateL2capLeChannel[] = "CreateL2capLeChannel"; const char kCreateRfcommSocketToServiceRecord[] = "CreateRfcommSocketToServiceRecord"; const char kAccept[] = "Accept";
diff --git a/device/bluetooth/floss/floss_dbus_client.h b/device/bluetooth/floss/floss_dbus_client.h index df7a3b6..f4f53ea 100644 --- a/device/bluetooth/floss/floss_dbus_client.h +++ b/device/bluetooth/floss/floss_dbus_client.h
@@ -129,15 +129,19 @@ namespace socket_manager { extern DEVICE_BLUETOOTH_EXPORT const char kRegisterCallback[]; extern DEVICE_BLUETOOTH_EXPORT const char kListenUsingInsecureL2capChannel[]; +extern DEVICE_BLUETOOTH_EXPORT const char kListenUsingInsecureL2capLeChannel[]; extern DEVICE_BLUETOOTH_EXPORT const char kListenUsingInsecureRfcommWithServiceRecord[]; extern DEVICE_BLUETOOTH_EXPORT const char kListenUsingL2capChannel[]; +extern DEVICE_BLUETOOTH_EXPORT const char kListenUsingL2capLeChannel[]; extern DEVICE_BLUETOOTH_EXPORT const char kListenUsingRfcomm[]; extern DEVICE_BLUETOOTH_EXPORT const char kListenUsingRfcommWithServiceRecord[]; extern DEVICE_BLUETOOTH_EXPORT const char kCreateInsecureL2capChannel[]; +extern DEVICE_BLUETOOTH_EXPORT const char kCreateInsecureL2capLeChannel[]; extern DEVICE_BLUETOOTH_EXPORT const char kCreateInsecureRfcommSocketToServiceRecord[]; extern DEVICE_BLUETOOTH_EXPORT const char kCreateL2capChannel[]; +extern DEVICE_BLUETOOTH_EXPORT const char kCreateL2capLeChannel[]; extern DEVICE_BLUETOOTH_EXPORT const char kCreateRfcommSocketToServiceRecord[]; extern DEVICE_BLUETOOTH_EXPORT const char kAccept[]; extern DEVICE_BLUETOOTH_EXPORT const char kClose[];
diff --git a/device/bluetooth/floss/floss_sdp_types.cc b/device/bluetooth/floss/floss_sdp_types.cc index a2e1cfa4..3dd2c30 100644 --- a/device/bluetooth/floss/floss_sdp_types.cc +++ b/device/bluetooth/floss/floss_sdp_types.cc
@@ -51,6 +51,29 @@ constexpr char kSdpDipRecordPropVersion[] = "version"; constexpr char kSdpDipRecordPropPrimaryRecord[] = "primary_record"; +absl::optional<device::BluetoothUUID> GetUUIDFromSdpRecord( + const floss::BtSdpRecord& record) { + if (absl::holds_alternative<floss::BtSdpHeaderOverlay>(record)) { + return absl::get<floss::BtSdpHeaderOverlay>(record).uuid; + } else if (absl::holds_alternative<floss::BtSdpMasRecord>(record)) { + return absl::get<floss::BtSdpMasRecord>(record).hdr.uuid; + } else if (absl::holds_alternative<floss::BtSdpMnsRecord>(record)) { + return absl::get<floss::BtSdpMnsRecord>(record).hdr.uuid; + } else if (absl::holds_alternative<floss::BtSdpPseRecord>(record)) { + return absl::get<floss::BtSdpPseRecord>(record).hdr.uuid; + } else if (absl::holds_alternative<floss::BtSdpPceRecord>(record)) { + return absl::get<floss::BtSdpPceRecord>(record).hdr.uuid; + } else if (absl::holds_alternative<floss::BtSdpOpsRecord>(record)) { + return absl::get<floss::BtSdpOpsRecord>(record).hdr.uuid; + } else if (absl::holds_alternative<floss::BtSdpSapRecord>(record)) { + return absl::get<floss::BtSdpSapRecord>(record).hdr.uuid; + } else if (absl::holds_alternative<floss::BtSdpDipRecord>(record)) { + return absl::get<floss::BtSdpDipRecord>(record).hdr.uuid; + } else { + return absl::nullopt; + } +} + template <> bool FlossDBusClient::ReadDBusParam(dbus::MessageReader* reader, BtSdpType* sdp_type) {
diff --git a/device/bluetooth/floss/floss_sdp_types.h b/device/bluetooth/floss/floss_sdp_types.h index 65e6d33d..aeed541 100644 --- a/device/bluetooth/floss/floss_sdp_types.h +++ b/device/bluetooth/floss/floss_sdp_types.h
@@ -93,6 +93,9 @@ BtSdpSapRecord, BtSdpDipRecord>; +absl::optional<device::BluetoothUUID> DEVICE_BLUETOOTH_EXPORT +GetUUIDFromSdpRecord(const floss::BtSdpRecord& record); + } // namespace floss #endif // DEVICE_BLUETOOTH_FLOSS_FLOSS_SDP_TYPES_H_
diff --git a/device/bluetooth/floss/floss_socket_manager.cc b/device/bluetooth/floss/floss_socket_manager.cc index 155ce12..d204c276 100644 --- a/device/bluetooth/floss/floss_socket_manager.cc +++ b/device/bluetooth/floss/floss_socket_manager.cc
@@ -343,6 +343,27 @@ method, callback_id_); } +void FlossSocketManager::ListenUsingL2capLe( + const Security security_level, + ResponseCallback<BtifStatus> callback, + ConnectionStateChanged ready_cb, + ConnectionAccepted new_connection_cb) { + if (callback_id_ == kInvalidCallbackId) { + std::move(callback).Run(base::unexpected(Error(kErrorInvalidCallback, ""))); + return; + } + + const char* method = security_level == Security::kInsecure + ? socket_manager::kListenUsingInsecureL2capLeChannel + : socket_manager::kListenUsingL2capLeChannel; + + CallSocketMethod( + base::BindOnce(&FlossSocketManager::CompleteListen, + weak_ptr_factory_.GetWeakPtr(), std::move(callback), + std::move(ready_cb), std::move(new_connection_cb)), + method, callback_id_); +} + void FlossSocketManager::ListenUsingRfcommAlt( const absl::optional<std::string> name, const absl::optional<device::BluetoothUUID> application_uuid, @@ -407,6 +428,25 @@ method, callback_id_, remote_device, psm); } +void FlossSocketManager::ConnectUsingL2capLe(const FlossDeviceId& remote_device, + const int psm, + const Security security_level, + ConnectionCompleted callback) { + if (callback_id_ == kInvalidCallbackId) { + std::move(callback).Run(BtifStatus::kFail, /*socket=*/absl::nullopt); + return; + } + + const char* method = security_level == Security::kInsecure + ? socket_manager::kCreateInsecureL2capLeChannel + : socket_manager::kCreateL2capLeChannel; + + CallSocketMethod( + base::BindOnce(&FlossSocketManager::CompleteConnect, + weak_ptr_factory_.GetWeakPtr(), std::move(callback)), + method, callback_id_, remote_device, psm); +} + void FlossSocketManager::ConnectUsingRfcomm(const FlossDeviceId& remote_device, const device::BluetoothUUID& uuid, const Security security_level,
diff --git a/device/bluetooth/floss/floss_socket_manager.h b/device/bluetooth/floss/floss_socket_manager.h index 227e3eb..42207e8 100644 --- a/device/bluetooth/floss/floss_socket_manager.h +++ b/device/bluetooth/floss/floss_socket_manager.h
@@ -134,12 +134,18 @@ FlossSocketManager(); ~FlossSocketManager() override; - // Listen for connections using a connection oriented LE L2Cap channel. + // Listen for connections using a L2Cap channel. virtual void ListenUsingL2cap(const Security security_level, ResponseCallback<BtifStatus> callback, ConnectionStateChanged ready_cb, ConnectionAccepted new_connection_cb); + // Listen for connections using a connection oriented LE L2Cap channel. + virtual void ListenUsingL2capLe(const Security security_level, + ResponseCallback<BtifStatus> callback, + ConnectionStateChanged ready_cb, + ConnectionAccepted new_connection_cb); + // Listen for connections using an RFCOMM channel. This API exposes all of the // options supported by Floss and should only be used if there are no safer // variants capable of supporting a use-case, such as when manually @@ -162,12 +168,18 @@ ConnectionStateChanged ready_cb, ConnectionAccepted new_connection_cb); - // Connect via a connection oriented LE L2Cap channel on given psm. + // Connect via a L2Cap channel on given psm. virtual void ConnectUsingL2cap(const FlossDeviceId& remote_device, const int psm, const Security security_level, ConnectionCompleted callback); + // Connect via a connection oriented LE L2Cap channel on given psm. + virtual void ConnectUsingL2capLe(const FlossDeviceId& remote_device, + const int psm, + const Security security_level, + ConnectionCompleted callback); + // Connect to a remote service using a RFCOMM channel. virtual void ConnectUsingRfcomm(const FlossDeviceId& remote_device, const device::BluetoothUUID& uuid,
diff --git a/device/bluetooth/floss/floss_socket_manager_unittest.cc b/device/bluetooth/floss/floss_socket_manager_unittest.cc index f252ec0..55e2eb5 100644 --- a/device/bluetooth/floss/floss_socket_manager_unittest.cc +++ b/device/bluetooth/floss/floss_socket_manager_unittest.cc
@@ -254,6 +254,10 @@ {socket_manager::kListenUsingInsecureL2capChannel, Security::kInsecure}, {socket_manager::kListenUsingL2capChannel, Security::kSecure}, }; + std::map<std::string, Security> l2cap_le_apis = { + {socket_manager::kListenUsingInsecureL2capLeChannel, Security::kInsecure}, + {socket_manager::kListenUsingL2capLeChannel, Security::kSecure}, + }; std::map<std::string, Security> rfcomm_apis = { {socket_manager::kListenUsingInsecureRfcommWithServiceRecord, Security::kInsecure}, @@ -279,6 +283,24 @@ EXPECT_EQ(BtifStatus::kSuccess, last_status_); } + for (auto kv : l2cap_le_apis) { + EXPECT_CALL(*sockmgr_proxy_.get(), + DoCallMethodWithErrorResponse(HasMemberOf(kv.first), _, _)) + .WillOnce( + Invoke(this, &FlossSocketManagerTest::HandleReturnSocketResult)); + + last_status_ = BtifStatus::kNotReady; + sockmgr_->ListenUsingL2capLe( + kv.second, + base::BindOnce(&FlossSocketManagerTest::SockStatusCb, + weak_ptr_factory_.GetWeakPtr()), + base::BindRepeating(&FlossSocketManagerTest::SockConnectionStateChanged, + weak_ptr_factory_.GetWeakPtr()), + base::BindRepeating(&FlossSocketManagerTest::SockConnectionAccepted, + weak_ptr_factory_.GetWeakPtr())); + + EXPECT_EQ(BtifStatus::kSuccess, last_status_); + } for (auto kv : rfcomm_apis) { EXPECT_CALL(*sockmgr_proxy_.get(), @@ -308,6 +330,11 @@ {socket_manager::kCreateL2capChannel, Security::kSecure}, }; + std::map<std::string, Security> l2cap_le_apis = { + {socket_manager::kCreateInsecureL2capLeChannel, Security::kInsecure}, + {socket_manager::kCreateL2capLeChannel, Security::kSecure}, + }; + std::map<std::string, Security> rfcomm_apis = { {socket_manager::kCreateInsecureRfcommSocketToServiceRecord, Security::kInsecure}, @@ -368,6 +395,51 @@ EXPECT_EQ(psm, found_psm); } + for (auto kv : l2cap_le_apis) { + EXPECT_CALL(*sockmgr_proxy_.get(), + DoCallMethodWithErrorResponse(HasMemberOf(kv.first), _, _)) + .WillOnce( + Invoke(this, &FlossSocketManagerTest::HandleReturnSocketResult)); + + bool callback_completed = false; + BtifStatus callback_status = BtifStatus::kNotReady; + int found_psm = -1; + + sockmgr_->ConnectUsingL2capLe( + remote_device, psm, kv.second, + base::BindOnce( + [](bool* complete, BtifStatus* cb_status, int* fpsm, + BtifStatus status, + absl::optional<FlossSocketManager::FlossSocket>&& socket) { + *complete = true; + *cb_status = status; + if (socket) { + *fpsm = socket->port; + } + }, + &callback_completed, &callback_status, &found_psm)); + + // Status shouldn't be updated yet since we get callback update AFTER we + // send outgoing result. + EXPECT_FALSE(callback_completed); + EXPECT_EQ(BtifStatus::kNotReady, callback_status); + + absl::optional<FlossSocketManager::FlossSocket> sock = + FlossSocketManager::FlossSocket(); + sock->id = socket_id_ctr_ - 1; + sock->port = psm; + + // Trigger the callback completion. We don't care about socket itself. + SendOutgoingConnectionResult( + socket_id_ctr_ - 1, BtifStatus::kSuccess, std::move(sock), + base::BindOnce(&FlossSocketManagerTest::ExpectNormalResponse, + weak_ptr_factory_.GetWeakPtr())); + + EXPECT_TRUE(callback_completed); + EXPECT_EQ(BtifStatus::kSuccess, callback_status); + EXPECT_EQ(psm, found_psm); + } + for (auto kv : rfcomm_apis) { EXPECT_CALL(*sockmgr_proxy_.get(), DoCallMethodWithErrorResponse(HasMemberOf(kv.first), _, _))
diff --git a/docs/webui_build_configuration.md b/docs/webui_build_configuration.md index 50cd5ec..b87e4a3f 100644 --- a/docs/webui_build_configuration.md +++ b/docs/webui_build_configuration.md
@@ -505,6 +505,8 @@ |optimize_webui_host| must be specified if |optimize_webui_in_files| is provided. optimize_webui_excludes: See |excludes| in optimize_webui(). Optional. +optimize_webui_external_paths: See |external_paths| in optimize_webui(). + Optional. optimize_webui_host: See |host| in optimize_webui(). optimize_webui_in_files: See |in_files| in optimize_webui().
diff --git a/fuchsia_web/webengine/BUILD.gn b/fuchsia_web/webengine/BUILD.gn index 16da102e..6e0c7a8 100644 --- a/fuchsia_web/webengine/BUILD.gn +++ b/fuchsia_web/webengine/BUILD.gn
@@ -737,6 +737,7 @@ ":switches", "//components/cast/message_port", "//components/cast_streaming/browser", + "//ui/display", "//url", ] public = [
diff --git a/fuchsia_web/webengine/browser/receiver_session_client.cc b/fuchsia_web/webengine/browser/receiver_session_client.cc index 03af3bd..0353652 100644 --- a/fuchsia_web/webengine/browser/receiver_session_client.cc +++ b/fuchsia_web/webengine/browser/receiver_session_client.cc
@@ -12,6 +12,12 @@ #include "components/cast_streaming/common/public/mojom/demuxer_connector.mojom.h" #include "media/base/audio_decoder_config.h" #include "media/base/video_decoder_config.h" +#include "ui/display/screen.h" +#include "ui/gfx/geometry/size.h" + +namespace { +constexpr size_t kMaxFrameRate = 30; +} // namespace ReceiverSessionClient::ReceiverSessionClient( fidl::InterfaceRequest<fuchsia::web::MessagePort> message_port_request, @@ -56,6 +62,19 @@ cast_streaming::ReceiverConfig config(std::move(video_codecs), std::move(audio_codecs)); + gfx::Size display_resolution = + display::Screen::GetScreen()->GetPrimaryDisplay().bounds().size(); + config.video_limits.push_back(cast_streaming::ReceiverConfig::VideoLimits{ + .max_pixels_per_second = + static_cast<int>(display_resolution.width() * + display_resolution.height() * kMaxFrameRate), + .max_dimensions = gfx::Rect(display_resolution), + .max_frame_rate = kMaxFrameRate}); + config.display_description = cast_streaming::ReceiverConfig::Display{ + .dimensions = gfx::Rect(display_resolution), + .max_frame_rate = kMaxFrameRate, + .can_scale_content = true}; + receiver_session_ = cast_streaming::ReceiverSession::Create( config, base::BindOnce(
diff --git a/gpu/ipc/service/stream_texture_android.cc b/gpu/ipc/service/stream_texture_android.cc index 75ffcf92..5dcfbd4 100644 --- a/gpu/ipc/service/stream_texture_android.cc +++ b/gpu/ipc/service/stream_texture_android.cc
@@ -55,6 +55,13 @@ : TextureOwner::Mode::kSurfaceTextureInsecure; } +scoped_refptr<gpu::RefCountedLock> CreateDrDcLockIfNeeded() { + if (features::NeedThreadSafeAndroidMedia()) { + return base::MakeRefCounted<gpu::RefCountedLock>(); + } + return nullptr; +} + } // namespace // static @@ -93,9 +100,10 @@ int32_t route_id, mojo::PendingAssociatedReceiver<mojom::StreamTexture> receiver, scoped_refptr<SharedContextState> context_state) - : texture_owner_(TextureOwner::Create(GetTextureOwnerMode(), + : RefCountedLockHelperDrDc(CreateDrDcLockIfNeeded()), + texture_owner_(TextureOwner::Create(GetTextureOwnerMode(), context_state, - /*drdc_lock=*/nullptr)), + GetDrDcLock())), has_pending_frame_(false), channel_(channel), route_id_(route_id), @@ -241,7 +249,7 @@ auto shared_image = AndroidVideoImageBacking::Create( mailbox, coded_size, gfx::ColorSpace::CreateSRGB(), kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType, this, context_state_, - /*drdc_lock=*/nullptr); + GetDrDcLock()); channel_->shared_image_stub()->factory()->RegisterBacking( std::move(shared_image));
diff --git a/gpu/ipc/service/stream_texture_android.h b/gpu/ipc/service/stream_texture_android.h index df8edbd..c3a2884e 100644 --- a/gpu/ipc/service/stream_texture_android.h +++ b/gpu/ipc/service/stream_texture_android.h
@@ -15,6 +15,7 @@ #include "base/task/single_thread_task_runner.h" #include "base/threading/thread_checker.h" #include "base/unguessable_token.h" +#include "gpu/command_buffer/service/ref_counted_lock.h" #include "gpu/command_buffer/service/shared_context_state.h" #include "gpu/command_buffer/service/stream_texture_shared_image_interface.h" #include "gpu/command_buffer/service/texture_owner.h" @@ -35,7 +36,8 @@ // This class is thread safe to be used by multiple gpu threads as // |texture_owner_| is thread safe and all other members are only accessed on // gpu main thread. -class StreamTexture : public StreamTextureSharedImageInterface, +class StreamTexture : public RefCountedLockHelperDrDc, + public StreamTextureSharedImageInterface, public mojom::StreamTexture { public: static scoped_refptr<StreamTexture> Create(
diff --git a/infra/config/generated/luci/cr-buildbucket.cfg b/infra/config/generated/luci/cr-buildbucket.cfg index 1c9f65b..d3542951 100644 --- a/infra/config/generated/luci/cr-buildbucket.cfg +++ b/infra/config/generated/luci/cr-buildbucket.cfg
@@ -55455,6 +55455,13 @@ ' "builder": "android-12-x64-rel",' ' "project": "chromium"' ' }' + ' },' + ' {' + ' "builder_id": {' + ' "bucket": "ci",' + ' "builder": "android-12l-x64-dbg-tests",' + ' "project": "chromium"' + ' }' ' }' ' ]' '}'
diff --git a/infra/config/subprojects/reviver/reviver.star b/infra/config/subprojects/reviver/reviver.star index 5fd80c50..df1bf77 100644 --- a/infra/config/subprojects/reviver/reviver.star +++ b/infra/config/subprojects/reviver/reviver.star
@@ -55,6 +55,7 @@ "ci/android-nougat-x86-rel", "ci/android-pie-x86-rel", "ci/android-12-x64-rel", + "ci/android-12l-x64-dbg-tests", ], )
diff --git a/ios/chrome/app/strings/ios_strings.grd b/ios/chrome/app/strings/ios_strings.grd index 373cc3a..88e5ea3 100644 --- a/ios/chrome/app/strings/ios_strings.grd +++ b/ios/chrome/app/strings/ios_strings.grd
@@ -2312,10 +2312,10 @@ Chrome is Signed Out </message> <message name="IDS_IOS_POST_RESTORE_SIGN_IN_ALERT_PROMO_MESSAGE_IPHONE" desc="The message text of the alert post restore sign-in promo. [iOS only]"> - You were signed out of your account <ph name="USER_NAME">$1<ex>example@gmail.com</ex></ph> as part of your iPhone reset. Tap continue below to sign in. + You were signed out of your account, <ph name="USER_NAME">$1<ex>example@gmail.com</ex></ph>, as part of your iPhone reset. To sign back in, tap "Continue" below. </message> <message name="IDS_IOS_POST_RESTORE_SIGN_IN_ALERT_PROMO_MESSAGE_IPAD" desc="The message text of the alert post restore sign-in promo. [iOS only]"> - You were signed out of your account <ph name="USER_NAME">$1<ex>example@gmail.com</ex></ph> as part of your iPad reset. Tap continue below to sign in. + You were signed out of your account, <ph name="USER_NAME">$1<ex>example@gmail.com</ex></ph>, as part of your iPad reset. To sign back in, tap "Continue" below. </message> <message name="IDS_IOS_POST_RESTORE_SIGN_IN_ALERT_PROMO_CANCEL_ACTION" desc="The cancel action text of the alert post restore sign-in promo. [iOS only]"> Ignore
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_POST_RESTORE_SIGN_IN_ALERT_PROMO_MESSAGE_IPAD.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_POST_RESTORE_SIGN_IN_ALERT_PROMO_MESSAGE_IPAD.png.sha1 index 5f2452d..1b46bd3 100644 --- a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_POST_RESTORE_SIGN_IN_ALERT_PROMO_MESSAGE_IPAD.png.sha1 +++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_POST_RESTORE_SIGN_IN_ALERT_PROMO_MESSAGE_IPAD.png.sha1
@@ -1 +1 @@ -fb4bfc2d10449429fc40c0fe49ece8351d410162 \ No newline at end of file +d8df4b3ce91b7c97342e13c3d6d5701225a827fa \ No newline at end of file
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_POST_RESTORE_SIGN_IN_ALERT_PROMO_MESSAGE_IPHONE.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_POST_RESTORE_SIGN_IN_ALERT_PROMO_MESSAGE_IPHONE.png.sha1 index 84229fa..c9a2abb 100644 --- a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_POST_RESTORE_SIGN_IN_ALERT_PROMO_MESSAGE_IPHONE.png.sha1 +++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_POST_RESTORE_SIGN_IN_ALERT_PROMO_MESSAGE_IPHONE.png.sha1
@@ -1 +1 @@ -7e85512bc0f7f48cfa0df7b91a793646faad79ea \ No newline at end of file +3839418ba40fcc9a8f1f929ac1d96a1c40a00faa \ No newline at end of file
diff --git a/ios/chrome/browser/ui/bookmarks/bookmarks_egtest.mm b/ios/chrome/browser/ui/bookmarks/bookmarks_egtest.mm index 74511fa0..c498af4 100644 --- a/ios/chrome/browser/ui/bookmarks/bookmarks_egtest.mm +++ b/ios/chrome/browser/ui/bookmarks/bookmarks_egtest.mm
@@ -30,6 +30,7 @@ using chrome_test_util::BookmarksHomeDoneButton; using chrome_test_util::BookmarksNavigationBarBackButton; using chrome_test_util::BookmarksSaveEditDoneButton; +using chrome_test_util::BookmarksSaveEditFolderButton; using chrome_test_util::ButtonWithAccessibilityLabelId; using chrome_test_util::ContextBarCenterButtonWithLabel; using chrome_test_util::ContextBarLeadingButtonWithLabel; @@ -141,6 +142,64 @@ [BookmarkEarlGreyUI openMobileBookmarks]; } +// Tests opening the folder chooser from the bookmark editor using +// an incognito tab. +// See http://crbug.com/1432310. +- (void)testOpenFolderChooserFromBookmarkEditorWithIncognito { + [ChromeEarlGrey openNewIncognitoTab]; + [BookmarkEarlGrey setupStandardBookmarks]; + [BookmarkEarlGreyUI openBookmarks]; + [BookmarkEarlGreyUI openMobileBookmarks]; + // Invoke Edit through long press on "First URL" bookmark. + [[EarlGrey + selectElementWithMatcher:TappableBookmarkNodeWithLabel(@"First URL")] + performAction:grey_longPress()]; + [[EarlGrey selectElementWithMatcher:chrome_test_util:: + BookmarksContextMenuEditButton()] + performAction:grey_tap()]; + // Tap the Folder button. + [[EarlGrey selectElementWithMatcher:grey_accessibilityID(@"Change Folder")] + performAction:grey_tap()]; + // Close the folder chooser, bookmark editor and the bookmark list. + [[EarlGrey + selectElementWithMatcher:grey_allOf(BookmarksNavigationBarBackButton(), + grey_sufficientlyVisible(), nil)] + performAction:grey_tap()]; + [[EarlGrey selectElementWithMatcher:BookmarksSaveEditDoneButton()] + performAction:grey_tap()]; + [[EarlGrey selectElementWithMatcher:BookmarksHomeDoneButton()] + performAction:grey_tap()]; +} + +// Tests opening the folder chooser from the folder editor using +// an incognito tab. +// See http://crbug.com/1432310. +- (void)testOpenFolderChooserFromFolderEditorWithIncognito { + [ChromeEarlGrey openNewIncognitoTab]; + [BookmarkEarlGrey setupStandardBookmarks]; + [BookmarkEarlGreyUI openBookmarks]; + [BookmarkEarlGreyUI openMobileBookmarks]; + // Invoke Edit through long press on "Folder 1" folder. + [[EarlGrey + selectElementWithMatcher:TappableBookmarkNodeWithLabel(@"Folder 1")] + performAction:grey_longPress()]; + [[EarlGrey selectElementWithMatcher:chrome_test_util:: + BookmarksContextMenuEditButton()] + performAction:grey_tap()]; + // Tap the Folder button. + [[EarlGrey selectElementWithMatcher:grey_accessibilityID(@"Change Folder")] + performAction:grey_tap()]; + // Close the folder chooser, bookmark editor and the bookmark list. + [[EarlGrey + selectElementWithMatcher:grey_allOf(BookmarksNavigationBarBackButton(), + grey_sufficientlyVisible(), nil)] + performAction:grey_tap()]; + [[EarlGrey selectElementWithMatcher:BookmarksSaveEditFolderButton()] + performAction:grey_tap()]; + [[EarlGrey selectElementWithMatcher:BookmarksHomeDoneButton()] + performAction:grey_tap()]; +} + // Tests that changes to the parent folder from the Single Bookmark Editor // are saved to the bookmark only when saving the results. - (void)testMoveDoesSaveOnSave {
diff --git a/ios/chrome/browser/ui/bookmarks/folder_chooser/BUILD.gn b/ios/chrome/browser/ui/bookmarks/folder_chooser/BUILD.gn index 6c6e22d..39e7442 100644 --- a/ios/chrome/browser/ui/bookmarks/folder_chooser/BUILD.gn +++ b/ios/chrome/browser/ui/bookmarks/folder_chooser/BUILD.gn
@@ -38,6 +38,7 @@ "//base", "//components/bookmarks/browser", "//ios/chrome/browser/bookmarks", + "//ios/chrome/browser/browser_state", "//ios/chrome/browser/main:public", "//ios/chrome/browser/signin:signin", "//ios/chrome/browser/sync:sync",
diff --git a/ios/chrome/browser/ui/bookmarks/folder_chooser/bookmarks_folder_chooser_coordinator.mm b/ios/chrome/browser/ui/bookmarks/folder_chooser/bookmarks_folder_chooser_coordinator.mm index cd043d5..01f681c 100644 --- a/ios/chrome/browser/ui/bookmarks/folder_chooser/bookmarks_folder_chooser_coordinator.mm +++ b/ios/chrome/browser/ui/bookmarks/folder_chooser/bookmarks_folder_chooser_coordinator.mm
@@ -15,6 +15,7 @@ #import "components/bookmarks/common/bookmark_features.h" #import "ios/chrome/browser/bookmarks/account_bookmark_model_factory.h" #import "ios/chrome/browser/bookmarks/local_or_syncable_bookmark_model_factory.h" +#import "ios/chrome/browser/browser_state/chrome_browser_state.h" #import "ios/chrome/browser/main/browser.h" #import "ios/chrome/browser/signin/authentication_service_factory.h" #import "ios/chrome/browser/sync/sync_service_factory.h" @@ -113,7 +114,8 @@ - (void)start { [super start]; - ChromeBrowserState* browserState = self.browser->GetBrowserState(); + ChromeBrowserState* browserState = + self.browser->GetBrowserState()->GetOriginalChromeBrowserState(); bookmarks::BookmarkModel* profileModel = ios::LocalOrSyncableBookmarkModelFactory::GetForBrowserState( browserState);
diff --git a/ios/chrome/browser/ui/bookmarks/folder_editor/BUILD.gn b/ios/chrome/browser/ui/bookmarks/folder_editor/BUILD.gn index c9bd1f1..45742736 100644 --- a/ios/chrome/browser/ui/bookmarks/folder_editor/BUILD.gn +++ b/ios/chrome/browser/ui/bookmarks/folder_editor/BUILD.gn
@@ -38,6 +38,7 @@ "//base", "//components/bookmarks/browser", "//ios/chrome/browser/bookmarks", + "//ios/chrome/browser/browser_state", "//ios/chrome/browser/main:public", "//ios/chrome/browser/shared/public/commands", "//ios/chrome/browser/sync",
diff --git a/ios/chrome/browser/ui/bookmarks/folder_editor/bookmarks_folder_editor_coordinator.mm b/ios/chrome/browser/ui/bookmarks/folder_editor/bookmarks_folder_editor_coordinator.mm index 842adcd..d47d2982 100644 --- a/ios/chrome/browser/ui/bookmarks/folder_editor/bookmarks_folder_editor_coordinator.mm +++ b/ios/chrome/browser/ui/bookmarks/folder_editor/bookmarks_folder_editor_coordinator.mm
@@ -11,6 +11,7 @@ #import "base/metrics/user_metrics_action.h" #import "components/bookmarks/browser/bookmark_model.h" #import "ios/chrome/browser/bookmarks/local_or_syncable_bookmark_model_factory.h" +#import "ios/chrome/browser/browser_state/chrome_browser_state.h" #import "ios/chrome/browser/main/browser.h" #import "ios/chrome/browser/shared/public/commands/command_dispatcher.h" #import "ios/chrome/browser/shared/public/commands/snackbar_commands.h" @@ -83,7 +84,8 @@ - (void)start { [super start]; // TODO(crbug.com/1402758): Create a mediator. - ChromeBrowserState* browserState = self.browser->GetBrowserState(); + ChromeBrowserState* browserState = + self.browser->GetBrowserState()->GetOriginalChromeBrowserState(); bookmarks::BookmarkModel* model = ios::LocalOrSyncableBookmarkModelFactory::GetForBrowserState( browserState);
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm index fa90d099..cd2f8a8 100644 --- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm +++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm
@@ -58,6 +58,9 @@ // The horizontal spacing between trending query views. const float kTrendingQueryViewHorizontalSpacing = 12.0f; +// The bottom padding for the vertical stack view. +const float kBottomStackViewPadding = 6.0f; + // Returns the module width depending on the horizontal trait collection. CGFloat GetModuleWidthForHorizontalTraitCollection( UITraitCollection* traitCollection) { @@ -169,26 +172,32 @@ // height/width configurations for each row. self.verticalStackView.distribution = UIStackViewDistributionFill; [self.view addSubview:self.verticalStackView]; + // Add bottom spacing to last module by applying it after + // `_verticalStackView`. If ShouldMinimizeSpacingForModuleRefresh() is YES, + // then no space is added after the last module. + + // Add bottom spacing to the last module by applying it after + // `_verticalStackView`. If `IsContentSuggestionsUIModuleRefreshEnabled()` is + // YES, and ShouldMinimizeSpacingForModuleRefresh() is YES, then no space is + // added after the last module. Otherwise we add kModuleVerticalSpacing. If + // `IsContentSuggestionsUIModuleRefreshEnabled()` is NO, then we add + // `kBottomStackViewPadding` + CGFloat bottomSpacing = kBottomStackViewPadding; if (IsContentSuggestionsUIModuleRefreshEnabled()) { - // Add bottom spacing to last module by applying it after - // `_verticalStackView`. If ShouldMinimizeSpacingForModuleRefresh() is YES, - // then no space is added after the last module. - CGFloat bottomSpacing = + bottomSpacing = ShouldMinimizeSpacingForModuleRefresh() ? 0 : kModuleVerticalSpacing; - [NSLayoutConstraint activateConstraints:@[ - [self.verticalStackView.leadingAnchor - constraintEqualToAnchor:self.view.leadingAnchor], - [self.verticalStackView.trailingAnchor - constraintEqualToAnchor:self.view.trailingAnchor], - [self.verticalStackView.topAnchor - constraintEqualToAnchor:self.view.topAnchor], - [self.verticalStackView.bottomAnchor - constraintEqualToAnchor:self.view.bottomAnchor - constant:-bottomSpacing] - ]]; - } else { - AddSameConstraints(self.view, self.verticalStackView); } + [NSLayoutConstraint activateConstraints:@[ + [self.verticalStackView.leadingAnchor + constraintEqualToAnchor:self.view.leadingAnchor], + [self.verticalStackView.trailingAnchor + constraintEqualToAnchor:self.view.trailingAnchor], + [self.verticalStackView.topAnchor + constraintEqualToAnchor:self.view.topAnchor], + [self.verticalStackView.bottomAnchor + constraintEqualToAnchor:self.view.bottomAnchor + constant:-bottomSpacing] + ]]; CGFloat horizontalSpacing = ContentSuggestionsTilesHorizontalSpacing(self.traitCollection);
diff --git a/ios/chrome/browser/ui/passwords/bottom_sheet/password_suggestion_bottom_sheet_view_controller.mm b/ios/chrome/browser/ui/passwords/bottom_sheet/password_suggestion_bottom_sheet_view_controller.mm index e1fd886..e7d005c 100644 --- a/ios/chrome/browser/ui/passwords/bottom_sheet/password_suggestion_bottom_sheet_view_controller.mm +++ b/ios/chrome/browser/ui/passwords/bottom_sheet/password_suggestion_bottom_sheet_view_controller.mm
@@ -305,24 +305,16 @@ // Defaults to the globe symbol if no URL is associated with the cell. - (void)loadFaviconAtIndexPath:(NSIndexPath*)indexPath forCell:(UITableViewCell*)cell { - TableViewItem* item = - [_tableViewController.tableViewModel itemAtIndexPath:indexPath]; - DCHECK(item); DCHECK(cell); - TableViewURLItem* URLItem = base::mac::ObjCCastStrict<TableViewURLItem>(item); TableViewURLCell* URLCell = base::mac::ObjCCastStrict<TableViewURLCell>(cell); - NSString* itemIdentifier = URLItem.uniqueIdentifier; - auto faviconLoadedBlock = ^(FaviconAttributes* attributes) { - // Only set favicon if the cell hasn't been reused. - if ([URLCell.cellUniqueIdentifier isEqualToString:itemIdentifier]) { - DCHECK(attributes); - [URLCell.faviconView configureWithAttributes:attributes]; - } + // TODO(crbug.com/1422362): if the user scrolls quickly and the cell is + // reused, it is possible that the wrong favicon is displayed (as the + // favicon fetch is asynchronous). + [URLCell.faviconView configureWithAttributes:attributes]; }; - [self.delegate loadFaviconAtIndexPath:indexPath faviconBlockHandler:faviconLoadedBlock]; }
diff --git a/ios/chrome/browser/ui/post_restore_signin/post_restore_signin_provider_unittest.mm b/ios/chrome/browser/ui/post_restore_signin/post_restore_signin_provider_unittest.mm index 0af9f6d..c995c3a 100644 --- a/ios/chrome/browser/ui/post_restore_signin/post_restore_signin_provider_unittest.mm +++ b/ios/chrome/browser/ui/post_restore_signin/post_restore_signin_provider_unittest.mm
@@ -95,11 +95,13 @@ EnableFeatureVariationAlert(); NSString* expected; if (ui::GetDeviceFormFactor() == ui::DEVICE_FORM_FACTOR_TABLET) { - expected = @"You were signed out of your account person@example.org as " - @"part of your iPad reset. Tap continue below to sign in."; + expected = @"You were signed out of your account, person@example.org, as " + @"part of your iPad reset. To sign back in, tap \"Continue\" " + @"below."; } else { - expected = @"You were signed out of your account person@example.org as " - @"part of your iPhone reset. Tap continue below to sign in."; + expected = @"You were signed out of your account, person@example.org, as " + @"part of your iPhone reset. To sign back in, tap \"Continue\" " + @"below."; } EXPECT_TRUE([[provider_ message] isEqualToString:expected]); }
diff --git a/ios/chrome/browser/ui/settings/password/password_details/add_password_view_controller.mm b/ios/chrome/browser/ui/settings/password/password_details/add_password_view_controller.mm index d39cdc5..fffb5721ce 100644 --- a/ios/chrome/browser/ui/settings/password/password_details/add_password_view_controller.mm +++ b/ios/chrome/browser/ui/settings/password/password_details/add_password_view_controller.mm
@@ -47,6 +47,7 @@ namespace { using base::UmaHistogramEnumeration; +using password_manager::constants::kMaxPasswordNoteLength; using password_manager::metrics_util::LogPasswordSettingsReauthResult; using password_manager::metrics_util::PasswordCheckInteraction; using password_manager::metrics_util::ReauthResult; @@ -631,8 +632,7 @@ // Update save button state based on the note's length and validity of other // input fields. - BOOL noteValid = tableViewItem.text.length <= - password_manager::constants::kMaxPasswordNoteLength; + BOOL noteValid = tableViewItem.text.length <= kMaxPasswordNoteLength; if (self.isNoteValid != noteValid) { self.isNoteValid = noteValid; tableViewItem.validText = noteValid; @@ -642,6 +642,15 @@ [self toggleNavigationBarRightButtonItem]; } + // Notify that the note character limit has been reached via VoiceOver. + if (!noteValid) { + NSString* tooLongNoteMessage = l10n_util::GetNSStringF( + IDS_IOS_SETTINGS_PASSWORDS_TOO_LONG_NOTE_DESCRIPTION, + base::NumberToString16(kMaxPasswordNoteLength)); + UIAccessibilityPostNotification(UIAccessibilityAnnouncementNotification, + tooLongNoteMessage); + } + // Update note footer based on the note's length. BOOL shouldDisplayNoteFooter = tableViewItem.text.length >= kMinNoteCharAmountForWarning;
diff --git a/ios/chrome/browser/ui/settings/password/password_details/password_details.h b/ios/chrome/browser/ui/settings/password/password_details/password_details.h index bf0c52f..b5bd7d84 100644 --- a/ios/chrome/browser/ui/settings/password/password_details/password_details.h +++ b/ios/chrome/browser/ui/settings/password/password_details/password_details.h
@@ -22,6 +22,16 @@ CredentialTypeFederation, }; +// Enum which represents the entry point from which the password details are +// accessed. +enum class DetailsContext { + kGeneral, // When accessed from any context other than Password Checkup. + kCompromisedIssues, // When accessed from the compromised issues page. + kDismissedWarnings, // When accessed from the dismissed warnings page. + kReusedIssues, // When accessed from the reused issues page. + kWeakIssues, // When accessed from the weak issues page. +}; + // Object which is used by `PasswordDetailsViewController` to show // information about password. @interface PasswordDetails : NSObject @@ -60,6 +70,9 @@ // `shouldOfferToMoveToAccount` tells whether or not to show a move option. @property(nonatomic, assign) BOOL shouldOfferToMoveToAccount; +// The DetailsContext for the password details. +@property(nonatomic, assign) DetailsContext context; + - (instancetype)initWithCredential: (const password_manager::CredentialUIEntry&)credential NS_DESIGNATED_INITIALIZER;
diff --git a/ios/chrome/browser/ui/settings/password/password_details/password_details_coordinator.h b/ios/chrome/browser/ui/settings/password/password_details/password_details_coordinator.h index 447f0ad..a0d4407 100644 --- a/ios/chrome/browser/ui/settings/password/password_details/password_details_coordinator.h +++ b/ios/chrome/browser/ui/settings/password/password_details/password_details_coordinator.h
@@ -6,6 +6,7 @@ #define IOS_CHROME_BROWSER_UI_SETTINGS_PASSWORD_PASSWORD_DETAILS_PASSWORD_DETAILS_COORDINATOR_H_ #import "ios/chrome/browser/shared/coordinator/chrome_coordinator/chrome_coordinator.h" +#import "ios/chrome/browser/ui/settings/password/password_details/password_details.h" namespace password_manager { class AffiliatedGroup; @@ -28,7 +29,7 @@ (const password_manager::CredentialUIEntry&) credential reauthModule:(ReauthenticationModule*)reauthModule - supportMoveToAccount:(BOOL)supportMoveToAccount + context:(DetailsContext)context NS_DESIGNATED_INITIALIZER; - (instancetype) @@ -38,7 +39,7 @@ affiliatedGroup:(const password_manager::AffiliatedGroup&) affiliatedGroup reauthModule:(ReauthenticationModule*)reauthModule - supportMoveToAccount:(BOOL)supportMoveToAccount + context:(DetailsContext)context NS_DESIGNATED_INITIALIZER; - (instancetype)initWithBaseViewController:(UIViewController*)viewController
diff --git a/ios/chrome/browser/ui/settings/password/password_details/password_details_coordinator.mm b/ios/chrome/browser/ui/settings/password/password_details/password_details_coordinator.mm index f1aebd6b..3a8d6886 100644 --- a/ios/chrome/browser/ui/settings/password/password_details/password_details_coordinator.mm +++ b/ios/chrome/browser/ui/settings/password/password_details/password_details_coordinator.mm
@@ -49,9 +49,8 @@ password_manager::AffiliatedGroup _affiliatedGroup; password_manager::CredentialUIEntry _credential; - // Tells whether or not to support move to account option. If YES, move option - // will be supported, NO otherwise. - BOOL _supportMoveToAccount; + // The context in which the password details are accessed. + DetailsContext _context; } // Main view controller for this coordinator. @@ -85,7 +84,7 @@ (const password_manager::CredentialUIEntry&) credential reauthModule:(ReauthenticationModule*)reauthModule - supportMoveToAccount:(BOOL)supportMoveToAccount { + context:(DetailsContext)context { self = [super initWithBaseViewController:navigationController browser:browser]; if (self) { @@ -94,7 +93,7 @@ _baseNavigationController = navigationController; _credential = credential; _reauthenticationModule = reauthModule; - _supportMoveToAccount = supportMoveToAccount; + _context = context; } return self; } @@ -106,7 +105,7 @@ affiliatedGroup:(const password_manager::AffiliatedGroup&) affiliatedGroup reauthModule:(ReauthenticationModule*)reauthModule - supportMoveToAccount:(BOOL)supportMoveToAccount { + context:(DetailsContext)context { self = [super initWithBaseViewController:navigationController browser:browser]; if (self) { @@ -115,7 +114,7 @@ _baseNavigationController = navigationController; _affiliatedGroup = affiliatedGroup; _reauthenticationModule = reauthModule; - _supportMoveToAccount = supportMoveToAccount; + _context = context; } return self; } @@ -150,7 +149,7 @@ .get() prefService:browserState->GetPrefs() syncService:SyncServiceFactory::GetForBrowserState(browserState) - supportMoveToAccount:_supportMoveToAccount + context:_context passwordManagerClient:PasswordTabHelper::FromWebState(webState) ->GetPasswordManagerClient()]; self.mediator.consumer = self.viewController;
diff --git a/ios/chrome/browser/ui/settings/password/password_details/password_details_coordinator_unittest.mm b/ios/chrome/browser/ui/settings/password/password_details/password_details_coordinator_unittest.mm index ceaf16c..a33910d9 100644 --- a/ios/chrome/browser/ui/settings/password/password_details/password_details_coordinator_unittest.mm +++ b/ios/chrome/browser/ui/settings/password/password_details/password_details_coordinator_unittest.mm
@@ -36,7 +36,7 @@ browser:browser_.get() affiliatedGroup:affiliateGroup reauthModule:nil - supportMoveToAccount:YES]; + context:DetailsContext::kGeneral]; } web::WebTaskEnvironment task_environment_;
diff --git a/ios/chrome/browser/ui/settings/password/password_details/password_details_mediator.h b/ios/chrome/browser/ui/settings/password/password_details/password_details_mediator.h index 83408fb..2fd5629e 100644 --- a/ios/chrome/browser/ui/settings/password/password_details/password_details_mediator.h +++ b/ios/chrome/browser/ui/settings/password/password_details/password_details_mediator.h
@@ -8,6 +8,7 @@ #import <Foundation/Foundation.h> #import "base/mac/foundation_util.h" +#import "ios/chrome/browser/ui/settings/password/password_details/password_details.h" #import "ios/chrome/browser/ui/settings/password/password_details/password_details_table_view_controller_delegate.h" namespace password_manager { @@ -38,7 +39,7 @@ passwordCheckManager:(IOSChromePasswordCheckManager*)manager prefService:(PrefService*)prefService syncService:(syncer::SyncService*)syncService - supportMoveToAccount:(BOOL)supportMoveToAccount + context:(DetailsContext)context passwordManagerClient: (password_manager::PasswordManagerClient*)passwordManagerClient NS_DESIGNATED_INITIALIZER;
diff --git a/ios/chrome/browser/ui/settings/password/password_details/password_details_mediator.mm b/ios/chrome/browser/ui/settings/password/password_details/password_details_mediator.mm index d19b387..55e263c 100644 --- a/ios/chrome/browser/ui/settings/password/password_details/password_details_mediator.mm +++ b/ios/chrome/browser/ui/settings/password/password_details/password_details_mediator.mm
@@ -65,9 +65,8 @@ // Listens to compromised passwords changes. std::unique_ptr<PasswordCheckObserverBridge> _passwordCheckObserver; - // YES when move to account option is supported in password details page, NO - // otherwise. - BOOL _supportMoveToAccount; + // The context in which the password details are accessed. + DetailsContext _context; // Password manager client. raw_ptr<password_manager::PasswordManagerClient> _passwordManagerClient; @@ -99,7 +98,7 @@ passwordCheckManager:(IOSChromePasswordCheckManager*)manager prefService:(PrefService*)prefService syncService:(syncer::SyncService*)syncService - supportMoveToAccount:(BOOL)supportMoveToAccount + context:(DetailsContext)context passwordManagerClient: (password_manager::PasswordManagerClient*)passwordManagerClient { DCHECK(manager); @@ -116,7 +115,7 @@ _displayName = displayName; _passwordCheckObserver = std::make_unique<PasswordCheckObserverBridge>(self, manager); - _supportMoveToAccount = supportMoveToAccount; + _context = context; _passwordManagerClient = passwordManagerClient; _prefService = prefService; _syncService = syncService; @@ -371,19 +370,18 @@ // Pushes password details to the consumer. - (void)providePasswordsToConsumer { NSMutableArray<PasswordDetails*>* passwords = [NSMutableArray array]; - std::vector<password_manager::CredentialUIEntry> insecureCredentials = - _manager->GetInsecureCredentials(); for (const password_manager::CredentialUIEntry& credential : _credentials) { PasswordDetails* password = [[PasswordDetails alloc] initWithCredential:credential]; - password.compromised = base::Contains(insecureCredentials, credential); + password.context = _context; + password.compromised = IsCompromised(credential); // Only offer moving to the account if all of these hold. // - The embedder of this page wants to support it. // - The entry was flagged as local only in the top-level view. // - The user is interested in saving passwords to the account, i.e. they // are opted in to account storage. password.shouldOfferToMoveToAccount = - _supportMoveToAccount && + _context == DetailsContext::kGeneral && password_manager::features_util::IsOptedInForAccountStorage( _prefService, _syncService) && ShouldShowLocalOnlyIcon(credential, _syncService);
diff --git a/ios/chrome/browser/ui/settings/password/password_details/password_details_table_view_controller.mm b/ios/chrome/browser/ui/settings/password/password_details/password_details_table_view_controller.mm index 78f5efc..4b5706b1 100644 --- a/ios/chrome/browser/ui/settings/password/password_details/password_details_table_view_controller.mm +++ b/ios/chrome/browser/ui/settings/password/password_details/password_details_table_view_controller.mm
@@ -91,6 +91,12 @@ // Minimal amount of characters in password note to display the warning. const int kMinNoteCharAmountForWarning = 901; +// Returns the index of a password in the `passwords` array. +int GetPasswordIndex(int section) { + // Only one password at position 0 shows if no grouping applied. + return IsPasswordGroupingEnabled() ? section : 0; +} + } // namespace #pragma mark - TableViewTextItemWithConfigureHandler @@ -141,8 +147,7 @@ @interface PasswordDetailsTableViewController () < TableViewTextEditItemDelegate, - TableViewMultiLineTextEditItemDelegate, - UIGestureRecognizerDelegate> { + TableViewMultiLineTextEditItemDelegate> { // Index of the password the user wants to reveal. NSInteger _passwordIndexToReveal; @@ -549,7 +554,7 @@ } case PasswordDetailsItemTypeChangePasswordButton: if (!self.tableView.editing) { - int passwordIndex = IsPasswordGroupingEnabled() ? indexPath.section : 0; + int passwordIndex = GetPasswordIndex(indexPath.section); DCHECK(self.applicationCommandsHandler); DCHECK(self.passwords[passwordIndex].changePasswordURL.is_valid()); OpenNewTabCommand* command = [OpenNewTabCommand @@ -567,9 +572,29 @@ [textFieldCell.textView becomeFirstResponder]; break; } - case PasswordDetailsItemTypeChangePasswordRecommendation: case PasswordDetailsItemTypeDeleteButton: + if (self.tableView.editing) { + UITableViewCell* cell = + [self.tableView cellForRowAtIndexPath:indexPath]; + [self didTapDeleteButton:cell + atPasswordIndex:GetPasswordIndex(indexPath.section)]; + [self.tableView + deselectRowAtIndexPath:self.tableView.indexPathForSelectedRow + animated:YES]; + } + break; case PasswordDetailsItemTypeMoveToAccountButton: + if (!self.tableView.editing) { + UITableViewCell* cell = + [self.tableView cellForRowAtIndexPath:indexPath]; + [self didTapMoveButton:cell + atPasswordIndex:GetPasswordIndex(indexPath.section)]; + [self.tableView + deselectRowAtIndexPath:self.tableView.indexPathForSelectedRow + animated:YES]; + } + break; + case PasswordDetailsItemTypeChangePasswordRecommendation: case PasswordDetailsItemTypeMoveToAccountRecommendation: break; } @@ -603,7 +628,23 @@ - (BOOL)tableView:(UITableView*)tableView shouldHighlightRowAtIndexPath:(NSIndexPath*)indexPath { NSInteger itemType = [self.tableViewModel itemTypeForIndexPath:indexPath]; - return !self.editing || itemType == PasswordDetailsItemTypeNote; + switch (itemType) { + case PasswordDetailsItemTypeNote: + return YES; + case PasswordDetailsItemTypeWebsite: + case PasswordDetailsItemTypeFederation: + case PasswordDetailsItemTypeUsername: + case PasswordDetailsItemTypePassword: + case PasswordDetailsItemTypeChangePasswordButton: + case PasswordDetailsItemTypeMoveToAccountButton: + return !self.editing; + case PasswordDetailsItemTypeDeleteButton: + return self.editing; + case PasswordDetailsItemTypeChangePasswordRecommendation: + case PasswordDetailsItemTypeMoveToAccountRecommendation: + return NO; + } + return YES; } - (CGFloat)tableView:(UITableView*)tableView @@ -655,31 +696,11 @@ addTarget:self action:@selector(didTapShowHideButton:) forControlEvents:UIControlEventTouchUpInside]; - [textFieldCell.identifyingIconButton setTag:indexPath.section]; + textFieldCell.identifyingIconButton.tag = indexPath.section; break; } - case PasswordDetailsItemTypeChangePasswordRecommendation: { - cell.selectionStyle = UITableViewCellSelectionStyleNone; - break; - } - case PasswordDetailsItemTypeDeleteButton: { - UITapGestureRecognizer* tapRecognizer = [[UITapGestureRecognizer alloc] - initWithTarget:self - action:@selector(didTapDeleteButton:)]; - tapRecognizer.delegate = self; - [cell addGestureRecognizer:tapRecognizer]; - [cell setTag:indexPath.section]; - break; - } - case PasswordDetailsItemTypeMoveToAccountButton: { - UITapGestureRecognizer* tapRecognizer = [[UITapGestureRecognizer alloc] - initWithTarget:self - action:@selector(didTapMoveButton:)]; - tapRecognizer.delegate = self; - [cell addGestureRecognizer:tapRecognizer]; - [cell setTag:indexPath.section]; - break; - } + case PasswordDetailsItemTypeChangePasswordRecommendation: + case PasswordDetailsItemTypeMoveToAccountRecommendation: case PasswordDetailsItemTypeNote: { cell.selectionStyle = UITableViewCellSelectionStyleNone; break; @@ -688,6 +709,8 @@ case PasswordDetailsItemTypeWebsite: case PasswordDetailsItemTypeFederation: case PasswordDetailsItemTypeChangePasswordButton: + case PasswordDetailsItemTypeDeleteButton: + case PasswordDetailsItemTypeMoveToAccountButton: break; } return cell; @@ -702,6 +725,7 @@ case PasswordDetailsItemTypeUsername: case PasswordDetailsItemTypePassword: case PasswordDetailsItemTypeNote: + case PasswordDetailsItemTypeDeleteButton: return YES; } return NO; @@ -774,11 +798,20 @@ [self toggleNavigationBarRightButtonItem]; [self reconfigureCellsForItems:@[ tableViewItem ]]; + // Notify that the note character limit has been reached via VoiceOver. + if (!noteValid) { + NSString* tooLongNoteMessage = l10n_util::GetNSStringF( + IDS_IOS_SETTINGS_PASSWORDS_TOO_LONG_NOTE_DESCRIPTION, + base::NumberToString16(kMaxPasswordNoteLength)); + UIAccessibilityPostNotification(UIAccessibilityAnnouncementNotification, + tooLongNoteMessage); + } + BOOL shouldDisplayNoteFooter = tableViewItem.text.length >= kMinNoteCharAmountForWarning; NSIndexPath* indexPath = [self.tableViewModel indexPathForItem:static_cast<TableViewItem*>(tableViewItem)]; - int passwordIndex = IsPasswordGroupingEnabled() ? indexPath.section : 0; + int passwordIndex = GetPasswordIndex(indexPath.section); // Refresh the cells' height and update note footer based on note's length. [self.tableView beginUpdates]; @@ -1404,26 +1437,23 @@ } } -- (void)didTapDeleteButton:(UIGestureRecognizer*)gestureRecognizer { - UIView* view = gestureRecognizer.view; - int position = view.tag; - DCHECK(position >= 0); +- (void)didTapDeleteButton:(UITableViewCell*)cell + atPasswordIndex:(int)passwordIndex { + DCHECK(passwordIndex >= 0); DCHECK(self.handler); [self.handler - showPasswordDeleteDialogWithPasswordDetails:self.passwords[position] - anchorView:view]; + showPasswordDeleteDialogWithPasswordDetails:self.passwords[passwordIndex] + anchorView:cell]; } -- (void)didTapMoveButton:(UIGestureRecognizer*)gestureRecognizer { +- (void)didTapMoveButton:(UITableViewCell*)cell + atPasswordIndex:(int)passwordIndex { [self setOrExtendAuthValidityTimer]; - UIView* view = gestureRecognizer.view; - // Only one password at position 0 shows if no grouping applied. - int passwordIndex = IsPasswordGroupingEnabled() ? view.tag : 0; // With password notes feature enabled the authentication happens during // navigation from the password list view to the password details view. if (IsPasswordNotesWithBackupEnabled()) { - [self moveCredentialToAccountStore:passwordIndex anchorView:view]; + [self moveCredentialToAccountStore:passwordIndex anchorView:cell]; return; } @@ -1443,7 +1473,7 @@ return; } - [self moveCredentialToAccountStore:passwordIndex anchorView:view]; + [self moveCredentialToAccountStore:passwordIndex anchorView:cell]; }; [self.reauthModule attemptReauthWithLocalizedReason:
diff --git a/ios/chrome/browser/ui/settings/password/password_issues/password_issues_coordinator.mm b/ios/chrome/browser/ui/settings/password/password_issues/password_issues_coordinator.mm index 1397edf..ad482f2 100644 --- a/ios/chrome/browser/ui/settings/password/password_issues/password_issues_coordinator.mm +++ b/ios/chrome/browser/ui/settings/password/password_issues/password_issues_coordinator.mm
@@ -32,6 +32,28 @@ #error "This file requires ARC support." #endif +using password_manager::WarningType; + +namespace { + +// Returns a DetailsContext based on the given WarningType. +DetailsContext ComputeDetailsContextFromWarningType(WarningType warning_type) { + switch (warning_type) { + case WarningType::kCompromisedPasswordsWarning: + return DetailsContext::kCompromisedIssues; + case WarningType::kReusedPasswordsWarning: + return DetailsContext::kReusedIssues; + case WarningType::kWeakPasswordsWarning: + return DetailsContext::kWeakIssues; + case WarningType::kDismissedWarningsWarning: + return DetailsContext::kDismissedWarnings; + case WarningType::kNoInsecurePasswordsWarning: + return DetailsContext::kGeneral; + } +} + +} // namespace + @interface PasswordIssuesCoordinator () <PasswordDetailsCoordinatorDelegate, PasswordIssuesCoordinatorDelegate, PasswordIssuesPresenter> { @@ -139,7 +161,8 @@ browser:self.browser credential:password.credential reauthModule:self.reauthModule - supportMoveToAccount:NO]; + context:ComputeDetailsContextFromWarningType( + _warningType)]; self.passwordDetails.delegate = self; [self.passwordDetails start]; }
diff --git a/ios/chrome/browser/ui/settings/password/passwords_coordinator.mm b/ios/chrome/browser/ui/settings/password/passwords_coordinator.mm index 18462e0..b59330c 100644 --- a/ios/chrome/browser/ui/settings/password/passwords_coordinator.mm +++ b/ios/chrome/browser/ui/settings/password/passwords_coordinator.mm
@@ -234,7 +234,7 @@ browser:self.browser credential:credential reauthModule:self.reauthModule - supportMoveToAccount:YES]; + context:DetailsContext::kGeneral]; self.passwordDetailsCoordinator.delegate = self; [self.passwordDetailsCoordinator start]; } @@ -247,7 +247,7 @@ browser:self.browser affiliatedGroup:affiliatedGroup reauthModule:self.reauthModule - supportMoveToAccount:YES]; + context:DetailsContext::kGeneral]; self.passwordDetailsCoordinator.delegate = self; [self.passwordDetailsCoordinator start]; }
diff --git a/ios/chrome/browser/ui/settings/settings_navigation_controller.mm b/ios/chrome/browser/ui/settings/settings_navigation_controller.mm index f652800..75e839e 100644 --- a/ios/chrome/browser/ui/settings/settings_navigation_controller.mm +++ b/ios/chrome/browser/ui/settings/settings_navigation_controller.mm
@@ -700,7 +700,7 @@ browser:self.browser credential:credential reauthModule:[[ReauthenticationModule alloc] init] - supportMoveToAccount:YES]; + context:DetailsContext::kGeneral]; self.passwordDetailsCoordinator.delegate = self; self.passwordDetailsCoordinator.showCancelButton = showCancelButton; [self.passwordDetailsCoordinator start];
diff --git a/ios/chrome/browser/ui/webui/BUILD.gn b/ios/chrome/browser/ui/webui/BUILD.gn index 0346612..0c60be9 100644 --- a/ios/chrome/browser/ui/webui/BUILD.gn +++ b/ios/chrome/browser/ui/webui/BUILD.gn
@@ -65,6 +65,7 @@ "//components/strings", "//components/ukm", "//components/ukm/debug:util", + "//components/variations/service", "//components/version_info", "//components/version_ui", "//google_apis",
diff --git a/ios/chrome/browser/ui/webui/version_ui.mm b/ios/chrome/browser/ui/webui/version_ui.mm index cba5eff..79c49d2 100644 --- a/ios/chrome/browser/ui/webui/version_ui.mm +++ b/ios/chrome/browser/ui/webui/version_ui.mm
@@ -16,8 +16,11 @@ #import "components/strings/grit/components_chromium_strings.h" #import "components/strings/grit/components_google_chrome_strings.h" #import "components/strings/grit/components_strings.h" +#import "components/variations/service/variations_service.h" #import "components/version_info/version_info.h" +#import "components/version_ui/version_handler_helper.h" #import "components/version_ui/version_ui_constants.h" +#import "ios/chrome/browser/application_context/application_context.h" #import "ios/chrome/browser/browser_state/chrome_browser_state.h" #import "ios/chrome/browser/ui/webui/version_handler.h" #import "ios/chrome/browser/url/chrome_url_constants.h" @@ -99,6 +102,13 @@ IDS_VERSION_UI_VARIATIONS); html_source->AddLocalizedString(version_ui::kVariationsCmdName, IDS_VERSION_UI_VARIATIONS_CMD); + html_source->AddLocalizedString(version_ui::kVariationsSeedName, + IDS_VERSION_UI_VARIATIONS_SEED_NAME); + + html_source->AddString( + version_ui::kVariationsSeed, + version_ui::SeedTypeToUiString( + GetApplicationContext()->GetVariationsService()->GetSeedType())); html_source->AddString(version_ui::kSanitizer, version_info::GetSanitizerList());
diff --git a/ios/chrome/credential_provider_extension/ui/new_password_view_controller.mm b/ios/chrome/credential_provider_extension/ui/new_password_view_controller.mm index a1f1d12..cb39702 100644 --- a/ios/chrome/credential_provider_extension/ui/new_password_view_controller.mm +++ b/ios/chrome/credential_provider_extension/ui/new_password_view_controller.mm
@@ -295,9 +295,18 @@ - (void)textViewDidChangeInCell:(PasswordNoteCell*)cell { self.noteText = cell.textView.text; int noteLength = cell.textView.text.length; - [cell setValid:(noteLength <= kMaxNoteCharAmount)]; + BOOL noteValid = noteLength <= kMaxNoteCharAmount; + [cell setValid:noteValid]; [self updateSaveButtonState]; + // Notify that the character limit has been reached via VoiceOver. + if (!noteValid) { + UIAccessibilityPostNotification( + UIAccessibilityAnnouncementNotification, + NSLocalizedString(@"IDS_IOS_CREDENTIAL_PROVIDER_TOO_LONG_NOTE", + @"Notes can save up to 1000 characters.")); + } + // Update note footer based on note's length. self.isNoteFooterShown = noteLength >= kMinNoteCharAmountForWarning; UITableViewHeaderFooterView* footerView =
diff --git a/media/audio/mac/audio_auhal_mac.cc b/media/audio/mac/audio_auhal_mac.cc index ef83b268..0405498e 100644 --- a/media/audio/mac/audio_auhal_mac.cc +++ b/media/audio/mac/audio_auhal_mac.cc
@@ -34,13 +34,13 @@ kAudioChannelLabel_Right, kAudioChannelLabel_Center, kAudioChannelLabel_LFEScreen, - kAudioChannelLabel_LeftSurround, - kAudioChannelLabel_RightSurround, + kAudioChannelLabel_RearSurroundLeft, + kAudioChannelLabel_RearSurroundRight, kAudioChannelLabel_LeftCenter, kAudioChannelLabel_RightCenter, kAudioChannelLabel_CenterSurround, - kAudioChannelLabel_RearSurroundLeft, - kAudioChannelLabel_RearSurroundRight + kAudioChannelLabel_LeftSurround, + kAudioChannelLabel_RightSurround }; static_assert(0 == LEFT && 1 == RIGHT && 2 == CENTER && 3 == LFE && 4 == BACK_LEFT &&
diff --git a/media/base/media_switches.cc b/media/base/media_switches.cc index 3fdd134c..b40122f 100644 --- a/media/base/media_switches.cc +++ b/media/base/media_switches.cc
@@ -1262,6 +1262,9 @@ "UseSequencedTaskRunnerForMediaService", base::FEATURE_DISABLED_BY_DEFAULT); +// SequencedTaskRunner isn't supported on Windows since the accelerator requires +// a COM STA TaskRunner. +#if !BUILDFLAG(IS_WIN) // Use SequencedTaskRunner for MojoVideoEncodeAcceleratorProvider. BASE_FEATURE(kUseSequencedTaskRunnerForMojoVEAProvider, "UseSequencedTaskRunnerForMojoVEAProvider", @@ -1271,11 +1274,12 @@ base::FEATURE_DISABLED_BY_DEFAULT #endif ); +#endif // !BUILDFLAG(IS_WIN) // Use TaskRunner for each MojoVideoEncodeAcceleratorService. Replaces // per-accelerator encoding task runner. BASE_FEATURE(kUseTaskRunnerForMojoVEAService, - "kUseTaskRunnerForMojoVEAService", + "UseTaskRunnerForMojoVEAService", #if BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_WIN) base::FEATURE_ENABLED_BY_DEFAULT #else
diff --git a/media/filters/ffmpeg_demuxer.cc b/media/filters/ffmpeg_demuxer.cc index 6c79c41d..daa2187 100644 --- a/media/filters/ffmpeg_demuxer.cc +++ b/media/filters/ffmpeg_demuxer.cc
@@ -1064,7 +1064,7 @@ DCHECK(!pending_seek_cb_); TRACE_EVENT_ASYNC_BEGIN0("media", "FFmpegDemuxer::Seek", this); pending_seek_cb_ = std::move(cb); - SeekInternal(time, base::BindOnce(&FFmpegDemuxer::OnSeekFrameSuccess, + SeekInternal(time, base::BindOnce(&FFmpegDemuxer::OnSeekFrameDone, weak_factory_.GetWeakPtr())); } @@ -1073,7 +1073,7 @@ } void FFmpegDemuxer::SeekInternal(base::TimeDelta time, - base::OnceClosure seek_cb) { + base::OnceCallback<void(int)> seek_cb) { DCHECK(task_runner_->RunsTasksInCurrentSequence()); // FFmpeg requires seeks to be adjusted according to the lowest starting time. @@ -1115,10 +1115,10 @@ const AVStream* seeking_stream = demux_stream->av_stream(); DCHECK(seeking_stream); - blocking_task_runner_->PostTaskAndReply( + blocking_task_runner_->PostTaskAndReplyWithResult( FROM_HERE, - base::BindOnce(base::IgnoreResult(&av_seek_frame), - glue_->format_context(), seeking_stream->index, + base::BindOnce(&av_seek_frame, glue_->format_context(), + seeking_stream->index, ConvertToTimeBase(seeking_stream->time_base, seek_time), // Always seek to a timestamp <= to the desired timestamp. AVSEEK_FLAG_BACKWARD), @@ -1656,7 +1656,7 @@ return nullptr; } -void FFmpegDemuxer::OnSeekFrameSuccess() { +void FFmpegDemuxer::OnSeekFrameDone(int result) { DCHECK(task_runner_->RunsTasksInCurrentSequence()); DCHECK(pending_seek_cb_); @@ -1666,6 +1666,12 @@ return; } + if (result < 0) { + MEDIA_LOG(ERROR, media_log_) << GetDisplayName() << ": demuxer seek failed"; + RunPendingSeekCB(PIPELINE_ERROR_READ); + return; + } + // Tell streams to flush buffers due to seeking. for (const auto& stream : streams_) { if (stream) @@ -1729,8 +1735,10 @@ void FFmpegDemuxer::OnVideoSeekedForTrackChange( DemuxerStream* video_stream, - base::OnceClosure seek_completed_cb) { + base::OnceClosure seek_completed_cb, + int result) { static_cast<FFmpegDemuxerStream*>(video_stream)->FlushBuffers(true); + // TODO(crbug.com/1424380): Report seek failures for track changes too. std::move(seek_completed_cb).Run(); }
diff --git a/media/filters/ffmpeg_demuxer.h b/media/filters/ffmpeg_demuxer.h index 569e2c7..bbc77cfa 100644 --- a/media/filters/ffmpeg_demuxer.h +++ b/media/filters/ffmpeg_demuxer.h
@@ -304,7 +304,7 @@ FFmpegDemuxerStream* FindPreferredStreamForSeeking(base::TimeDelta seek_time); // FFmpeg callbacks during seeking. - void OnSeekFrameSuccess(); + void OnSeekFrameDone(int result); // FFmpeg callbacks during reading + helper method to initiate reads. void ReadFrameIfNeeded(); @@ -334,9 +334,11 @@ void SetLiveness(StreamLiveness liveness); - void SeekInternal(base::TimeDelta time, base::OnceClosure seek_cb); + void SeekInternal(base::TimeDelta time, + base::OnceCallback<void(int)> seek_cb); void OnVideoSeekedForTrackChange(DemuxerStream* video_stream, - base::OnceClosure seek_completed_cb); + base::OnceClosure seek_completed_cb, + int result); void SeekOnVideoTrackChange(base::TimeDelta seek_to_time, TrackChangeCB seek_completed_cb, DemuxerStream::Type stream_type,
diff --git a/media/test/data/bear.flac b/media/test/data/bear.flac index 1db13f91..c9cc8c37 100644 --- a/media/test/data/bear.flac +++ b/media/test/data/bear.flac Binary files differ
diff --git a/net/cert/cert_verify_proc.h b/net/cert/cert_verify_proc.h index 22e6055..31401d45 100644 --- a/net/cert/cert_verify_proc.h +++ b/net/cert/cert_verify_proc.h
@@ -39,17 +39,14 @@ enum VerifyFlags { // If set, enables online revocation checking via CRLs and OCSP for the // certificate chain. + // Note: has no effect if VERIFY_DISABLE_NETWORK_FETCHES is set. VERIFY_REV_CHECKING_ENABLED = 1 << 0, // If set, this is equivalent to VERIFY_REV_CHECKING_ENABLED, in that it // enables online revocation checking via CRLs or OCSP, but only // for certificates issued by non-public trust anchors. Failure to check // revocation is treated as a hard failure. - // Note: If VERIFY_CERT_IO_ENABLE is not also supplied, certificates - // that chain to local trust anchors will likely fail - for example, due to - // lacking fresh cached revocation issue (Windows) or because OCSP stapling - // can only provide information for the leaf, and not for any - // intermediates. + // Note: has no effect if VERIFY_DISABLE_NETWORK_FETCHES is set. VERIFY_REV_CHECKING_REQUIRED_LOCAL_ANCHORS = 1 << 1, // If set, certificates with SHA-1 signatures will be allowed, but only if @@ -59,6 +56,12 @@ // If set, disables the policy enforcement described at // https://security.googleblog.com/2017/09/chromes-plan-to-distrust-symantec.html VERIFY_DISABLE_SYMANTEC_ENFORCEMENT = 1 << 3, + + // Disable network fetches during verification. This will override + // VERIFY_REV_CHECKING_ENABLED and + // VERIFY_REV_CHECKING_REQUIRED_LOCAL_ANCHORS if they are also specified. + // TODO(https://crbug.com/1432793): This should also disable AIA fetching. + VERIFY_DISABLE_NETWORK_FETCHES = 1 << 4, }; // These values are persisted to logs. Entries should not be renumbered and
diff --git a/net/cert/cert_verify_proc_builtin.cc b/net/cert/cert_verify_proc_builtin.cc index 907f295e..dd9d25b 100644 --- a/net/cert/cert_verify_proc_builtin.cc +++ b/net/cert/cert_verify_proc_builtin.cc
@@ -314,6 +314,18 @@ // Selects a revocation policy based on the CertVerifier flags and the given // certificate chain. RevocationPolicy ChooseRevocationPolicy(const ParsedCertificateList& certs) { + if (flags_ & CertVerifyProc::VERIFY_DISABLE_NETWORK_FETCHES) { + // In theory when network fetches are disabled but revocation is enabled + // we could continue with networking_allowed=false (and + // VERIFY_REV_CHECKING_REQUIRED_LOCAL_ANCHORS would also have to change + // allow_missing_info and allow_unable_to_check to true). + // That theoretically could allow still consulting any cached CRLs/etc. + // However in the way things are currently implemented in the builtin + // verifier there really is no point to bothering, just disable + // revocation checking if network fetches are disabled. + return NoRevocationChecking(); + } + // Use hard-fail revocation checking for local trust anchors, if requested // by the load flag and the chain uses a non-public root. if ((flags_ & CertVerifyProc::VERIFY_REV_CHECKING_REQUIRED_LOCAL_ANCHORS) &&
diff --git a/net/cert/cert_verify_proc_unittest.cc b/net/cert/cert_verify_proc_unittest.cc index 784a7d0..d93de8a 100644 --- a/net/cert/cert_verify_proc_unittest.cc +++ b/net/cert/cert_verify_proc_unittest.cc
@@ -3299,6 +3299,36 @@ EXPECT_TRUE(verify_result.cert_status & CERT_STATUS_REV_CHECKING_ENABLED); } +TEST_P(CertVerifyProcInternalWithNetFetchingTest, + RevocationHardFailNoCrlsDisableNetworkFetches) { + if (!SupportsRevCheckingRequiredLocalAnchors()) { + LOG(INFO) << "Skipping test as verifier doesn't support " + "VERIFY_REV_CHECKING_REQUIRED_LOCAL_ANCHORS"; + return; + } + + // Create certs which have no AIA or CRL distribution points. + const char kHostname[] = "www.example.com"; + auto [leaf, intermediate, root] = CertBuilder::CreateSimpleChain3(); + + // Trust the root and build a chain to verify that includes the intermediate. + ScopedTestRoot scoped_root(root->GetX509Certificate().get()); + scoped_refptr<X509Certificate> chain = leaf->GetX509CertificateChain(); + ASSERT_TRUE(chain.get()); + + // Verify with flags for both hard-fail revocation checking for local anchors + // and disabling network fetches. + const int flags = CertVerifyProc::VERIFY_REV_CHECKING_REQUIRED_LOCAL_ANCHORS | + CertVerifyProc::VERIFY_DISABLE_NETWORK_FETCHES; + CertVerifyResult verify_result; + int error = + Verify(chain.get(), kHostname, flags, CertificateList(), &verify_result); + + // Should succeed, VERIFY_DISABLE_NETWORK_FETCHES takes priority. + EXPECT_THAT(error, IsOk()); + EXPECT_FALSE(verify_result.cert_status & CERT_STATUS_REV_CHECKING_ENABLED); +} + // CRL hard fail test where both leaf and intermediate are covered by valid // CRLs which have empty (non-present) revokedCertificates list. Verification // should succeed. @@ -3656,6 +3686,42 @@ } TEST_P(CertVerifyProcInternalWithNetFetchingTest, + RevocationSoftFailLeafRevokedByCrlDisableNetworkFetches) { + if (!SupportsSoftFailRevChecking()) { + LOG(INFO) << "Skipping test as verifier doesn't support " + "VERIFY_REV_CHECKING_ENABLED"; + return; + } + + const char kHostname[] = "www.example.com"; + auto [leaf, intermediate, root] = CertBuilder::CreateSimpleChain3(); + + // Root-issued CRL which does not revoke intermediate. + intermediate->SetCrlDistributionPointUrl(CreateAndServeCrl(root.get(), {})); + + // Leaf is revoked by intermediate issued CRL. + leaf->SetCrlDistributionPointUrl( + CreateAndServeCrl(intermediate.get(), {leaf->GetSerialNumber()})); + + // Trust the root and build a chain to verify that includes the intermediate. + ScopedTestRoot scoped_root(root->GetX509Certificate().get()); + scoped_refptr<X509Certificate> chain = leaf->GetX509CertificateChain(); + ASSERT_TRUE(chain.get()); + + // Verify with flags for both soft-fail revocation checking and disabling + // network fetches. + const int flags = CertVerifyProc::VERIFY_REV_CHECKING_ENABLED | + CertVerifyProc::VERIFY_DISABLE_NETWORK_FETCHES; + CertVerifyResult verify_result; + int error = + Verify(chain.get(), kHostname, flags, CertificateList(), &verify_result); + + // Should succeed, VERIFY_DISABLE_NETWORK_FETCHES takes priority. + EXPECT_THAT(error, IsOk()); + EXPECT_FALSE(verify_result.cert_status & CERT_STATUS_REV_CHECKING_ENABLED); +} + +TEST_P(CertVerifyProcInternalWithNetFetchingTest, RevocationSoftFailIntermediateRevokedByCrl) { if (!SupportsSoftFailRevChecking()) { LOG(INFO) << "Skipping test as verifier doesn't support "
diff --git a/net/cert/multi_threaded_cert_verifier.cc b/net/cert/multi_threaded_cert_verifier.cc index dfa1916..0ac8dfc 100644 --- a/net/cert/multi_threaded_cert_verifier.cc +++ b/net/cert/multi_threaded_cert_verifier.cc
@@ -149,8 +149,7 @@ int flags = GetFlagsForConfig(config); if (params.flags() & CertVerifier::VERIFY_DISABLE_NETWORK_FETCHES) { - flags &= ~CertVerifyProc::VERIFY_REV_CHECKING_ENABLED; - flags &= ~CertVerifyProc::VERIFY_REV_CHECKING_REQUIRED_LOCAL_ANCHORS; + flags |= CertVerifyProc::VERIFY_DISABLE_NETWORK_FETCHES; } base::ThreadPool::PostTaskAndReplyWithResult( FROM_HERE,
diff --git a/net/cert/multi_threaded_cert_verifier_unittest.cc b/net/cert/multi_threaded_cert_verifier_unittest.cc index a56ee3e..05fcc9f 100644 --- a/net/cert/multi_threaded_cert_verifier_unittest.cc +++ b/net/cert/multi_threaded_cert_verifier_unittest.cc
@@ -298,6 +298,37 @@ } } +// Tests propagation of CertVerifier flags into CertVerifyProc flags +TEST_F(MultiThreadedCertVerifierTest, ConvertsFlagsToFlags) { + scoped_refptr<X509Certificate> test_cert( + ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem")); + ASSERT_TRUE(test_cert); + + EXPECT_CALL( + *mock_verify_proc_, + VerifyInternal(_, _, _, _, CertVerifyProc::VERIFY_DISABLE_NETWORK_FETCHES, + _, _, _)) + .WillRepeatedly( + DoAll(SetCertVerifyRevokedResult(), Return(ERR_CERT_REVOKED))); + + CertVerifyResult verify_result; + TestCompletionCallback callback; + std::unique_ptr<CertVerifier::Request> request; + int error = verifier_->Verify( + CertVerifier::RequestParams(test_cert, "www.example.com", + CertVerifier::VERIFY_DISABLE_NETWORK_FETCHES, + /*ocsp_response=*/std::string(), + /*sct_list=*/std::string()), + &verify_result, callback.callback(), &request, NetLogWithSource()); + ASSERT_THAT(error, IsError(ERR_IO_PENDING)); + EXPECT_TRUE(request); + error = callback.WaitForResult(); + EXPECT_TRUE(IsCertificateError(error)); + EXPECT_THAT(error, IsError(ERR_CERT_REVOKED)); + + testing::Mock::VerifyAndClearExpectations(mock_verify_proc_.get()); +} + // Tests swapping in new Chrome Root Store Data. TEST_F(MultiThreadedCertVerifierTest, VerifyProcChangeChromeRootStore) { CertVerifierObserverCounter observer_counter(verifier_.get());
diff --git a/net/ssl/ssl_config_service.cc b/net/ssl/ssl_config_service.cc index c54a7ff..0bb171c0 100644 --- a/net/ssl/ssl_config_service.cc +++ b/net/ssl/ssl_config_service.cc
@@ -20,10 +20,10 @@ const net::SSLContextConfig& config2) { return std::tie(config1.version_min, config1.version_max, config1.disabled_cipher_suites, config1.post_quantum_enabled, - config1.ech_enabled, config1.insecure_hash_enabled) == + config1.ech_enabled, config1.insecure_hash_override) == std::tie(config2.version_min, config2.version_max, config2.disabled_cipher_suites, config2.post_quantum_enabled, - config2.ech_enabled, config2.insecure_hash_enabled); + config2.ech_enabled, config2.insecure_hash_override); } } // namespace @@ -42,15 +42,8 @@ } bool SSLContextConfig::InsecureHashesInTLSHandshakesEnabled() const { - switch (insecure_hash_enabled) { - case insecure_hash_enabled_value::kUnset: - return base::FeatureList::IsEnabled(features::kSHA1ServerSignature); - case insecure_hash_enabled_value::kEnabled: - return true; - case insecure_hash_enabled_value::kDisabled: - return false; - } - NOTREACHED(); + return insecure_hash_override.value_or( + base::FeatureList::IsEnabled(features::kSHA1ServerSignature)); } SSLConfigService::SSLConfigService()
diff --git a/net/ssl/ssl_config_service.h b/net/ssl/ssl_config_service.h index 9417e55..e7c229d 100644 --- a/net/ssl/ssl_config_service.h +++ b/net/ssl/ssl_config_service.h
@@ -10,6 +10,7 @@ #include "base/observer_list.h" #include "net/base/net_export.h" #include "net/ssl/ssl_config.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace net { @@ -52,16 +53,9 @@ // ECH is enabled, use `EncryptedClientHelloEnabled` instead. bool ech_enabled = true; - // If kEnabled, allows insecure hashes in TLS handshakes. If kDisabled, - // disallows insecure hashes in TLS handshakes. If kUnset use hashes - // determined by feature flags. - enum class insecure_hash_enabled_value { - kUnset, - kEnabled, - kDisabled, - }; - insecure_hash_enabled_value insecure_hash_enabled = - insecure_hash_enabled_value::kUnset; + // If specified, controls whether insecure hashes are allowed in TLS + // handshakes. If `absl::nullopt`, this is determined by feature flags. + absl::optional<bool> insecure_hash_override; // ADDING MORE HERE? Don't forget to update `SSLContextConfigsAreEqual`. };
diff --git a/printing/printing_context.cc b/printing/printing_context.cc index a6ce93f..370dedf 100644 --- a/printing/printing_context.cc +++ b/printing/printing_context.cc
@@ -201,8 +201,12 @@ } #endif -void PrintingContext::ApplyPrintSettings(const PrintSettings& settings) { +void PrintingContext::SetPrintSettings(const PrintSettings& settings) { *settings_ = settings; +} + +void PrintingContext::ApplyPrintSettings(const PrintSettings& settings) { + SetPrintSettings(settings); #if !BUILDFLAG(ENABLE_OOP_BASIC_PRINT_DIALOG) if (skip_system_calls()) {
diff --git a/printing/printing_context.h b/printing/printing_context.h index 7582c73..2fb3aef07 100644 --- a/printing/printing_context.h +++ b/printing/printing_context.h
@@ -109,10 +109,17 @@ std::unique_ptr<PrintSettings> job_settings); #endif + // Sets the print settings to `settings`. + void SetPrintSettings(const PrintSettings& settings); + // Applies the print settings to this context. Intended to be used only by // the Print Backend service process. void ApplyPrintSettings(const PrintSettings& settings); + // Set the printable area in print settings to be the default printable area. + // Intended to be used only for virtual printers. + void SetDefaultPrintableAreaForVirtualPrinters(); + // Does platform specific setup of the printer before the printing. Signal the // printer that a document is about to be spooled. // Warning: This function enters a message loop. That may cause side effects @@ -202,8 +209,6 @@ // Does bookkeeping when an error occurs. virtual mojom::ResultCode OnError(); - void SetDefaultPrintableAreaForVirtualPrinters(); - // Complete print context settings. std::unique_ptr<PrintSettings> settings_;
diff --git a/sandbox/linux/system_headers/linux_prctl.h b/sandbox/linux/system_headers/linux_prctl.h index c08cee91..bf4971c 100644 --- a/sandbox/linux/system_headers/linux_prctl.h +++ b/sandbox/linux/system_headers/linux_prctl.h
@@ -15,14 +15,19 @@ #define PR_SET_TIMERSLACK 29 #endif -#if BUILDFLAG(IS_ANDROID) - +// The PR_SET_VMA* symbols are originally from // https://android.googlesource.com/platform/bionic/+/lollipop-release/libc/private/bionic_prctl.h +// and were subsequently added to mainline Linux in Jan 2022. +// +// We conditionally define these symbols here to support older +// GNU/Linux operating systems that may not have these symbols yet. #if !defined(PR_SET_VMA) #define PR_SET_VMA 0x53564d41 #endif -#endif // BUILDFLAG(IS_ANDROID) +#if !defined(PR_SET_VMA_ANON_NAME) +#define PR_SET_VMA_ANON_NAME 0 +#endif #if !defined(PR_SET_PTRACER) #define PR_SET_PTRACER 0x59616d61
diff --git a/services/accessibility/features/mojo/mojo_watcher.cc b/services/accessibility/features/mojo/mojo_watcher.cc index 3cc9c51..12994bcc 100644 --- a/services/accessibility/features/mojo/mojo_watcher.cc +++ b/services/accessibility/features/mojo/mojo_watcher.cc
@@ -319,7 +319,8 @@ if (result == MOJO_RESULT_FAILED_PRECONDITION) { DCHECK_EQ(1u, num_blocking_events); - DCHECK_EQ(reinterpret_cast<uintptr_t>(this), + DCHECK_EQ(reinterpret_cast<uintptr_t>( + reinterpret_cast<uintptr_t>(persistent_wrap_.get())), blocking_event.trigger_context); *ready_result = blocking_event.result; return result;
diff --git a/services/network/public/mojom/ssl_config.mojom b/services/network/public/mojom/ssl_config.mojom index 10039bee..29edc1a 100644 --- a/services/network/public/mojom/ssl_config.mojom +++ b/services/network/public/mojom/ssl_config.mojom
@@ -4,17 +4,13 @@ module network.mojom; +import "services/network/public/mojom/optional_bool.mojom"; + enum SSLVersion { kTLS12, kTLS13, }; -enum insecure_hash_enabled_value { - kUnset, - kEnabled, - kDisabled, -}; - // This is a combination of net::SSLContextConfig and // net::CertVerifier::Config's fields. See those two classes for descriptions. struct SSLConfig { @@ -51,10 +47,9 @@ // may be enabled or disabled, depending on feature flags. bool ech_enabled = true; - // If kEnabled, allows insecure hashes in TLS handshakes. If kDisabled, - // disallows insecure hashes in TLS handshakes. If kUnset use hashes - // determined by feature flags. - insecure_hash_enabled_value insecure_hash_enabled = kUnset; + // If specified, controls whether insecure hashes are allowed in TLS + // handshakes. If kUnset, this is determined by feature flags. + OptionalBool insecure_hash_override = kUnset; }; // Receives SSL configuration updates.
diff --git a/services/network/ssl_config_type_converter.cc b/services/network/ssl_config_type_converter.cc index 487cb08..3455647 100644 --- a/services/network/ssl_config_type_converter.cc +++ b/services/network/ssl_config_type_converter.cc
@@ -6,9 +6,24 @@ #include "base/check_op.h" #include "base/notreached.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace mojo { +namespace { +absl::optional<bool> OptionalBoolFromMojo(network::mojom::OptionalBool v) { + switch (v) { + case network::mojom::OptionalBool::kTrue: + return absl::make_optional(true); + case network::mojom::OptionalBool::kFalse: + return absl::make_optional(false); + case network::mojom::OptionalBool::kUnset: + return absl::nullopt; + } + NOTREACHED_NORETURN(); +} +} // namespace + int MojoSSLVersionToNetSSLVersion(network::mojom::SSLVersion mojo_version) { switch (mojo_version) { case network::mojom::SSLVersion::kTLS12: @@ -33,20 +48,8 @@ net_config.disabled_cipher_suites = mojo_config->disabled_cipher_suites; net_config.post_quantum_enabled = mojo_config->post_quantum_enabled; net_config.ech_enabled = mojo_config->ech_enabled; - switch (mojo_config->insecure_hash_enabled) { - case network::mojom::insecure_hash_enabled_value::kUnset: - net_config.insecure_hash_enabled = - net::SSLContextConfig::insecure_hash_enabled_value::kUnset; - break; - case network::mojom::insecure_hash_enabled_value::kEnabled: - net_config.insecure_hash_enabled = - net::SSLContextConfig::insecure_hash_enabled_value::kEnabled; - break; - case network::mojom::insecure_hash_enabled_value::kDisabled: - net_config.insecure_hash_enabled = - net::SSLContextConfig::insecure_hash_enabled_value::kDisabled; - break; - } + net_config.insecure_hash_override = + OptionalBoolFromMojo(mojo_config->insecure_hash_override); return net_config; }
diff --git a/services/viz/public/mojom/BUILD.gn b/services/viz/public/mojom/BUILD.gn index a4bc44b..17f0b9ab 100644 --- a/services/viz/public/mojom/BUILD.gn +++ b/services/viz/public/mojom/BUILD.gn
@@ -24,6 +24,7 @@ "compositing/frame_sink_bundle_id.mojom", "compositing/frame_sink_id.mojom", "compositing/frame_timing_details.mojom", + "compositing/layer_context.mojom", "compositing/local_surface_id.mojom", "compositing/paint_filter.mojom", "compositing/quads.mojom",
diff --git a/services/viz/public/mojom/compositing/compositor_frame_sink.mojom b/services/viz/public/mojom/compositing/compositor_frame_sink.mojom index f7fd878..f0515087 100644 --- a/services/viz/public/mojom/compositing/compositor_frame_sink.mojom +++ b/services/viz/public/mojom/compositing/compositor_frame_sink.mojom
@@ -8,6 +8,7 @@ import "mojo/public/mojom/base/shared_memory.mojom"; import "services/viz/public/mojom/compositing/begin_frame_args.mojom"; import "services/viz/public/mojom/compositing/compositor_frame.mojom"; +import "services/viz/public/mojom/compositing/layer_context.mojom"; import "services/viz/public/mojom/compositing/local_surface_id.mojom"; import "services/viz/public/mojom/compositing/frame_timing_details.mojom"; import "services/viz/public/mojom/compositing/returned_resource.mojom"; @@ -93,6 +94,13 @@ // are silently ignored. InitializeCompositorFrameSinkType(CompositorFrameSinkType type); + // Binds to the LayerContext interface for this frame sink. Once this is bound + // the frame sink is permanently in LayerContext mode and the client should no + // longer submit frames through the CompositorFrameSink interface. Instead + // frames will automtaically be submitted by Viz based on the state of a + // GPU-side layer tree which can be manipulated through this LayerContext. + BindLayerContext(PendingLayerContext context); + // Informs the display compositor the IDs of the thread involved in frame // production. This is used on Android PerformanceHint API to dynamically // adjust performance to allow power saving.
diff --git a/services/viz/public/mojom/compositing/layer_context.mojom b/services/viz/public/mojom/compositing/layer_context.mojom new file mode 100644 index 0000000..84b8e1b --- /dev/null +++ b/services/viz/public/mojom/compositing/layer_context.mojom
@@ -0,0 +1,47 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +module viz.mojom; + +import "ui/gfx/geometry/mojom/geometry.mojom"; +import "services/viz/public/mojom/compositing/begin_frame_args.mojom"; +import "services/viz/public/mojom/compositing/local_surface_id.mojom"; + +// Metadata about a layer tree to be updated with each LayerContext commit. +struct LayerTreeUpdate { + gfx.mojom.Rect device_viewport; + float device_scale_factor; + LocalSurfaceId local_surface_id_from_parent; +}; + +// Drives updates to a GPU-side LayerTreeHostImpl from its corresponding +// client-side (e.g. renderer- or browser-side) LayerTreeHost. +interface LayerContext { + // Updates the LocalSurfaceId associated with the tree. + SetTargetLocalSurfaceId(LocalSurfaceId id); + + // Globally controls whether the tree contents are visible. + SetVisible(bool visible); + + // Flushes pending updates from the client to the LayerTreeHostImpl. + Commit(LayerTreeUpdate update); +}; + +// Provides feedback from a GPU-side LayerTreeHostImpl to its corresponding +// client-side (e.g. renderer- or browser-side) LayerTreeHost. +interface LayerContextClient { + // Sent by the LayerTreeHostImpl when it needs to produce a new frame soon and + // the client had previously indicated that it wants an opporunity to make + // changes to the tree before that frame is drawn. + OnRequestCommitForFrame(BeginFrameArgs args); +}; + +// Parameters needed to bind a LayerContext endpoint via a CompositorFrameSink. +struct PendingLayerContext { + // TODO(https://crbug.com/1431762): De-associate these interfaces from + // CompositorFrameSink. + pending_associated_receiver<LayerContext> receiver; + pending_associated_remote<LayerContextClient> client; +}; +
diff --git a/testing/buildbot/query_optimal_shard_counts.py b/testing/buildbot/query_optimal_shard_counts.py index ac16ea7..563e26c0 100755 --- a/testing/buildbot/query_optimal_shard_counts.py +++ b/testing/buildbot/query_optimal_shard_counts.py
@@ -12,6 +12,7 @@ import argparse import datetime import json +import os import subprocess import sys @@ -20,7 +21,7 @@ # TODO(crbug.com/1418199): Replace with queried, per-suite overheads, once # infra is set up to support automated overhead measurements. # See go/nplus1shardsproposal -DEFAULT_OVERHEAD_SEC = 60 * 0.5 +DEFAULT_OVERHEAD_SEC = 60 ANDROID_OVERHEAD_SEC = 60 * 2 # Builders that should currently not be autosharded because they don't use GCE @@ -277,6 +278,11 @@ '-o', action='store', help='The filename to store bigquery results.') + parser.add_argument('--overwrite-output-file', + action='store_true', + help='If there is already an output-file written, ' + 'overwrite the contents with new data. Otherwise, results' + ' will be merged with existing file.') parser.add_argument('--lookback-days', default=14, type=int, @@ -336,7 +342,16 @@ percentile=opts.percentile, min_sample_size=opts.min_sample_size, ) + data = {} + new_data = {} + verbose_new_data = {} + if not opts.overwrite_output_file and os.path.exists(opts.output_file): + with open(opts.output_file, 'r') as existing_output_file: + print('Output file already exists. Will merge query results with existing' + ' output file.') + data = json.load(existing_output_file) + for r in results: builder_group = r['waterfall_builder_group'] builder_name = r['waterfall_builder_name'] @@ -345,8 +360,9 @@ 'shards': r['optimal_shard_count'], }, } + verbose_dict = shard_dict.copy() if opts.verbose: - suite_dict = shard_dict[r['test_suite']] + suite_dict = verbose_dict[r['test_suite']] suite_dict['current_shard_count'] = r['shard_count'] suite_dict['current_percentile_duration_minutes'] = r[ 'percentile_duration_minutes'] @@ -359,17 +375,30 @@ suite_dict['avg_pending_time_sec'] = r['avg_pending_time_sec'] suite_dict['p50_pending_time_sec'] = r['p50_pending_time_sec'] suite_dict['p90_pending_time_sec'] = r['p90_pending_time_sec'] + verbose_new_data.setdefault(builder_group, + {}).setdefault(builder_name, + {}).update(shard_dict) data.setdefault(builder_group, {}).setdefault(builder_name, {}).update(shard_dict) + new_data.setdefault(builder_group, {}).setdefault(builder_name, + {}).update(shard_dict) output_data = json.dumps(data, indent=4, separators=(',', ': '), sort_keys=True) + print('Results from query:') + if opts.verbose: + print(json.dumps(verbose_new_data, indent=4, separators=(',', ': '))) + else: + print(json.dumps(new_data, indent=4, separators=(',', ': '))) + if opts.output_file: + if opts.overwrite_output_file and os.path.exists(opts.output_file): + print('Will overwrite existing output file.') with open(opts.output_file, 'w') as output_file: + print('Writing to output file.') output_file.write(output_data) - print(output_data) if __name__ == '__main__':
diff --git a/testing/buildbot/query_optimal_shard_counts_unittest.py b/testing/buildbot/query_optimal_shard_counts_unittest.py index ab5a3c2b..8e7ce84 100755 --- a/testing/buildbot/query_optimal_shard_counts_unittest.py +++ b/testing/buildbot/query_optimal_shard_counts_unittest.py
@@ -70,6 +70,17 @@ 'query_optimal_shard_counts.subprocess.check_output') self._mock_check_output = self._mock_check_output_patcher.start() self.output_file_handle, self.output_file = tempfile.mkstemp() + with open(self.output_file, 'w') as f: + f.write( + json.dumps({ + 'chromium.builder_group': { + 'builder_name': { + 'fake_test_suite': { + 'shards': 4 + } + } + }, + })) def tearDown(self): os.remove(self.output_file) @@ -98,7 +109,7 @@ ]) query_optimal_shard_counts.main(['--output-file', self.output_file]) with open(self.output_file, 'r') as f: - script_result = json.loads(f.read()) + script_result = json.load(f) self.assertEqual( script_result['chromium.linux']['Linux Tests'], {'browser_tests': { @@ -126,7 +137,7 @@ ]) query_optimal_shard_counts.main(['--output-file', self.output_file]) with open(self.output_file, 'r') as f: - script_result = json.loads(f.read()) + script_result = json.load(f) self.assertEqual( len(script_result['chromium.linux']), 2, @@ -153,7 +164,7 @@ query_optimal_shard_counts.main( ['--output-file', self.output_file, '--verbose']) with open(self.output_file, 'r') as f: - script_result = json.loads(f.read()) + script_result = json.load(f) expected_dict = { 'shards': DEFAULT_DICT['optimal_shard_count'], @@ -171,9 +182,10 @@ def testNoQueryResults(self): self._mock_check_output.return_value = json.dumps([]) - query_optimal_shard_counts.main(['--output-file', self.output_file]) + query_optimal_shard_counts.main( + ['--output-file', self.output_file, '--overwrite-output-file']) with open(self.output_file, 'r') as f: - script_result = json.loads(f.read()) + script_result = json.load(f) self.assertEqual({}, script_result) def testLookbackDates(self): @@ -214,6 +226,97 @@ self.assertTrue(any('2023-01-01' in arg for arg in big_query_arg_list)) self.assertTrue(any('2022-12-29' in arg for arg in big_query_arg_list)) + def testMergeExistingOutputFile(self): + self._mock_check_output.return_value = json.dumps([ + query_response_test_suite_dict( + waterfall_builder_group='chromium.linux', + waterfall_builder_name='Linux Tests', + try_builder='linux-rel', + test_suite='browser_tests', + optimal_shard_count=16, + ), + ]) + existing_output_file_data = json.dumps({ + 'chromium.linux': { + 'Linux Tests': { + 'browser_tests': { + 'shards': 15, + }, + 'interactive_ui_tests': { + 'shards': 3, + } + }, + }, + 'chromium.android': { + 'android-12-x64-rel': { + 'webview_instrumentation_test_apk': { + 'shards': 11, + } + } + } + }) + with open(self.output_file, 'w') as f: + f.write(existing_output_file_data) + query_optimal_shard_counts.main(['--output-file', self.output_file]) + with open(self.output_file, 'r') as f: + script_result = json.load(f) + self.assertEqual( + script_result['chromium.linux']['Linux Tests']['browser_tests'], + {'shards': 16}, + ) + self.assertEqual( + script_result['chromium.linux']['Linux Tests']['interactive_ui_tests'], + {'shards': 3}, + ) + self.assertEqual( + script_result['chromium.android']['android-12-x64-rel'] + ['webview_instrumentation_test_apk'], + {'shards': 11}, + ) + + def testOverwriteExistingOutputFile(self): + self._mock_check_output.return_value = json.dumps([ + query_response_test_suite_dict( + waterfall_builder_group='chromium.linux', + waterfall_builder_name='Linux Tests', + try_builder='linux-rel', + test_suite='browser_tests', + optimal_shard_count=16, + ), + ]) + existing_output_file_data = json.dumps({ + 'chromium.linux': { + 'Linux Tests': { + 'browser_tests': { + 'shards': 15, + }, + 'interactive_ui_tests': { + 'shards': 3, + } + }, + }, + 'chromium.android': { + 'android-12-x64-rel': { + 'webview_instrumentation_test_apk': { + 'shards': 11, + } + } + } + }) + with open(self.output_file, 'w') as f: + f.write(existing_output_file_data) + query_optimal_shard_counts.main( + ['--output-file', self.output_file, '--overwrite-output-file']) + with open(self.output_file, 'r') as f: + script_result = json.load(f) + self.assertEqual( + script_result['chromium.linux']['Linux Tests']['browser_tests'], + {'shards': 16}, + ) + self.assertIsNone(script_result['chromium.linux']['Linux Tests'].get( + 'interactive_ui_tests')) + self.assertIsNone(script_result.get('chromium.android')) + if __name__ == '__main__': unittest.main(verbosity=2)
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index 9bf9391..6f852a8 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -1972,6 +1972,26 @@ ] } ], + "BlockMidiByDefault": [ + { + "platforms": [ + "android", + "chromeos", + "chromeos_lacros", + "linux", + "mac", + "windows" + ], + "experiments": [ + { + "name": "Enabled", + "enable_features": [ + "BlockMidiByDefault" + ] + } + ] + } + ], "BluetoothQualityReport": [ { "platforms": [
diff --git a/third_party/android_deps/buildSrc/src/main/groovy/BuildConfigGenerator.groovy b/third_party/android_deps/buildSrc/src/main/groovy/BuildConfigGenerator.groovy index 8196c6d..b932f47 100644 --- a/third_party/android_deps/buildSrc/src/main/groovy/BuildConfigGenerator.groovy +++ b/third_party/android_deps/buildSrc/src/main/groovy/BuildConfigGenerator.groovy
@@ -871,6 +871,12 @@ // Every target that has a dep on androidx_window_window will need these checks turned off. sb.append(' enable_bytecode_checks = false\n') break + case 'androidx_credentials_credentials': + sb.append('\n') + // We are overriding 1.0.0-SNAPSHOT to 1.2.0-alpha03 which has different deps. + // TODO(1433052): remove after 1.2.0 becomes part of the normal release structure. + sb.append(' deps += [":androidx_core_core_java"]\n') + break case 'androidx_asynclayoutinflater_asynclayoutinflater': sb.append('\n') sb.append(' # References AppCompatActivity using reflection, if exists.\n')
diff --git a/third_party/androidx/build.gradle.template b/third_party/androidx/build.gradle.template index 10dfc480..3362950 100644 --- a/third_party/androidx/build.gradle.template +++ b/third_party/androidx/build.gradle.template
@@ -83,6 +83,7 @@ compile 'androidx.legacy:legacy-support-core-utils:1.0.0' compile 'androidx.documentfile:documentfile:{{androidx_dependency_version}}' compile 'androidx.print:print:{{androidx_dependency_version}}' + compile 'androidx.credentials:credentials:{{androidx_dependency_version}}' compile 'androidx.multidex:multidex:2.0.0' compile 'androidx.webkit:webkit:{{androidx_dependency_version}}'
diff --git a/third_party/androidx/fetch_all_androidx.py b/third_party/androidx/fetch_all_androidx.py index aea1e4a..ca618dd 100755 --- a/third_party/androidx/fetch_all_androidx.py +++ b/third_party/androidx/fetch_all_androidx.py
@@ -54,6 +54,9 @@ 'https://androidx.dev/snapshots/builds/9668027/artifacts/repository/' 'androidx/recyclerview/recyclerview/1.4.0-SNAPSHOT/' 'recyclerview-1.4.0-20230228.234124-1.aar'), + ('androidx_credentials_credentials/credentials-1.0.0-SNAPSHOT.aar', + 'https://dl.google.com/android/maven2/androidx/credentials/credentials/' + '1.2.0-alpha03/credentials-1.2.0-alpha03.aar'), ]
diff --git a/third_party/blink/common/BUILD.gn b/third_party/blink/common/BUILD.gn index b58db79..631ef445 100644 --- a/third_party/blink/common/BUILD.gn +++ b/third_party/blink/common/BUILD.gn
@@ -324,7 +324,6 @@ "//ui/display", "//ui/display/mojom", "//ui/events:events_base", - "//ui/events/mojom:event_latency_metadata_mojom", "//ui/latency/mojom:shared_mojom_traits", ]
diff --git a/third_party/blink/common/DEPS b/third_party/blink/common/DEPS index 77997ecf2..40bf560cf 100644 --- a/third_party/blink/common/DEPS +++ b/third_party/blink/common/DEPS
@@ -41,7 +41,6 @@ "+ui/base/dragdrop/mojom", "+ui/display", "+ui/events/base_event_utils.h", - "+ui/events/mojom/event_latency_metadata_mojom_traits.h", "+ui/gfx/presentation_feedback.h", "+ui/gfx/transform.h", "+ui/gfx/geometry",
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc index 286ff369..e49f22d 100644 --- a/third_party/blink/common/features.cc +++ b/third_party/blink/common/features.cc
@@ -1263,11 +1263,6 @@ "ReportFCPOnlyOnSuccessfulCommit", base::FEATURE_ENABLED_BY_DEFAULT); -// TODO(crbug.com/1382005): Deprecate this flag. -BASE_FEATURE(kRegionCaptureExperimentalSubtypes, - "RegionCaptureExperimentalSubtypes", - base::FEATURE_ENABLED_BY_DEFAULT); - // When enabled, Source Location blocking BFCache is captured // to send it to the browser. BASE_FEATURE(kRegisterJSSourceLocationBlockingBFCache,
diff --git a/third_party/blink/common/input/web_coalesced_input_event_mojom_traits.cc b/third_party/blink/common/input/web_coalesced_input_event_mojom_traits.cc index 1adbb11..cae8aad 100644 --- a/third_party/blink/common/input/web_coalesced_input_event_mojom_traits.cc +++ b/third_party/blink/common/input/web_coalesced_input_event_mojom_traits.cc
@@ -13,7 +13,6 @@ #include "third_party/blink/public/common/input/web_gesture_event.h" #include "third_party/blink/public/common/input/web_keyboard_event.h" #include "third_party/blink/public/common/input/web_mouse_wheel_event.h" -#include "ui/events/mojom/event_latency_metadata_mojom_traits.h" #include "ui/latency/mojom/latency_info_mojom_traits.h" namespace mojo { @@ -362,12 +361,6 @@ return false; } - ui::EventLatencyMetadata event_latency_metadata; - if (!event.ReadEventLatencyMetadata(&event_latency_metadata)) { - return false; - }; - input_event->GetModifiableEventLatencyMetadata() = - std::move(event_latency_metadata); ui::LatencyInfo latency_info; if (!event.ReadLatency(&latency_info)) return false;
diff --git a/third_party/blink/common/shared_storage/shared_storage_utils.cc b/third_party/blink/common/shared_storage/shared_storage_utils.cc index d99abe9..897e44a6 100644 --- a/third_party/blink/common/shared_storage/shared_storage_utils.cc +++ b/third_party/blink/common/shared_storage/shared_storage_utils.cc
@@ -33,4 +33,10 @@ error_type); } +bool ShouldDefinePrivateAggregationInSharedStorage() { + return base::FeatureList::IsEnabled( + blink::features::kPrivateAggregationApi) && + blink::features::kPrivateAggregationApiEnabledInSharedStorage.Get(); +} + } // namespace blink
diff --git a/third_party/blink/public/common/DEPS b/third_party/blink/public/common/DEPS index 74484c759..c2c3018 100644 --- a/third_party/blink/public/common/DEPS +++ b/third_party/blink/public/common/DEPS
@@ -36,6 +36,5 @@ "+ui/gfx/display_color_spaces.h", "+ui/gfx/geometry", "+ui/latency/latency_info.h", - "+ui/events/event_latency_metadata.h", "+url", ]
diff --git a/third_party/blink/public/common/features.h b/third_party/blink/public/common/features.h index b17c255..8b3bf44 100644 --- a/third_party/blink/public/common/features.h +++ b/third_party/blink/public/common/features.h
@@ -582,10 +582,6 @@ // a commit failure (see crbug.com/1257607). BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kReportFCPOnlyOnSuccessfulCommit); -// 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 BASE_DECLARE_FEATURE(kRegionCaptureExperimentalSubtypes); - BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE( kRegisterJSSourceLocationBlockingBFCache);
diff --git a/third_party/blink/public/common/input/web_coalesced_input_event_mojom_traits.h b/third_party/blink/public/common/input/web_coalesced_input_event_mojom_traits.h index 31edf22..aa7f806 100644 --- a/third_party/blink/public/common/input/web_coalesced_input_event_mojom_traits.h +++ b/third_party/blink/public/common/input/web_coalesced_input_event_mojom_traits.h
@@ -7,7 +7,6 @@ #include "third_party/blink/public/common/common_export.h" #include "third_party/blink/public/common/input/web_coalesced_input_event.h" -#include "third_party/blink/public/common/input/web_input_event.h" #include "third_party/blink/public/mojom/input/input_handler.mojom.h" namespace mojo { @@ -36,11 +35,6 @@ return event->latency_info(); } - static const ui::EventLatencyMetadata& event_latency_metadata( - const std::unique_ptr<blink::WebCoalescedInputEvent>& event) { - return event->Event().GetEventLatencyMetadata(); - } - static blink::mojom::KeyDataPtr key_data( const std::unique_ptr<blink::WebCoalescedInputEvent>& event); static blink::mojom::PointerDataPtr pointer_data(
diff --git a/third_party/blink/public/common/input/web_input_event.h b/third_party/blink/public/common/input/web_input_event.h index 7fe9ec3..d6ee25c8 100644 --- a/third_party/blink/public/common/input/web_input_event.h +++ b/third_party/blink/public/common/input/web_input_event.h
@@ -40,7 +40,6 @@ #include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/blink/public/common/common_export.h" #include "third_party/blink/public/mojom/input/input_event.mojom-shared.h" -#include "ui/events/event_latency_metadata.h" #include "ui/events/types/event_type.h" #include "ui/gfx/geometry/point_f.h" #include "ui/gfx/geometry/vector2d_f.h" @@ -315,13 +314,6 @@ base::TimeTicks TimeStamp() const { return time_stamp_; } void SetTimeStamp(base::TimeTicks time_stamp) { time_stamp_ = time_stamp; } - const ui::EventLatencyMetadata& GetEventLatencyMetadata() const { - return event_latency_metadata_; - } - ui::EventLatencyMetadata& GetModifiableEventLatencyMetadata() { - return event_latency_metadata_; - } - void SetTargetFrameMovedRecently() { modifiers_ |= kTargetFrameMovedRecently; } @@ -365,8 +357,6 @@ base::TimeTicks time_stamp_; Type type_ = Type::kUndefined; int modifiers_ = kNoModifiers; - - ui::EventLatencyMetadata event_latency_metadata_; }; } // namespace blink
diff --git a/third_party/blink/public/common/shared_storage/shared_storage_utils.h b/third_party/blink/public/common/shared_storage/shared_storage_utils.h index 6327335b..afce034 100644 --- a/third_party/blink/public/common/shared_storage/shared_storage_utils.h +++ b/third_party/blink/public/common/shared_storage/shared_storage_utils.h
@@ -65,6 +65,10 @@ BLINK_COMMON_EXPORT void LogSharedStorageWorkletError( SharedStorageWorkletErrorType error_type); +// Whether `privateAggregation` should be exposed to `SharedStorageWorklet` +// scope. +BLINK_COMMON_EXPORT bool ShouldDefinePrivateAggregationInSharedStorage(); + } // namespace blink #endif // THIRD_PARTY_BLINK_PUBLIC_COMMON_SHARED_STORAGE_SHARED_STORAGE_UTILS_H_
diff --git a/third_party/blink/public/mojom/BUILD.gn b/third_party/blink/public/mojom/BUILD.gn index 122f66b..21ca9a1 100644 --- a/third_party/blink/public/mojom/BUILD.gn +++ b/third_party/blink/public/mojom/BUILD.gn
@@ -297,7 +297,6 @@ "//ui/base/mojom", "//ui/display/mojom", "//ui/events/mojom", - "//ui/events/mojom:event_latency_metadata_mojom", "//ui/gfx/geometry/mojom", "//ui/gfx/mojom", "//ui/gfx/range/mojom",
diff --git a/third_party/blink/public/mojom/input/input_handler.mojom b/third_party/blink/public/mojom/input/input_handler.mojom index 7e289ec..020807b 100644 --- a/third_party/blink/public/mojom/input/input_handler.mojom +++ b/third_party/blink/public/mojom/input/input_handler.mojom
@@ -4,28 +4,27 @@ module blink.mojom; -import "cc/mojom/browser_controls_state.mojom"; import "cc/mojom/overscroll_behavior.mojom"; import "cc/mojom/touch_action.mojom"; import "mojo/public/mojom/base/string16.mojom"; import "mojo/public/mojom/base/time.mojom"; import "third_party/blink/public/mojom/input/gesture_event.mojom"; -import "third_party/blink/public/mojom/input/handwriting_gesture_result.mojom"; -import "third_party/blink/public/mojom/input/input_event_result.mojom"; import "third_party/blink/public/mojom/input/input_event.mojom"; +import "third_party/blink/public/mojom/input/input_event_result.mojom"; import "third_party/blink/public/mojom/input/pointer_lock_context.mojom"; import "third_party/blink/public/mojom/input/pointer_lock_result.mojom"; -import "third_party/blink/public/mojom/input/stylus_writing_gesture.mojom"; import "third_party/blink/public/mojom/input/touch_event.mojom"; import "third_party/blink/public/mojom/selection_menu/selection_menu_behavior.mojom"; import "ui/base/ime/mojom/ime_types.mojom"; -import "ui/events/mojom/event_constants.mojom"; -import "ui/events/mojom/event_latency_metadata.mojom"; +import "third_party/blink/public/mojom/input/handwriting_gesture_result.mojom"; +import "third_party/blink/public/mojom/input/stylus_writing_gesture.mojom"; import "ui/events/mojom/event.mojom"; +import "ui/events/mojom/event_constants.mojom"; import "ui/events/mojom/scroll_granularity.mojom"; import "ui/gfx/geometry/mojom/geometry.mojom"; import "ui/gfx/range/mojom/range.mojom"; import "ui/latency/mojom/latency_info.mojom"; +import "cc/mojom/browser_controls_state.mojom"; [EnableIf=is_android] import "third_party/blink/public/mojom/input/synchronous_compositor.mojom"; @@ -170,7 +169,6 @@ int32 modifiers; mojo_base.mojom.TimeTicks timestamp; ui.mojom.LatencyInfo latency; - ui.mojom.EventLatencyMetadata event_latency_metadata; KeyData? key_data; PointerData? pointer_data; GestureData? gesture_data;
diff --git a/third_party/blink/public/mojom/shared_storage/shared_storage_worklet_service.mojom b/third_party/blink/public/mojom/shared_storage/shared_storage_worklet_service.mojom index 66e2a3a..be19f13 100644 --- a/third_party/blink/public/mojom/shared_storage/shared_storage_worklet_service.mojom +++ b/third_party/blink/public/mojom/shared_storage/shared_storage_worklet_service.mojom
@@ -115,8 +115,7 @@ // checked at the Mojo boundary to ensure it's from the same origin of the // current context. AddModule(pending_remote<network.mojom.URLLoaderFactory> url_loader_factory, - url.mojom.Url script_source_url, - bool should_define_private_aggregation_object) + url.mojom.Url script_source_url) => (bool success, string error_message); // Handle sharedStorage.runURLSelectionOperation(): run the operation
diff --git a/third_party/blink/renderer/build/scripts/templates/runtime_feature_state_override_context.cc.tmpl b/third_party/blink/renderer/build/scripts/templates/runtime_feature_state_override_context.cc.tmpl index 0869347..c471c58 100644 --- a/third_party/blink/renderer/build/scripts/templates/runtime_feature_state_override_context.cc.tmpl +++ b/third_party/blink/renderer/build/scripts/templates/runtime_feature_state_override_context.cc.tmpl
@@ -62,7 +62,7 @@ bool RuntimeFeatureStateOverrideContext:: Set{{feature.name}}Enabled(const WTF::Vector<WTF::String>& tokens) { {% if (feature.name)|string == 'DisableThirdPartyStoragePartitioning' %} - UseCounter::Count(execution_context_, + UseCounter::Count(use_counter_, WebFeature::kDisableThirdPartyStoragePartitioning); // If the base::Feature for the deprecation trial is disabled, we should // not send any overrides to the browser, so we return false immediately, @@ -83,7 +83,8 @@ [mojom::RuntimeFeatureState::k{{feature.name}}] = true; // Add successful overrides to the list of features we sent back // to the browser process. - mojom::blink::FeatureValuePtr value = mojom::blink::FeatureValue::New(true, tokens); + mojom::blink::FeatureValuePtr value = + mojom::blink::FeatureValue::New(true, tokens); origin_trial_overrides_[ mojom::RuntimeFeatureState::k{{feature.name}}] = std::move(value); @@ -132,26 +133,29 @@ } void RuntimeFeatureStateOverrideContext::EnablePersistentTrial( - const WTF::String& raw_token, - const WTF::Vector<scoped_refptr<const blink::SecurityOrigin>>& script_origins) { - GetOrBindRuntimeFeatureStateController()-> - EnablePersistentTrial(raw_token, script_origins); -} + const WTF::String& raw_token, + const WTF::Vector<scoped_refptr<const blink::SecurityOrigin>>& + script_origins) { + GetOrBindRuntimeFeatureStateController()->EnablePersistentTrial( + raw_token, script_origins); + } mojom::blink::RuntimeFeatureStateController* RuntimeFeatureStateOverrideContext::GetOrBindRuntimeFeatureStateController(){ // TODO(https://crbug.com/1410817): add support for workers/non-frames that // are enabling origin trials to send their information to the browser too. - if(!runtime_feature_state_controller_remote_.is_bound()){ - CHECK(execution_context_->IsWindow()); - execution_context_->GetBrowserInterfaceBroker().GetInterface( - runtime_feature_state_controller_remote_.BindNewPipeAndPassReceiver(execution_context_->GetTaskRunner(TaskType::kInternalDefault))); - } + if (!runtime_feature_state_controller_remote_.is_bound()) { + CHECK(send_runtime_features_to_browser_); + binding_context_->GetBrowserInterfaceBroker().GetInterface( + runtime_feature_state_controller_remote_.BindNewPipeAndPassReceiver( + binding_context_->GetTaskRunner(TaskType::kInternalDefault))); + } return runtime_feature_state_controller_remote_.get(); } void RuntimeFeatureStateOverrideContext::Trace(Visitor* visitor) const{ - visitor->Trace(execution_context_); + visitor->Trace(binding_context_); + visitor->Trace(use_counter_); visitor->Trace(runtime_feature_state_controller_remote_); }
diff --git a/third_party/blink/renderer/build/scripts/templates/runtime_feature_state_override_context.h.tmpl b/third_party/blink/renderer/build/scripts/templates/runtime_feature_state_override_context.h.tmpl index 9ecbe23..3f3622f 100644 --- a/third_party/blink/renderer/build/scripts/templates/runtime_feature_state_override_context.h.tmpl +++ b/third_party/blink/renderer/build/scripts/templates/runtime_feature_state_override_context.h.tmpl
@@ -11,9 +11,10 @@ #include "third_party/blink/public/common/origin_trials/origin_trial_feature.h" #include "third_party/blink/public/mojom/runtime_feature_state/runtime_feature_state_controller.mojom-blink.h" #include "third_party/blink/public/mojom/runtime_feature_state/runtime_feature_state.mojom-shared.h" -#include "third_party/blink/renderer/core/execution_context/execution_context.h" #include "third_party/blink/renderer/platform/heap/garbage_collected.h" +#include "third_party/blink/renderer/platform/instrumentation/use_counter.h" #include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h" +#include "third_party/blink/renderer/platform/mojo/mojo_binding_context.h" #include "third_party/blink/renderer/platform/platform_export.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" #include "third_party/blink/renderer/platform/wtf/vector.h" @@ -26,13 +27,18 @@ class PLATFORM_EXPORT RuntimeFeatureStateOverrideContext : public GarbageCollected<RuntimeFeatureStateOverrideContext> { public: - RuntimeFeatureStateOverrideContext(ExecutionContext* context) - : execution_context_(context), - runtime_feature_state_controller_remote_(context) { - DCHECK(execution_context_); - override_values_.reserve({{overridable_features|length()}}); - origin_trial_overrides_.reserve({{overridable_features|length()}}); - } + RuntimeFeatureStateOverrideContext(MojoBindingContext* binding_context, + UseCounter* use_counter, + bool send_runtime_features_to_browser) + : binding_context_(binding_context), + use_counter_(use_counter), + runtime_feature_state_controller_remote_(binding_context), + send_runtime_features_to_browser_(send_runtime_features_to_browser) { + DCHECK(binding_context); + DCHECK(use_counter); + override_values_.reserve({{overridable_features|length()}}); + origin_trial_overrides_.reserve({{overridable_features|length()}}); +} void ApplyOverrideValuesFromParams( const base::flat_map<mojom::RuntimeFeatureState, bool>& @@ -56,22 +62,32 @@ {% endfor %} void EnablePersistentTrial( - const WTF::String& raw_token, - const WTF::Vector<scoped_refptr<const blink::SecurityOrigin>>& script_origins); + const WTF::String& raw_token, + const WTF::Vector<scoped_refptr<const blink::SecurityOrigin>>& + script_origins); - const base::flat_map<mojom::RuntimeFeatureState, bool>& GetOverrideValuesForTesting() const { + const base::flat_map<mojom::RuntimeFeatureState, bool>& + GetOverrideValuesForTesting() const { return override_values_; } void Trace(Visitor*) const; private: - mojom::blink::RuntimeFeatureStateController* GetOrBindRuntimeFeatureStateController(); + mojom::blink::RuntimeFeatureStateController* + GetOrBindRuntimeFeatureStateController(); base::flat_map<mojom::RuntimeFeatureState, bool> override_values_; - base::flat_map<mojom::RuntimeFeatureState, mojom::blink::FeatureValuePtr> origin_trial_overrides_; - Member<ExecutionContext> execution_context_; - blink::HeapMojoRemote<mojom::blink::RuntimeFeatureStateController> runtime_feature_state_controller_remote_; + base::flat_map<mojom::RuntimeFeatureState, mojom::blink::FeatureValuePtr> + origin_trial_overrides_; + Member<MojoBindingContext> binding_context_; + Member<UseCounter> use_counter_; + blink::HeapMojoRemote<mojom::blink::RuntimeFeatureStateController> + runtime_feature_state_controller_remote_; + + // TODO(https://crbug.com/1410817): add support for workers/non-frames that + // are enabling origin trials to send their information to the browser too. + bool send_runtime_features_to_browser_ = false; }; } // namespace blink
diff --git a/third_party/blink/renderer/core/animation/css/css_animation_update.cc b/third_party/blink/renderer/core/animation/css/css_animation_update.cc index 6675b4a9..35c6af8 100644 --- a/third_party/blink/renderer/core/animation/css/css_animation_update.cc +++ b/third_party/blink/renderer/core/animation/css/css_animation_update.cc
@@ -29,6 +29,7 @@ updated_compositor_keyframes_ = update.UpdatedCompositorKeyframes(); changed_scroll_timelines_ = update.changed_scroll_timelines_; changed_view_timelines_ = update.changed_view_timelines_; + changed_attaching_timelines_ = update.changed_attaching_timelines_; } void CSSAnimationUpdate::Clear() { @@ -44,6 +45,7 @@ updated_compositor_keyframes_.clear(); changed_scroll_timelines_.clear(); changed_view_timelines_.clear(); + changed_attaching_timelines_.clear(); } void CSSAnimationUpdate::StartTransition(
diff --git a/third_party/blink/renderer/core/animation/css/css_animation_update.h b/third_party/blink/renderer/core/animation/css/css_animation_update.h index fdeca19..e7e3844 100644 --- a/third_party/blink/renderer/core/animation/css/css_animation_update.h +++ b/third_party/blink/renderer/core/animation/css/css_animation_update.h
@@ -202,6 +202,10 @@ changed_view_timelines_ = std::move(timelines); } + void SetChangedAttachingTimelines(AttachingTimelineMap timelines) { + changed_attaching_timelines_ = std::move(timelines); + } + const HeapVector<NewCSSAnimation>& NewAnimations() const { return new_animations_; } @@ -254,6 +258,10 @@ const CSSViewTimelineMap& ChangedViewTimelines() const { return changed_view_timelines_; } + const AttachingTimelineMap& ChangedAttachingTimelines() const { + return changed_attaching_timelines_; + } + void AdoptActiveInterpolationsForAnimations( ActiveInterpolationsMap& new_map) { new_map.swap(active_interpolations_for_animations_); @@ -282,7 +290,8 @@ !cancelled_transitions_.empty() || !finished_transitions_.empty() || !updated_compositor_keyframes_.empty() || !changed_scroll_timelines_.empty() || - !changed_view_timelines_.empty(); + !changed_view_timelines_.empty() || + !changed_attaching_timelines_.empty(); } void Trace(Visitor* visitor) const { @@ -295,6 +304,7 @@ visitor->Trace(active_interpolations_for_transitions_); visitor->Trace(changed_scroll_timelines_); visitor->Trace(changed_view_timelines_); + visitor->Trace(changed_attaching_timelines_); } private: @@ -320,6 +330,7 @@ CSSScrollTimelineMap changed_scroll_timelines_; CSSViewTimelineMap changed_view_timelines_; + AttachingTimelineMap changed_attaching_timelines_; ActiveInterpolationsMap active_interpolations_for_animations_; ActiveInterpolationsMap active_interpolations_for_transitions_;
diff --git a/third_party/blink/renderer/core/animation/css/css_animations.cc b/third_party/blink/renderer/core/animation/css/css_animations.cc index 617ae8e..8feb970b 100644 --- a/third_party/blink/renderer/core/animation/css/css_animations.cc +++ b/third_party/blink/renderer/core/animation/css/css_animations.cc
@@ -638,13 +638,12 @@ // When calculating timeline updates, we initially assume that all timelines // are going to be removed, and then erase the nullptr entries for timelines // where we discover that this doesn't apply. -template <typename TimelineType> -CSSTimelineMap<TimelineType> NullifyExistingTimelines( - const CSSTimelineMap<TimelineType>* existing_timelines) { - CSSTimelineMap<TimelineType> map; +template <typename MapType> +MapType NullifyExistingTimelines(const MapType* existing_timelines) { + MapType map; if (existing_timelines) { - for (const Member<const ScopedCSSName>& name : existing_timelines->Keys()) { - map.Set(name, nullptr); + for (const auto& key : existing_timelines->Keys()) { + map.Set(key, nullptr); } } return map; @@ -660,6 +659,15 @@ return i != timelines->end() ? i->value.Get() : nullptr; } +ScrollTimeline* GetAttachingTimeline(const AttachingTimelineMap* timelines, + ScrollTimelineAttachment* attachment) { + if (!timelines) { + return nullptr; + } + auto i = timelines->find(attachment); + return i != timelines->end() ? i->value.Get() : nullptr; +} + Element* ResolveReferenceElement(Document& document, TimelineScroller scroller, Element* reference_element) { @@ -708,14 +716,17 @@ public: CSSScrollTimelineOptions(Document& document, + TimelineAttachment attachment, TimelineScroller scroller, Element* reference_element, TimelineAxis axis) - : reference_type(ComputeReferenceType(scroller)), + : attachment(attachment), + reference_type(ComputeReferenceType(scroller)), reference_element( ResolveReferenceElement(document, scroller, reference_element)), axis(ComputeAxis(axis)) {} + TimelineAttachment attachment; ScrollTimeline::ReferenceType reference_type; Element* reference_element; ScrollTimeline::ScrollAxis axis; @@ -725,11 +736,16 @@ STACK_ALLOCATED(); public: - CSSViewTimelineOptions(Element* subject, + CSSViewTimelineOptions(TimelineAttachment attachment, + Element* subject, TimelineAxis axis, TimelineInset inset) - : subject(subject), axis(ComputeAxis(axis)), inset(inset) {} + : attachment(attachment), + subject(subject), + axis(ComputeAxis(axis)), + inset(inset) {} + TimelineAttachment attachment; Element* subject; ScrollTimeline::ScrollAxis axis; TimelineInset inset; @@ -737,13 +753,14 @@ bool TimelineMatches(const ScrollTimeline& timeline, const CSSScrollTimelineOptions& options) { - return timeline.Matches(options.reference_type, options.reference_element, - options.axis); + return timeline.Matches(options.attachment, options.reference_type, + options.reference_element, options.axis); } bool TimelineMatches(const ViewTimeline& timeline, const CSSViewTimelineOptions& options) { - return timeline.Matches(options.subject, options.axis, options.inset); + return timeline.Matches(options.attachment, options.subject, options.axis, + options.inset); } } // namespace @@ -794,14 +811,15 @@ // Note: ScrollTimeline does not use insets. ScrollTimeline* existing_timeline = GetTimeline(existing_scroll_timelines, *name); - CSSScrollTimelineOptions options(document, TimelineScroller::kSelf, + CSSScrollTimelineOptions options(document, attachment, + TimelineScroller::kSelf, &animating_element, axis); if (existing_timeline && TimelineMatches(*existing_timeline, options)) { changed_timelines.erase(name); continue; } ScrollTimeline* new_timeline = MakeGarbageCollected<ScrollTimeline>( - &document, attachment, options.reference_type, + &document, options.attachment, options.reference_type, options.reference_element, options.axis); new_timeline->ServiceAnimations(kTimingUpdateOnDemand); changed_timelines.Set(name, new_timeline); @@ -821,13 +839,13 @@ SpecifiedViewTimelines(style_builder)) { ViewTimeline* existing_timeline = GetTimeline(existing_view_timelines, *name); - CSSViewTimelineOptions options(&animating_element, axis, inset); + CSSViewTimelineOptions options(attachment, &animating_element, axis, inset); if (existing_timeline && TimelineMatches(*existing_timeline, options)) { changed_timelines.erase(name); continue; } ViewTimeline* new_timeline = MakeGarbageCollected<ViewTimeline>( - &animating_element.GetDocument(), attachment, options.subject, + &animating_element.GetDocument(), options.attachment, options.subject, options.axis, options.inset); new_timeline->ServiceAnimations(kTimingUpdateOnDemand); changed_timelines.Set(name, new_timeline); @@ -836,6 +854,159 @@ return changed_timelines; } +template <> +const CSSScrollTimelineMap* +CSSAnimations::GetExistingTimelines<CSSScrollTimelineMap>( + const TimelineData* data) { + return data ? &data->GetScrollTimelines() : nullptr; +} + +template <> +const CSSScrollTimelineMap* +CSSAnimations::GetChangedTimelines<CSSScrollTimelineMap>( + const CSSAnimationUpdate* update) { + return update ? &update->ChangedScrollTimelines() : nullptr; +} + +template <> +const CSSViewTimelineMap* +CSSAnimations::GetExistingTimelines<CSSViewTimelineMap>( + const TimelineData* data) { + return data ? &data->GetViewTimelines() : nullptr; +} + +template <> +const CSSViewTimelineMap* +CSSAnimations::GetChangedTimelines<CSSViewTimelineMap>( + const CSSAnimationUpdate* update) { + return update ? &update->ChangedViewTimelines() : nullptr; +} + +template <typename TimelineType, typename CallbackFunc> +void CSSAnimations::ForEachTimeline(const TimelineData* timeline_data, + const CSSAnimationUpdate* update, + CallbackFunc callback) { + blink::ForEachTimeline<TimelineType, CallbackFunc>( + GetExistingTimelines<CSSTimelineMap<TimelineType>>(timeline_data), + GetChangedTimelines<CSSTimelineMap<TimelineType>>(update), callback); +} + +template <typename TimelineType> +void CSSAnimations::CollectTimelinesWithAttachmentInto( + const TimelineData* timeline_data, + const CSSAnimationUpdate* update, + TimelineAttachment attachment, + CSSTimelineMap<TimelineType>& result) { + ForEachTimeline<TimelineType>( + timeline_data, update, + [attachment, &result](const ScopedCSSName& name, TimelineType* timeline) { + if (timeline->GetTimelineAttachment() == attachment) { + result.insert(name, timeline); + } + }); +} + +template <typename TimelineType> +void CSSAnimations::CalculateChangedAttachingTimelines( + const CSSTimelineMap<TimelineType>& ancestor_attached_timelines, + const CSSTimelineMap<TimelineType>& deferred_timelines, + const AttachingTimelineMap* existing_attaching_timelines, + AttachingTimelineMap& changed_attaching_timelines) { + for (auto [name, timeline] : ancestor_attached_timelines) { + auto i = deferred_timelines.find(name); + if (i == deferred_timelines.end()) { + continue; + } + + ScrollTimelineAttachment* attachment = timeline->CurrentAttachment(); + TimelineType* new_attaching_timeline = i->value.Get(); + + ScrollTimeline* existing_attaching_timeline = + GetAttachingTimeline(existing_attaching_timelines, attachment); + + if (new_attaching_timeline == existing_attaching_timeline) { + // No change, remove explicit nullptr previously added by + // CalculateAttachingTimelinesUpdate. + changed_attaching_timelines.erase(attachment); + continue; + } + + changed_attaching_timelines.Set(attachment, new_attaching_timeline); + } +} + +void CSSAnimations::CalculateAttachingTimelinesUpdate( + CSSAnimationUpdate& update, + Element& animating_element) { + const CSSAnimations::TimelineData* timeline_data = + GetTimelineData(animating_element); + + if (update.ChangedScrollTimelines().empty() && + update.ChangedViewTimelines().empty() && + (!timeline_data || timeline_data->IsEmpty())) { + return; + } + + // We assume that all existing timelines will be removed, and then erase + // explicit nullptr values from the map if we discover timelines that + // should be retained. + const AttachingTimelineMap* existing_attaching_timelines = + timeline_data ? &timeline_data->GetAttachingTimelines() : nullptr; + AttachingTimelineMap changed_attaching_timelines = + NullifyExistingTimelines(existing_attaching_timelines); + + // Find all timelines with TimelineAttachment::kAncestor attachment. + CSSScrollTimelineMap ancestor_attached_scroll_timelines; + CSSViewTimelineMap ancestor_attached_view_timelines; + + CollectTimelinesWithAttachmentInto<ScrollTimeline>( + timeline_data, &update, TimelineAttachment::kAncestor, + ancestor_attached_scroll_timelines); + CollectTimelinesWithAttachmentInto<ViewTimeline>( + timeline_data, &update, TimelineAttachment::kAncestor, + ancestor_attached_view_timelines); + + if (!ancestor_attached_scroll_timelines.empty() || + !ancestor_attached_view_timelines.empty()) { + // If we had any such timelines, we have to find the corresponding + // timelines with kDefer attachment in the ancestor chain. We do this + // by squashing all timelines in the ancestor chain into a single map + // (per timeline type). + + CSSScrollTimelineMap deferred_scroll_timelines; + CSSViewTimelineMap deferred_view_timelines; + + for (Element* ancestor = + LayoutTreeBuilderTraversal::ParentElement(animating_element); + ancestor; + ancestor = LayoutTreeBuilderTraversal::ParentElement(*ancestor)) { + const TimelineData* ancestor_data = GetTimelineData(*ancestor); + const CSSAnimationUpdate* ancestor_update = + GetPendingAnimationUpdate(*ancestor); + // Note that CollectTimelinesWithAttachmentInto will not overwrite + // names already present in the map, which means only the nearest + // instance of a name can be found in the final map. + CollectTimelinesWithAttachmentInto<ScrollTimeline>( + ancestor_data, ancestor_update, TimelineAttachment::kDefer, + deferred_scroll_timelines); + CollectTimelinesWithAttachmentInto<ViewTimeline>( + ancestor_data, ancestor_update, TimelineAttachment::kDefer, + deferred_view_timelines); + } + + // Finds the corresponding deferred timeline for each ancestor-attached + // timeline, and updates `changed_attaching_timelines` accordingly. + CalculateChangedAttachingTimelines<ScrollTimeline>( + ancestor_attached_scroll_timelines, deferred_scroll_timelines, + existing_attaching_timelines, changed_attaching_timelines); + CalculateChangedAttachingTimelines<ViewTimeline>( + ancestor_attached_view_timelines, deferred_view_timelines, + existing_attaching_timelines, changed_attaching_timelines); + } + + update.SetChangedAttachingTimelines(std::move(changed_attaching_timelines)); +} + const CSSAnimations::TimelineData* CSSAnimations::GetTimelineData( const Element& element) { const ElementAnimations* element_animations = element.GetElementAnimations(); @@ -877,6 +1048,11 @@ if (target_name.GetName() != candidate_name.GetName()) { return; } + if (candidate->GetTimelineAttachment() == TimelineAttachment::kAncestor) { + // TODO(crbug.com/1425939): We may want to treat ancestor-attached timelines + // as "local" if they aren't attached to anything. + return; + } if (RuntimeEnabledFeatures::CSSTreeScopedTimelinesEnabled()) { size_t distance = TreeScopeDistance(candidate_name.GetTreeScope(), target_name.GetTreeScope()); @@ -938,7 +1114,7 @@ TimelineType* matching_timeline = nullptr; size_t matching_distance = std::numeric_limits<size_t>::max(); - ForEachTimeline( + blink::ForEachTimeline( existing_timelines, changed_timelines, [&target_name, &matching_timeline, &matching_distance]( const ScopedCSSName& name, TimelineType* candidate_timeline) { @@ -992,16 +1168,16 @@ const StyleTimeline::ScrollData& scroll_data, AnimationTimeline* existing_timeline) { Document& document = element->GetDocument(); - CSSScrollTimelineOptions options(document, scroll_data.GetScroller(), - /* reference_element */ element, - scroll_data.GetAxis()); + CSSScrollTimelineOptions options( + document, TimelineAttachment::kLocal, scroll_data.GetScroller(), + /* reference_element */ element, scroll_data.GetAxis()); if (auto* scroll_timeline = DynamicTo<ScrollTimeline>(existing_timeline); scroll_timeline && TimelineMatches(*scroll_timeline, options)) { return scroll_timeline; } // TODO(crbug.com/1356482): Cache/re-use timelines created from scroll(). return MakeGarbageCollected<ScrollTimeline>( - &document, TimelineAttachment::kLocal, options.reference_type, + &document, options.attachment, options.reference_type, options.reference_element, options.axis); } @@ -1011,7 +1187,8 @@ AnimationTimeline* existing_timeline) { TimelineAxis axis = view_data.GetAxis(); const TimelineInset& inset = view_data.GetInset(); - CSSViewTimelineOptions options(element, axis, inset); + CSSViewTimelineOptions options(TimelineAttachment::kLocal, element, axis, + inset); if (auto* view_timeline = DynamicTo<ViewTimeline>(existing_timeline); view_timeline && TimelineMatches(*view_timeline, options)) { @@ -1019,7 +1196,7 @@ } ViewTimeline* new_timeline = MakeGarbageCollected<ViewTimeline>( - &element->GetDocument(), TimelineAttachment::kLocal, options.subject, + &element->GetDocument(), options.attachment, options.subject, options.axis, options.inset); return new_timeline; } @@ -1173,6 +1350,7 @@ const ComputedStyleBuilder& style_builder) { CalculateScrollTimelineUpdate(update, animating_element, style_builder); CalculateViewTimelineUpdate(update, animating_element, style_builder); + CalculateAttachingTimelinesUpdate(update, animating_element); } void CSSAnimations::CalculateAnimationUpdate( @@ -1687,6 +1865,17 @@ for (auto [name, value] : pending_update_.ChangedViewTimelines()) { timeline_data_.SetViewTimeline(*name, value.Get()); } + for (auto [attachment, timeline] : + pending_update_.ChangedAttachingTimelines()) { + if (ScrollTimeline* existing_timeline = + timeline_data_.GetAttachingTimeline(attachment)) { + existing_timeline->RemoveAttachment(attachment); + } + if (timeline) { + timeline->AddAttachment(attachment); + timeline_data_.SetAttachingTimeline(attachment, timeline); + } + } for (wtf_size_t paused_index : pending_update_.AnimationIndicesWithPauseToggled()) { @@ -2359,6 +2548,10 @@ entry.value->animation->Update(kTimingUpdateOnDemand); } + for (auto [attachment, timeline] : timeline_data_.GetAttachingTimelines()) { + timeline->RemoveAttachment(attachment); + } + running_animations_.clear(); transitions_.clear(); timeline_data_.Clear(); @@ -2383,9 +2576,26 @@ } } +void CSSAnimations::TimelineData::SetAttachingTimeline( + ScrollTimelineAttachment* attachment, + ScrollTimeline* timeline) { + if (timeline == nullptr) { + attaching_timelines_.erase(attachment); + } else { + attaching_timelines_.Set(attachment, timeline); + } +} + +ScrollTimeline* CSSAnimations::TimelineData::GetAttachingTimeline( + ScrollTimelineAttachment* attachment) { + auto i = attaching_timelines_.find(attachment); + return i != attaching_timelines_.end() ? i->value.Get() : nullptr; +} + void CSSAnimations::TimelineData::Trace(blink::Visitor* visitor) const { visitor->Trace(scroll_timelines_); visitor->Trace(view_timelines_); + visitor->Trace(attaching_timelines_); } namespace {
diff --git a/third_party/blink/renderer/core/animation/css/css_animations.h b/third_party/blink/renderer/core/animation/css/css_animations.h index 77f44d3..b4ad2169 100644 --- a/third_party/blink/renderer/core/animation/css/css_animations.h +++ b/third_party/blink/renderer/core/animation/css/css_animations.h
@@ -207,18 +207,26 @@ const CSSViewTimelineMap& GetViewTimelines() const { return view_timelines_; } + void SetAttachingTimeline(ScrollTimelineAttachment*, ScrollTimeline*); + ScrollTimeline* GetAttachingTimeline(ScrollTimelineAttachment*); + const AttachingTimelineMap& GetAttachingTimelines() const { + return attaching_timelines_; + } bool IsEmpty() const { - return scroll_timelines_.empty() && view_timelines_.empty(); + return scroll_timelines_.empty() && view_timelines_.empty() && + attaching_timelines_.empty(); } void Clear() { scroll_timelines_.clear(); view_timelines_.clear(); + attaching_timelines_.clear(); } void Trace(Visitor*) const; private: CSSScrollTimelineMap scroll_timelines_; CSSViewTimelineMap view_timelines_; + AttachingTimelineMap attaching_timelines_; }; TimelineData timeline_data_; @@ -300,6 +308,35 @@ const CSSViewTimelineMap* existing_view_timelines, const ComputedStyleBuilder&); + template <typename MapType> + static const MapType* GetExistingTimelines(const TimelineData*); + template <typename MapType> + static const MapType* GetChangedTimelines(const CSSAnimationUpdate*); + + // Invokes `callback` for each timeline, taking both existing timelines + // and pending changes into account. + template <typename TimelineType, typename CallbackFunc> + static void ForEachTimeline(const TimelineData*, + const CSSAnimationUpdate*, + CallbackFunc); + + template <typename TimelineType> + static void CollectTimelinesWithAttachmentInto( + const TimelineData*, + const CSSAnimationUpdate*, + TimelineAttachment, + CSSTimelineMap<TimelineType>& result); + + template <typename TimelineType> + static void CalculateChangedAttachingTimelines( + const CSSTimelineMap<TimelineType>& ancestor_attached_timelines, + const CSSTimelineMap<TimelineType>& deferred_timelines, + const AttachingTimelineMap* existing_attaching_timelines, + AttachingTimelineMap& changed_attaching_timelines); + + static void CalculateAttachingTimelinesUpdate(CSSAnimationUpdate&, + Element& animating_element); + static const TimelineData* GetTimelineData(const Element&); static ScrollTimeline* FindTimelineForNode(const ScopedCSSName& name,
diff --git a/third_party/blink/renderer/core/animation/css/css_timeline_map.h b/third_party/blink/renderer/core/animation/css/css_timeline_map.h index 87771fe..cdfa76a 100644 --- a/third_party/blink/renderer/core/animation/css/css_timeline_map.h +++ b/third_party/blink/renderer/core/animation/css/css_timeline_map.h
@@ -14,6 +14,7 @@ class ScrollTimeline; class ViewTimeline; +class ScrollTimelineAttachment; template <typename TimelineType> using CSSTimelineMap = @@ -22,6 +23,9 @@ using CSSViewTimelineMap = CSSTimelineMap<ViewTimeline>; using CSSScrollTimelineMap = CSSTimelineMap<ScrollTimeline>; +using AttachingTimelineMap = + HeapHashMap<Member<ScrollTimelineAttachment>, Member<ScrollTimeline>>; + } // namespace blink #endif // THIRD_PARTY_BLINK_RENDERER_CORE_ANIMATION_CSS_CSS_TIMELINE_MAP_H_
diff --git a/third_party/blink/renderer/core/animation/scroll_timeline.cc b/third_party/blink/renderer/core/animation/scroll_timeline.cc index 5ab4877..19bd395 100644 --- a/third_party/blink/renderer/core/animation/scroll_timeline.cc +++ b/third_party/blink/renderer/core/animation/scroll_timeline.cc
@@ -107,8 +107,10 @@ ScrollTimelineAttachment* attachment) : AnimationTimeline(document), ScrollSnapshotClient(document->GetFrame()), - attachment_type_(attachment_type), - attachments_(1u, attachment) { + attachment_type_(attachment_type) { + if (attachment) { + attachments_.push_back(attachment); + } UpdateResolvedSource(); } @@ -350,24 +352,26 @@ ScrollSnapshotClient::Trace(visitor); } -bool ScrollTimeline::Matches(ReferenceType reference_type, +bool ScrollTimeline::Matches(TimelineAttachment attachment_type, + ReferenceType reference_type, Element* reference_element, ScrollAxis axis) const { + if (attachment_type_ == TimelineAttachment::kDefer) { + return attachment_type == TimelineAttachment::kDefer; + } const ScrollTimelineAttachment* attachment = CurrentAttachment(); - // TODO(crbug.com/1425939): When attachments other than kLocal - // are supported, attachment may be nullptr. DCHECK(attachment); - return (attachment->GetReferenceType() == reference_type) && + return (attachment_type_ == attachment_type) && + (attachment->GetReferenceType() == reference_type) && (attachment->GetReferenceElement() == reference_element) && (attachment->GetAxis() == axis); } ScrollAxis ScrollTimeline::GetAxis() const { - const ScrollTimelineAttachment* attachment = CurrentAttachment(); - // TODO(crbug.com/1425939): When attachments other than kLocal - // are supported, attachment may be nullptr. - DCHECK(attachment); - return attachment->GetAxis(); + if (const ScrollTimelineAttachment* attachment = CurrentAttachment()) { + return attachment->GetAxis(); + } + return ScrollAxis::kBlock; } void ScrollTimeline::InvalidateEffectTargetStyle() { @@ -403,6 +407,19 @@ CalculateOffsets(scrollable_area, physical_orientation); } +void ScrollTimeline::AddAttachment(ScrollTimelineAttachment* attachment) { + DCHECK_EQ(attachment_type_, TimelineAttachment::kDefer); + attachments_.push_back(attachment); +} + +void ScrollTimeline::RemoveAttachment(ScrollTimelineAttachment* attachment) { + DCHECK_EQ(attachment_type_, TimelineAttachment::kDefer); + wtf_size_t i = attachments_.Find(attachment); + if (i != kNotFound) { + attachments_.EraseAt(i); + } +} + cc::AnimationTimeline* ScrollTimeline::EnsureCompositorTimeline() { if (compositor_timeline_) return compositor_timeline_.get();
diff --git a/third_party/blink/renderer/core/animation/scroll_timeline.h b/third_party/blink/renderer/core/animation/scroll_timeline.h index df8c311..61ba18a8 100644 --- a/third_party/blink/renderer/core/animation/scroll_timeline.h +++ b/third_party/blink/renderer/core/animation/scroll_timeline.h
@@ -102,7 +102,10 @@ // timeline is inactive. absl::optional<ScrollOffsets> GetResolvedScrollOffsets() const; - bool Matches(ReferenceType, Element* reference_element, ScrollAxis) const; + bool Matches(TimelineAttachment, + ReferenceType, + Element* reference_element, + ScrollAxis) const; ScrollAxis GetAxis() const; @@ -137,6 +140,8 @@ // the resolved source so that timeline offsets can be properly computed. virtual void FlushStyleUpdate(); + TimelineAttachment GetTimelineAttachment() const { return attachment_type_; } + ScrollTimelineAttachment* CurrentAttachment() { return (attachments_.size() == 1u) ? attachments_.back().Get() : nullptr; } @@ -145,6 +150,9 @@ return const_cast<ScrollTimeline*>(this)->CurrentAttachment(); } + void AddAttachment(ScrollTimelineAttachment*); + void RemoveAttachment(ScrollTimelineAttachment*); + protected: ScrollTimeline(Document*, TimelineAttachment, ScrollTimelineAttachment*);
diff --git a/third_party/blink/renderer/core/animation/view_timeline.cc b/third_party/blink/renderer/core/animation/view_timeline.cc index 347420dd..34d4415 100644 --- a/third_party/blink/renderer/core/animation/view_timeline.cc +++ b/third_party/blink/renderer/core/animation/view_timeline.cc
@@ -425,26 +425,31 @@ : nullptr; } -bool ViewTimeline::Matches(Element* subject, +bool ViewTimeline::Matches(TimelineAttachment attachment_type, + Element* subject, ScrollAxis axis, const TimelineInset& inset) const { + if (!ScrollTimeline::Matches(attachment_type, ReferenceType::kNearestAncestor, + /* reference_element */ subject, axis)) { + return false; + } + if (GetTimelineAttachment() == TimelineAttachment::kDefer) { + return attachment_type == TimelineAttachment::kDefer; + } const auto* attachment = DynamicTo<ViewTimelineAttachment>(CurrentAttachment()); - // TODO(crbug.com/1425939): When attachments other than kLocal - // are supported, attachment may be nullptr. DCHECK(attachment); - return ScrollTimeline::Matches(ReferenceType::kNearestAncestor, - /* reference_element */ subject, axis) && - (attachment->GetInset() == inset); + return attachment->GetInset() == inset; } const TimelineInset& ViewTimeline::GetInset() const { - const auto* attachment = - DynamicTo<ViewTimelineAttachment>(CurrentAttachment()); - // TODO(crbug.com/1425939): When attachments other than kLocal - // are supported, attachment may be nullptr. - DCHECK(attachment); - return attachment->GetInset(); + if (const auto* attachment = + DynamicTo<ViewTimelineAttachment>(CurrentAttachment())) { + return attachment->GetInset(); + } + + DEFINE_STATIC_LOCAL(TimelineInset, default_inset, ()); + return default_inset; } double ViewTimeline::ToFractionalOffset(
diff --git a/third_party/blink/renderer/core/animation/view_timeline.h b/third_party/blink/renderer/core/animation/view_timeline.h index 0282978..cf6a2c2 100644 --- a/third_party/blink/renderer/core/animation/view_timeline.h +++ b/third_party/blink/renderer/core/animation/view_timeline.h
@@ -47,7 +47,10 @@ // IDL API implementation. Element* subject() const; - bool Matches(Element* subject, ScrollAxis, const TimelineInset&) const; + bool Matches(TimelineAttachment, + Element* subject, + ScrollAxis, + const TimelineInset&) const; const TimelineInset& GetInset() const;
diff --git a/third_party/blink/renderer/core/css/css_property_equality.cc b/third_party/blink/renderer/core/css/css_property_equality.cc index df93b8f7..033c4670 100644 --- a/third_party/blink/renderer/core/css/css_property_equality.cc +++ b/third_party/blink/renderer/core/css/css_property_equality.cc
@@ -31,19 +31,27 @@ return base::ranges::equal(*a_map, *b_map, [](const auto& a, const auto& b) { switch (property) { case CSSPropertyID::kCounterIncrement: - if (a.value.IncrementValue() != b.value.IncrementValue()) { + if (a.value.IsIncrement() != b.value.IsIncrement()) { + return false; + } + if (a.value.IsIncrement() && + a.value.IncrementValue() != b.value.IncrementValue()) { return false; } break; case CSSPropertyID::kCounterReset: - if (a.value.IsReset() != b.value.IsReset() || - a.value.ResetValue() != b.value.ResetValue()) { + if (a.value.IsReset() != b.value.IsReset()) { + return false; + } + if (a.value.IsReset() && a.value.ResetValue() != b.value.ResetValue()) { return false; } break; case CSSPropertyID::kCounterSet: - if (a.value.IsSet() != b.value.IsSet() || - a.value.SetValue() != b.value.SetValue()) { + if (a.value.IsSet() != b.value.IsSet()) { + return false; + } + if (a.value.IsSet() && a.value.SetValue() != b.value.SetValue()) { return false; } break;
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc index 1a445402..bca22ff 100644 --- a/third_party/blink/renderer/core/dom/element.cc +++ b/third_party/blink/renderer/core/dom/element.cc
@@ -4271,11 +4271,6 @@ : nullptr; } -bool Element::IsSupportedByRegionCapture() const { - return base::FeatureList::IsEnabled( - features::kRegionCaptureExperimentalSubtypes); -} - void Element::SetCustomElementDefinition(CustomElementDefinition* definition) { DCHECK(definition); DCHECK(!GetCustomElementDefinition()); @@ -8688,11 +8683,7 @@ GetElementRareData()->DecrementImplicitlyAnchoredElementCount(); } bool Element::HasImplicitlyAnchoredElement() const { - // TODO(xiaochengh): <selectmenu> should also use the implicitly anchored - // element count on element rare data. - return (HasRareData() && - GetElementRareData()->HasImplicitlyAnchoredElement()) || - IsA<HTMLSelectMenuElement>(this); + return HasRareData() && GetElementRareData()->HasImplicitlyAnchoredElement(); } AnchorElementObserver* Element::GetAnchorElementObserver() const {
diff --git a/third_party/blink/renderer/core/dom/element.h b/third_party/blink/renderer/core/dom/element.h index 5042647..209e220 100644 --- a/third_party/blink/renderer/core/dom/element.h +++ b/third_party/blink/renderer/core/dom/element.h
@@ -656,9 +656,6 @@ // Returns a pointer to the crop-ID if one was set; nullptr otherwise. const RegionCaptureCropId* GetRegionCaptureCropId() const; - // Support for all elements with region capture is currently experimental. - virtual bool IsSupportedByRegionCapture() const; - ShadowRoot* attachShadow(const ShadowRootInit*, ExceptionState&); // Returns true if the attachment was successful.
diff --git a/third_party/blink/renderer/core/execution_context/execution_context.cc b/third_party/blink/renderer/core/execution_context/execution_context.cc index e8b1d6e2..1f694184 100644 --- a/third_party/blink/renderer/core/execution_context/execution_context.cc +++ b/third_party/blink/renderer/core/execution_context/execution_context.cc
@@ -68,7 +68,9 @@ namespace blink { -ExecutionContext::ExecutionContext(v8::Isolate* isolate, Agent* agent) +ExecutionContext::ExecutionContext(v8::Isolate* isolate, + Agent* agent, + bool is_window) : isolate_(isolate), security_context_(this), agent_(agent), @@ -78,8 +80,14 @@ csp_delegate_(MakeGarbageCollected<ExecutionContextCSPDelegate>(*this)), window_interaction_tokens_(0), origin_trial_context_(MakeGarbageCollected<OriginTrialContext>(this)), + // RuntimeFeatureStateOverrideContext shouldn't attempt to communcate back + // to browser for ExecutionContexts that aren't windows. + // TODO(https://crbug.com/1410817): Add support for workers/non-frames. runtime_feature_state_override_context_( - MakeGarbageCollected<RuntimeFeatureStateOverrideContext>(this)) { + MakeGarbageCollected<RuntimeFeatureStateOverrideContext>( + this, + this, + /*send_runtime_features_to_browser=*/is_window)) { DCHECK(agent_); }
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 3bf4ea5..1b4ea9d6 100644 --- a/third_party/blink/renderer/core/execution_context/execution_context.h +++ b/third_party/blink/renderer/core/execution_context/execution_context.h
@@ -139,6 +139,9 @@ public UseCounter, public FeatureContext { public: + ExecutionContext(const ExecutionContext&) = delete; + ExecutionContext& operator=(const ExecutionContext&) = delete; + void Trace(Visitor*) const override; static ExecutionContext* From(const ScriptState*); @@ -491,9 +494,7 @@ virtual bool HasStorageAccess() const { return false; } protected: - explicit ExecutionContext(v8::Isolate* isolate, Agent*); - ExecutionContext(const ExecutionContext&) = delete; - ExecutionContext& operator=(const ExecutionContext&) = delete; + ExecutionContext(v8::Isolate* isolate, Agent* agent, bool is_window = false); ~ExecutionContext() override; // Resetting the Agent is only necessary for a special case related to the
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 805528d..1b718368 100644 --- a/third_party/blink/renderer/core/frame/local_dom_window.cc +++ b/third_party/blink/renderer/core/frame/local_dom_window.cc
@@ -221,7 +221,9 @@ LocalDOMWindow::LocalDOMWindow(LocalFrame& frame, WindowAgent* agent) : DOMWindow(frame), - ExecutionContext(V8PerIsolateData::MainThreadIsolate(), agent), + ExecutionContext(V8PerIsolateData::MainThreadIsolate(), + agent, + /*Same value as IsWindow(). is_window=*/true), script_controller_(MakeGarbageCollected<ScriptController>( *this, *static_cast<LocalWindowProxyManager*>(
diff --git a/third_party/blink/renderer/core/html/canvas/canvas_font_cache.cc b/third_party/blink/renderer/core/html/canvas/canvas_font_cache.cc index 4b9c933..b0e9ab5 100644 --- a/third_party/blink/renderer/core/html/canvas/canvas_font_cache.cc +++ b/third_party/blink/renderer/core/html/canvas/canvas_font_cache.cc
@@ -87,6 +87,12 @@ MutableCSSPropertyValueSet* CanvasFontCache::ParseFont( const String& font_string) { + // When the page becomes hidden it should trigger PruneAll(). In case this + // did not happen, prune here. See crbug.com/1421699. + if (fetched_fonts_.size() > HardMaxFonts()) { + PruneAll(); + } + MutableCSSPropertyValueSet* parsed_style; MutableStylePropertyMap::iterator i = fetched_fonts_.find(font_string); if (i != fetched_fonts_.end()) { @@ -118,7 +124,7 @@ void CanvasFontCache::DidProcessTask(const base::PendingTask& pending_task) { DCHECK(pruning_scheduled_); DCHECK(main_cache_purge_preventer_); - while (fetched_fonts_.size() > MaxFonts()) { + while (fetched_fonts_.size() > std::min(MaxFonts(), HardMaxFonts())) { fetched_fonts_.erase(font_lru_list_.back()); fonts_resolved_using_default_style_.erase(font_lru_list_.back()); font_lru_list_.pop_back(); @@ -137,10 +143,14 @@ pruning_scheduled_ = true; } -bool CanvasFontCache::IsInCache(const String& font_string) { +bool CanvasFontCache::IsInCache(const String& font_string) const { return fetched_fonts_.find(font_string) != fetched_fonts_.end(); } +unsigned int CanvasFontCache::GetCacheSize() const { + return fetched_fonts_.size(); +} + void CanvasFontCache::PruneAll() { fetched_fonts_.clear(); font_lru_list_.clear();
diff --git a/third_party/blink/renderer/core/html/canvas/canvas_font_cache.h b/third_party/blink/renderer/core/html/canvas/canvas_font_cache.h index 78817e2..8f32137 100644 --- a/third_party/blink/renderer/core/html/canvas/canvas_font_cache.h +++ b/third_party/blink/renderer/core/html/canvas/canvas_font_cache.h
@@ -52,7 +52,8 @@ void WillProcessTask(const base::PendingTask&, bool) override {} // For testing - bool IsInCache(const String&); + bool IsInCache(const String&) const; + unsigned int GetCacheSize() const; ~CanvasFontCache() override;
diff --git a/third_party/blink/renderer/core/html/canvas/canvas_font_cache_test.cc b/third_party/blink/renderer/core/html/canvas/canvas_font_cache_test.cc index 405fd6e6..2cfc4a3 100644 --- a/third_party/blink/renderer/core/html/canvas/canvas_font_cache_test.cc +++ b/third_party/blink/renderer/core/html/canvas/canvas_font_cache_test.cc
@@ -56,9 +56,8 @@ } TEST_F(CanvasFontCacheTest, CacheHardLimit) { - String font_string; - unsigned i; - for (i = 0; i < Cache()->HardMaxFonts() + 1; i++) { + for (unsigned i = 0; i < Cache()->HardMaxFonts() + 1; ++i) { + String font_string; font_string = String::Number(i + 1) + "px sans-serif"; Context2D()->setFont(font_string); if (i < Cache()->HardMaxFonts()) { @@ -100,4 +99,28 @@ EXPECT_TRUE(document->GetCanvasFontCache()); } +// Regression test for crbug.com/1421699. +// When page becomes hidden the cache should be cleared. If this does not +// happen, setFont() should clear the cache instead. +TEST_F(CanvasFontCacheTest, HardMaxFontsOnPageVisibility) { + GetPage().SetVisibilityState(mojom::blink::PageVisibilityState::kVisible, + /*initial_state=*/false); + // Fill up the font cache. + for (unsigned i = 0; i < Cache()->HardMaxFonts(); ++i) { + String font_string; + font_string = String::Number(i + 1) + "px sans-serif"; + Context2D()->setFont(font_string); + EXPECT_TRUE(Cache()->IsInCache(font_string)); + EXPECT_EQ(Cache()->GetCacheSize(), i + 1); + } + EXPECT_EQ(Cache()->GetCacheSize(), Cache()->HardMaxFonts()); + + // Set initial state to true to not trigger a flush. + GetPage().SetVisibilityState(mojom::blink::PageVisibilityState::kHidden, + /*initial_state=*/true); + // Set font should detect that things are out-of-sync and clear the cache. + Context2D()->setFont("15px serif"); + EXPECT_EQ(Cache()->GetCacheSize(), 1u); +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/html/forms/html_select_menu_element.cc b/third_party/blink/renderer/core/html/forms/html_select_menu_element.cc index 3f951c0..783db0ae 100644 --- a/third_party/blink/renderer/core/html/forms/html_select_menu_element.cc +++ b/third_party/blink/renderer/core/html/forms/html_select_menu_element.cc
@@ -193,6 +193,9 @@ select_mutation_callback_ = MakeGarbageCollected<HTMLSelectMenuElement::SelectMutationCallback>( *this); + + // A selectmenu is the implicit anchor of its listbox. + IncrementImplicitlyAnchoredElementCount(); } // static
diff --git a/third_party/blink/renderer/core/html/html_div_element.h b/third_party/blink/renderer/core/html/html_div_element.h index f175930..e67cf8a 100644 --- a/third_party/blink/renderer/core/html/html_div_element.h +++ b/third_party/blink/renderer/core/html/html_div_element.h
@@ -34,8 +34,6 @@ public: explicit HTMLDivElement(Document&); - bool IsSupportedByRegionCapture() const override { return true; } - private: void CollectStyleForPresentationAttribute( const QualifiedName&,
diff --git a/third_party/blink/renderer/core/html/html_iframe_element.h b/third_party/blink/renderer/core/html/html_iframe_element.h index d2f89f5..1a77ca0 100644 --- a/third_party/blink/renderer/core/html/html_iframe_element.h +++ b/third_party/blink/renderer/core/html/html_iframe_element.h
@@ -61,8 +61,6 @@ bool Credentialless() const override { return credentialless_; } - bool IsSupportedByRegionCapture() const override { return true; } - private: void SetCollapsed(bool) override;
diff --git a/third_party/blink/renderer/core/html/parser/html_document_parser_fastpath.cc b/third_party/blink/renderer/core/html/parser/html_document_parser_fastpath.cc index 3b43535..e2e1d09 100644 --- a/third_party/blink/renderer/core/html/parser/html_document_parser_fastpath.cc +++ b/third_party/blink/renderer/core/html/parser/html_document_parser_fastpath.cc
@@ -777,8 +777,9 @@ out->push_back(0xa0); } else { // This handles uncommon named references. - String input_string{reference.data(), - static_cast<unsigned>(reference.size())}; + // This does not use `reference` as `reference` does not contain the `;`, + // which impacts behavior of ConsumeHTMLEntity(). + String input_string{start, static_cast<unsigned>(pos_ - start)}; SegmentedString input_segmented{input_string}; DecodedHTMLEntity entity; bool not_enough_characters = false; @@ -792,9 +793,6 @@ // ConsumeHTMLEntity() may not have consumed all the input. const unsigned remaining_length = input_segmented.length(); if (remaining_length) { - if (*(pos_ - 1) == ';') { - --pos_; - } pos_ -= remaining_length; } }
diff --git a/third_party/blink/renderer/core/html/parser/html_document_parser_fastpath_test.cc b/third_party/blink/renderer/core/html/parser/html_document_parser_fastpath_test.cc index 6e9cc45c..1a0a3ae 100644 --- a/third_party/blink/renderer/core/html/parser/html_document_parser_fastpath_test.cc +++ b/third_party/blink/renderer/core/html/parser/html_document_parser_fastpath_test.cc
@@ -256,5 +256,22 @@ div->setInnerHTML(" -"); } +TEST(HTMLDocumentParserFastpathTest, HandlesCompleteCharacterReference) { + ScopedNullExecutionContext execution_context; + auto* document = + HTMLDocument::CreateForTest(execution_context.GetExecutionContext()); + document->write("<body></body>"); + auto* div = MakeGarbageCollected<HTMLDivElement>(*document); + + base::HistogramTester histogram_tester; + div->setInnerHTML("¢"); + Text* text_node = To<Text>(div->firstChild()); + ASSERT_TRUE(text_node); + EXPECT_EQ(text_node->data(), String(u"\u00A2")); + histogram_tester.ExpectTotalCount("Blink.HTMLFastPathParser.ParseResult", 1); + histogram_tester.ExpectUniqueSample("Blink.HTMLFastPathParser.ParseResult", + HtmlFastPathResult::kSucceeded, 1); +} + } // namespace } // namespace blink
diff --git a/third_party/blink/renderer/core/html/parser/html_entity_parser.cc b/third_party/blink/renderer/core/html/parser/html_entity_parser.cc index 6d3a77a..d9e0a49 100644 --- a/third_party/blink/renderer/core/html/parser/html_entity_parser.cc +++ b/third_party/blink/renderer/core/html/parser/html_entity_parser.cc
@@ -112,7 +112,10 @@ consumed_characters.push_back(cc); source.AdvanceAndASSERT(cc); } - not_enough_characters = source.IsEmpty(); + // Character reference ends in ';', so if the last character is ';' then + // don't treat it as not enough characters (because no additional characters + // will change the result). + not_enough_characters = source.IsEmpty() && cc != u';'; if (not_enough_characters) { // We can't decide on an entity because there might be a longer entity // that we could match if we had more data.
diff --git a/third_party/blink/renderer/core/style/shadow_data.h b/third_party/blink/renderer/core/style/shadow_data.h index 9cc53e2..3bafb27a0 100644 --- a/third_party/blink/renderer/core/style/shadow_data.h +++ b/third_party/blink/renderer/core/style/shadow_data.h
@@ -41,7 +41,7 @@ USING_FAST_MALLOC(ShadowData); public: - ShadowData(const gfx::PointF& location, + ShadowData(gfx::PointF location, float blur, float spread, ShadowStyle style,
diff --git a/third_party/blink/renderer/modules/mediastream/crop_target.cc b/third_party/blink/renderer/modules/mediastream/crop_target.cc index aed35c4..95d3b8b 100644 --- a/third_party/blink/renderer/modules/mediastream/crop_target.cc +++ b/third_party/blink/renderer/modules/mediastream/crop_target.cc
@@ -28,7 +28,7 @@ return ScriptPromise(); } - if (!element || !element->IsSupportedByRegionCapture()) { + if (!element) { exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError, "Invalid state."); return ScriptPromise();
diff --git a/third_party/blink/renderer/modules/mediastream/media_devices.cc b/third_party/blink/renderer/modules/mediastream/media_devices.cc index d9760c6..36b6d6be 100644 --- a/third_party/blink/renderer/modules/mediastream/media_devices.cc +++ b/third_party/blink/renderer/modules/mediastream/media_devices.cc
@@ -735,10 +735,9 @@ return ScriptPromise(); } - if (!element || !element->IsSupportedByRegionCapture()) { - exception_state.ThrowDOMException( - DOMExceptionCode::kNotSupportedError, - "Support for this subtype is not yet implemented."); + if (!element) { + exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError, + "Invalid element."); return ScriptPromise(); }
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 7390ec0c..380865e3 100644 --- a/third_party/blink/renderer/modules/mediastream/media_devices_test.cc +++ b/third_party/blink/renderer/modules/mediastream/media_devices_test.cc
@@ -265,10 +265,7 @@ MediaDevicesTest() : dispatcher_host_(std::make_unique<MockMediaDevicesDispatcherHost>()), - device_infos_(MakeGarbageCollected<MediaDeviceInfos>()) { - scoped_feature_list_.InitAndEnableFeature( - blink::features::kRegionCaptureExperimentalSubtypes); - } + device_infos_(MakeGarbageCollected<MediaDeviceInfos>()) {} MediaDevices* GetMediaDevices(LocalDOMWindow& window) { if (!media_devices_) { @@ -819,36 +816,6 @@ } } -// kRegionCaptureExperimentalSubtypes is default-enabled, -// functioning as a killswitch in case a regression is discovered -// when cropping to an element other than a <div> or <iframe>, -// in which case we can *partially* disable Region Capture. -// This test ensures the continued viability of this killswitch. -TEST_F(MediaDevicesTest, ProduceCropIdRejectedIfUnsupportedElementType) { - V8TestingScope scope; - auto* media_devices = GetMediaDevices(*GetDocument().domWindow()); - ASSERT_TRUE(media_devices); - - scoped_feature_list().Reset(); - scoped_feature_list().InitAndDisableFeature( - blink::features::kRegionCaptureExperimentalSubtypes); - SetBodyContent(R"HTML( - <button id='test-button'>Click!</button> - )HTML"); - - Document& document = GetDocument(); - Element* const button = document.getElementById("test-button"); - const ScriptPromise button_promise = media_devices->ProduceCropTarget( - scope.GetScriptState(), button, scope.GetExceptionState()); - platform()->RunUntilIdle(); - EXPECT_TRUE(button_promise.IsEmpty()); - EXPECT_TRUE(scope.GetExceptionState().HadException()); - EXPECT_EQ(scope.GetExceptionState().CodeAs<DOMExceptionCode>(), - DOMExceptionCode::kNotSupportedError); - EXPECT_EQ(scope.GetExceptionState().Message(), - String("Support for this subtype is not yet implemented.")); -} - TEST_F(MediaDevicesTest, ProduceCropIdRejectedIfDifferentWindow) { V8TestingScope scope; // Intentionally sets up a MediaDevices object in a different window.
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_track.cc b/third_party/blink/renderer/modules/mediastream/media_stream_track.cc index f961aea5..5dfc42a 100644 --- a/third_party/blink/renderer/modules/mediastream/media_stream_track.cc +++ b/third_party/blink/renderer/modules/mediastream/media_stream_track.cc
@@ -79,8 +79,9 @@ auto* window = DynamicTo<LocalDOMWindow>(ExecutionContext::From(script_state)); - if (!window) + if (!window) { return nullptr; + } UserMediaClient* user_media_client = UserMediaClient::From(window); if (!user_media_client) { @@ -102,7 +103,7 @@ MakeGarbageCollected<GetOpenDeviceRequestCallbacks>(), IdentifiableSurface()); if (!request) { - return nullptr; + return nullptr; } // TODO(1288839): Create a TransferredMediaStreamTrack implementing interfaces
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_track_impl.cc b/third_party/blink/renderer/modules/mediastream/media_stream_track_impl.cc index 4792226..9c68a7ec 100644 --- a/third_party/blink/renderer/modules/mediastream/media_stream_track_impl.cc +++ b/third_party/blink/renderer/modules/mediastream/media_stream_track_impl.cc
@@ -120,15 +120,18 @@ template <typename ConstraintSetCondition> bool ConstraintsSatisfyCondition(ConstraintSetCondition condition, const MediaTrackConstraints* constraints) { - if (condition(constraints)) + if (condition(constraints)) { return true; + } - if (!constraints->hasAdvanced()) + if (!constraints->hasAdvanced()) { return false; + } for (const auto& advanced_set : constraints->advanced()) { - if (condition(advanced_set)) + if (condition(advanced_set)) { return true; + } } return false; @@ -290,8 +293,9 @@ // Note that both 'live' and 'muted' correspond to a 'live' ready state in the // web API. - if (ready_state_ != MediaStreamSource::kReadyStateEnded) + if (ready_state_ != MediaStreamSource::kReadyStateEnded) { EnsureFeatureHandleForScheduler(); + } } MediaStreamTrackImpl::~MediaStreamTrackImpl() = default; @@ -324,8 +328,9 @@ } void MediaStreamTrackImpl::setEnabled(bool enabled) { - if (enabled == component_->Enabled()) + if (enabled == component_->Enabled()) { return; + } component_->SetEnabled(enabled); @@ -382,8 +387,9 @@ } String MediaStreamTrackImpl::readyState() const { - if (Ended()) + if (Ended()) { return "ended"; + } return ReadyStateToString(ready_state_); } @@ -398,15 +404,17 @@ // Observers may dispatch events which create and add new Observers; // take a snapshot so as to safely iterate. HeapVector<Member<MediaStreamTrack::Observer>> observers(observers_); - for (auto observer : observers) + for (auto observer : observers) { observer->TrackChangedState(); + } } } void MediaStreamTrackImpl::stopTrack(ExecutionContext* execution_context) { SendLogMessage(String::Format("%s()", __func__)); - if (Ended()) + if (Ended()) { return; + } if (auto* track = Component()->GetPlatformTrack()) { // Synchronously disable the platform track to prevent media from flowing, @@ -419,8 +427,9 @@ feature_handle_for_scheduler_.reset(); UserMediaClient* user_media_client = UserMediaClient::From(To<LocalDOMWindow>(execution_context)); - if (user_media_client) + if (user_media_client) { user_media_client->StopTrack(Component()); + } PropagateTrackEnded(); } @@ -443,28 +452,34 @@ MediaTrackCapabilities* MediaStreamTrackImpl::getCapabilities() const { MediaTrackCapabilities* capabilities = MediaTrackCapabilities::Create(); - if (image_capture_) + if (image_capture_) { image_capture_->GetMediaTrackCapabilities(capabilities); + } auto platform_capabilities = component_->Source()->GetCapabilities(); capabilities->setDeviceId(platform_capabilities.device_id); - if (!platform_capabilities.group_id.IsNull()) + if (!platform_capabilities.group_id.IsNull()) { capabilities->setGroupId(platform_capabilities.group_id); + } if (component_->GetSourceType() == MediaStreamSource::kTypeAudio) { Vector<bool> echo_cancellation, auto_gain_control, noise_suppression; - for (bool value : platform_capabilities.echo_cancellation) + for (bool value : platform_capabilities.echo_cancellation) { echo_cancellation.push_back(value); + } capabilities->setEchoCancellation(echo_cancellation); - for (bool value : platform_capabilities.auto_gain_control) + for (bool value : platform_capabilities.auto_gain_control) { auto_gain_control.push_back(value); + } capabilities->setAutoGainControl(auto_gain_control); - for (bool value : platform_capabilities.noise_suppression) + for (bool value : platform_capabilities.noise_suppression) { noise_suppression.push_back(value); + } capabilities->setNoiseSuppression(noise_suppression); Vector<String> echo_cancellation_type; - for (String value : platform_capabilities.echo_cancellation_type) + for (String value : platform_capabilities.echo_cancellation_type) { echo_cancellation_type.push_back(value); + } // Sample size. if (platform_capabilities.sample_size.size() == 2) { LongRange* sample_size = LongRange::Create(); @@ -564,17 +579,22 @@ MediaTrackSettings* settings = MediaTrackSettings::Create(); MediaStreamTrackPlatform::Settings platform_settings; component_->GetSettings(platform_settings); - if (platform_settings.HasFrameRate()) + if (platform_settings.HasFrameRate()) { settings->setFrameRate(platform_settings.frame_rate); - if (platform_settings.HasWidth()) + } + if (platform_settings.HasWidth()) { settings->setWidth(platform_settings.width); - if (platform_settings.HasHeight()) + } + if (platform_settings.HasHeight()) { settings->setHeight(platform_settings.height); - if (platform_settings.HasAspectRatio()) + } + if (platform_settings.HasAspectRatio()) { settings->setAspectRatio(platform_settings.aspect_ratio); + } settings->setDeviceId(platform_settings.device_id); - if (!platform_settings.group_id.IsNull()) + if (!platform_settings.group_id.IsNull()) { settings->setGroupId(platform_settings.group_id); + } if (platform_settings.HasFacingMode()) { switch (platform_settings.facing_mode) { case MediaStreamTrackPlatform::FacingMode::kUser: @@ -594,34 +614,44 @@ break; } } - if (!platform_settings.resize_mode.IsNull()) + if (!platform_settings.resize_mode.IsNull()) { settings->setResizeMode(platform_settings.resize_mode); + } - if (platform_settings.echo_cancellation) + if (platform_settings.echo_cancellation) { settings->setEchoCancellation(*platform_settings.echo_cancellation); - if (platform_settings.auto_gain_control) + } + if (platform_settings.auto_gain_control) { settings->setAutoGainControl(*platform_settings.auto_gain_control); - if (platform_settings.noise_supression) + } + if (platform_settings.noise_supression) { settings->setNoiseSuppression(*platform_settings.noise_supression); + } - if (platform_settings.HasSampleRate()) + if (platform_settings.HasSampleRate()) { settings->setSampleRate(platform_settings.sample_rate); - if (platform_settings.HasSampleSize()) + } + if (platform_settings.HasSampleSize()) { settings->setSampleSize(platform_settings.sample_size); - if (platform_settings.HasChannelCount()) + } + if (platform_settings.HasChannelCount()) { settings->setChannelCount(platform_settings.channel_count); - if (platform_settings.HasLatency()) + } + if (platform_settings.HasLatency()) { settings->setLatency(platform_settings.latency); + } - if (image_capture_) + if (image_capture_) { image_capture_->GetMediaTrackSettings(settings); + } if (platform_settings.display_surface) { settings->setDisplaySurface( GetDisplaySurfaceString(platform_settings.display_surface.value())); } - if (platform_settings.logical_surface) + if (platform_settings.logical_surface) { settings->setLogicalSurface(platform_settings.logical_surface.value()); + } if (platform_settings.cursor) { WTF::String value; switch (platform_settings.cursor.value()) { @@ -666,8 +696,9 @@ ScriptPromise MediaStreamTrackImpl::applyConstraints( ScriptState* script_state, const MediaTrackConstraints* constraints) { - if (!script_state->ContextIsValid()) + if (!script_state->ContextIsValid()) { return ScriptPromise(); + } auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state); ScriptPromise promise = resolver->Promise(); @@ -690,8 +721,9 @@ bool initial_values) { constraints_ = constraints; - if (!initial_values) + if (!initial_values) { return; + } DCHECK(!suppress_local_audio_playback_setting_.has_value()); if (!constraints_.IsNull() && @@ -767,8 +799,9 @@ } void MediaStreamTrackImpl::SourceChangedState() { - if (Ended()) + if (Ended()) { return; + } // Note that both 'live' and 'muted' correspond to a 'live' ready state in the // web API, hence the following logic around |feature_handle_for_scheduler_|. @@ -840,8 +873,9 @@ is_iterating_registered_media_streams_ = true; for (HeapHashSet<Member<MediaStream>>::iterator iter = registered_media_streams_.begin(); - iter != registered_media_streams_.end(); ++iter) + iter != registered_media_streams_.end(); ++iter) { (*iter)->TrackEnded(); + } is_iterating_registered_media_streams_ = false; } @@ -869,8 +903,9 @@ } absl::optional<const MediaStreamDevice> MediaStreamTrackImpl::device() const { - if (!component_->Source()->GetPlatformSource()) + if (!component_->Source()->GetPlatformSource()) { return absl::nullopt; + } return component_->Source()->GetPlatformSource()->device(); } @@ -979,16 +1014,19 @@ } void MediaStreamTrackImpl::EnsureFeatureHandleForScheduler() { - if (feature_handle_for_scheduler_) + if (feature_handle_for_scheduler_) { return; + } LocalDOMWindow* window = DynamicTo<LocalDOMWindow>(GetExecutionContext()); // Ideally we'd use To<LocalDOMWindow>, but in unittests the ExecutionContext // may not be a LocalDOMWindow. - if (!window) + if (!window) { return; + } // This can happen for detached frames. - if (!window->GetFrame()) + if (!window->GetFrame()) { return; + } feature_handle_for_scheduler_ = window->GetFrame()->GetFrameScheduler()->RegisterFeature( SchedulingPolicy::Feature::kWebRTC,
diff --git a/third_party/blink/renderer/modules/shared_storage/shared_storage_worklet_global_scope.cc b/third_party/blink/renderer/modules/shared_storage/shared_storage_worklet_global_scope.cc index 884115d..6159ac2 100644 --- a/third_party/blink/renderer/modules/shared_storage/shared_storage_worklet_global_scope.cc +++ b/third_party/blink/renderer/modules/shared_storage/shared_storage_worklet_global_scope.cc
@@ -17,6 +17,7 @@ #include "mojo/public/cpp/bindings/remote.h" #include "third_party/blink/public/common/features.h" #include "third_party/blink/public/common/shared_storage/module_script_downloader.h" +#include "third_party/blink/public/common/shared_storage/shared_storage_utils.h" #include "third_party/blink/public/platform/cross_variant_mojo_util.h" #include "third_party/blink/renderer/bindings/core/v8/idl_types.h" #include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h" @@ -242,8 +243,7 @@ ContextFeatureSettings::From( this, ContextFeatureSettings::CreationMode::kCreateIfNotExists) ->EnablePrivateAggregationInSharedStorage( - base::FeatureList::IsEnabled(features::kPrivateAggregationApi) && - features::kPrivateAggregationApiEnabledInSharedStorage.Get()); + ShouldDefinePrivateAggregationInSharedStorage()); } SharedStorageWorkletGlobalScope::~SharedStorageWorkletGlobalScope() = default; @@ -307,7 +307,7 @@ void SharedStorageWorkletGlobalScope::NotifyContextDestroyed() { if (private_aggregation_) { - CHECK(should_define_private_aggregation_object_); + CHECK(ShouldDefinePrivateAggregationInSharedStorage()); private_aggregation_->OnWorkletDestroyed(); } @@ -359,26 +359,11 @@ } } -bool SharedStorageWorkletGlobalScope::IsPrivateAggregationEnabled() { - return ContextFeatureSettings::From( - this, ContextFeatureSettings::CreationMode::kCreateIfNotExists) - ->isPrivateAggregationInSharedStorageEnabled(); -} - void SharedStorageWorkletGlobalScope::AddModule( mojo::PendingRemote<network::mojom::URLLoaderFactory> pending_url_loader_factory, const GURL& script_source_url, - bool should_define_private_aggregation_object, AddModuleCallback callback) { - // TODO(crbug.com/1432378): Remove this boolean if/when shared storage origins - // are only allowed to be potentially trustworthy. - if (should_define_private_aggregation_object_) { - CHECK(IsPrivateAggregationEnabled()); - } - should_define_private_aggregation_object_ = - should_define_private_aggregation_object; - mojo::Remote<network::mojom::URLLoaderFactory> url_loader_factory( std::move(pending_url_loader_factory)); @@ -561,7 +546,7 @@ PrivateAggregation* SharedStorageWorkletGlobalScope::privateAggregation( ScriptState* script_state, ExceptionState& exception_state) { - CHECK(IsPrivateAggregationEnabled()); + CHECK(ShouldDefinePrivateAggregationInSharedStorage()); if (!add_module_finished_) { CHECK(!private_aggregation_); @@ -573,16 +558,6 @@ return nullptr; } - if (!should_define_private_aggregation_object_) { - CHECK(!private_aggregation_); - - exception_state.ThrowDOMException( - DOMExceptionCode::kNotAllowedError, - "privateAggregation cannot be accessed in an insecure context."); - - return nullptr; - } - return GetOrCreatePrivateAggregation(); } @@ -696,7 +671,7 @@ private_aggregation_host) { CHECK(add_module_finished_); CHECK_EQ(!!private_aggregation_host, - should_define_private_aggregation_object_); + ShouldDefinePrivateAggregationInSharedStorage()); int64_t operation_id = operation_counter_++; @@ -709,7 +684,7 @@ context->SetContinuationPreservedEmbedderData( v8::BigInt::New(context->GetIsolate(), operation_id)); - if (should_define_private_aggregation_object_) { + if (ShouldDefinePrivateAggregationInSharedStorage()) { GetOrCreatePrivateAggregation()->OnOperationStarted( operation_id, std::move(private_aggregation_host)); } @@ -719,7 +694,7 @@ } void SharedStorageWorkletGlobalScope::FinishOperation(int64_t operation_id) { - if (should_define_private_aggregation_object_) { + if (ShouldDefinePrivateAggregationInSharedStorage()) { CHECK(private_aggregation_); private_aggregation_->OnOperationFinished(operation_id); } @@ -727,7 +702,7 @@ PrivateAggregation* SharedStorageWorkletGlobalScope::GetOrCreatePrivateAggregation() { - CHECK(should_define_private_aggregation_object_); + CHECK(ShouldDefinePrivateAggregationInSharedStorage()); CHECK(add_module_finished_); if (!private_aggregation_) {
diff --git a/third_party/blink/renderer/modules/shared_storage/shared_storage_worklet_global_scope.h b/third_party/blink/renderer/modules/shared_storage/shared_storage_worklet_global_scope.h index d000727..0c8b87f 100644 --- a/third_party/blink/renderer/modules/shared_storage/shared_storage_worklet_global_scope.h +++ b/third_party/blink/renderer/modules/shared_storage/shared_storage_worklet_global_scope.h
@@ -96,7 +96,6 @@ void AddModule(mojo::PendingRemote<network::mojom::URLLoaderFactory> pending_url_loader_factory, const GURL& script_source_url, - bool should_define_private_aggregation_object, AddModuleCallback callback) override; void RunURLSelectionOperation( const std::string& name, @@ -224,12 +223,6 @@ // worklet. bool private_aggregation_permissions_policy_allowed_ = false; - // Whether the privateAggregation object should be defined. Set in - // `AddModule()` and can be false afterwards even if - // `IsPrivateAggregationEnabled()` if the worklet origin is not potentially - // trustworthy. - bool should_define_private_aggregation_object_ = false; - const SharedStorageWorkletToken token_; };
diff --git a/third_party/blink/renderer/modules/shared_storage/shared_storage_worklet_unittest.cc b/third_party/blink/renderer/modules/shared_storage/shared_storage_worklet_unittest.cc index e0191c3..d7317d36 100644 --- a/third_party/blink/renderer/modules/shared_storage/shared_storage_worklet_unittest.cc +++ b/third_party/blink/renderer/modules/shared_storage/shared_storage_worklet_unittest.cc
@@ -27,6 +27,7 @@ #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/abseil-cpp/absl/numeric/int128.h" +#include "third_party/blink/public/common/shared_storage/shared_storage_utils.h" #include "third_party/blink/public/mojom/private_aggregation/aggregatable_report.mojom-blink.h" #include "third_party/blink/public/mojom/private_aggregation/private_aggregation_host.mojom-blink.h" #include "third_party/blink/public/mojom/shared_storage/shared_storage_worklet_service.mojom.h" @@ -293,9 +294,7 @@ base::test::TestFuture<bool, const std::string&> future; shared_storage_worklet_service_->AddModule( - factory.Unbind(), GURL(kModuleScriptSource), - /*should_define_private_aggregation_object=*/ - create_private_aggregation_host_, future.GetCallback()); + factory.Unbind(), GURL(kModuleScriptSource), future.GetCallback()); return {future.Get<0>(), future.Get<1>()}; } @@ -327,10 +326,13 @@ CrossVariantMojoRemote<mojom::blink::PrivateAggregationHostInterfaceBase> MaybeInitNewRemotePAHost() { + CHECK_EQ(ShouldDefinePrivateAggregationInSharedStorage(), + !!mock_private_aggregation_host_); + mojo::PendingRemote<mojom::blink::PrivateAggregationHost> pending_pa_host_remote; - if (mock_private_aggregation_host_) { + if (ShouldDefinePrivateAggregationInSharedStorage()) { mojo::PendingReceiver<mojom::blink::PrivateAggregationHost> pending_pa_host_receiver = pending_pa_host_remote.InitWithNewPipeAndPassReceiver(); @@ -352,7 +354,6 @@ Persistent<SharedStorageWorkletMessagingProxy> messaging_proxy_; absl::optional<std::u16string> embedder_context_; - bool create_private_aggregation_host_ = false; bool private_aggregation_permissions_policy_allowed_ = true; base::test::TestFuture<void> worklet_terminated_future_; @@ -388,7 +389,7 @@ test_client_ = std::make_unique<TestClient>( std::move(pending_shared_storage_service_client_receiver)); - if (create_private_aggregation_host_) { + if (ShouldDefinePrivateAggregationInSharedStorage()) { mock_private_aggregation_host_ = std::make_unique<MockMojomPrivateAggregationHost>(); } @@ -2243,7 +2244,6 @@ class SharedStoragePrivateAggregationTest : public SharedStorageWorkletTest { public: SharedStoragePrivateAggregationTest() { - create_private_aggregation_host_ = true; private_aggregation_feature_.InitWithFeaturesAndParameters( /*enabled_features=*/ {{blink::features::kPrivateAggregationApi, @@ -2251,6 +2251,15 @@ /*disabled_features=*/{}); } + void TearDown() override { + // Shut down the worklet gracefully. Otherwise, the + // `private_aggregation_feature_` may be destroyed before the worklet thread + // (e.g. SharedStorageWorkletGlobalScope::NotifyContextDestroyed()) and some + // feature state assertions could fail. + shared_storage_worklet_service_.reset(); + EXPECT_TRUE(worklet_terminated_future_.Wait()); + } + // `error_message` being `nullptr` indicates no error is expected. void ExecuteScriptAndValidateContribution( const std::string& script_body, @@ -2305,7 +2314,7 @@ {"class TestClass { async run() {", script_body, "}}; register(\"test-operation\", TestClass);"})); - CHECK_EQ(create_private_aggregation_host_, + CHECK_EQ(ShouldDefinePrivateAggregationInSharedStorage(), !!mock_private_aggregation_host_); if (mock_private_aggregation_host_) { @@ -2665,25 +2674,4 @@ run_loop.Run(); } -TEST_F(SharedStoragePrivateAggregationTest, - ShouldNotDefinePrivateAggregationObject_FailureIfAccessed) { - create_private_aggregation_host_ = false; - - AddModuleResult add_module_result = AddModule(/*script_content=*/R"( - class TestClass { - async run() { - privateAggregation.sendHistogramReport({bucket: 1n, value: 2}); - } - } - - register("test-operation", TestClass); - )"); - - RunResult run_result = Run("test-operation", /*serialized_data=*/{}); - EXPECT_FALSE(run_result.success); - EXPECT_THAT(run_result.error_message, - testing::HasSubstr("privateAggregation cannot be " - "accessed in an insecure context.")); -} - } // namespace blink
diff --git a/third_party/blink/renderer/modules/webcodecs/audio_encoder.cc b/third_party/blink/renderer/modules/webcodecs/audio_encoder.cc index 2038470..4ea3c4f 100644 --- a/third_party/blink/renderer/modules/webcodecs/audio_encoder.cc +++ b/third_party/blink/renderer/modules/webcodecs/audio_encoder.cc
@@ -396,7 +396,7 @@ media_encoder_ = CreateMediaAudioEncoder(*active_config_); if (!media_encoder_) { - HandleError(logger_->MakeException( + HandleError(logger_->MakeOperationError( "Encoder creation error.", media::EncoderStatus( media::EncoderStatus::Codes::kEncoderInitializationError, @@ -421,8 +421,8 @@ } DCHECK_CALLED_ON_VALID_SEQUENCE(self->sequence_checker_); if (!status.is_ok()) { - self->HandleError( - self->logger_->MakeException("Encoding error.", std::move(status))); + self->HandleError(self->logger_->MakeOperationError("Encoding error.", + std::move(status))); } else { base::UmaHistogramEnumeration("Blink.WebCodecs.AudioEncoder.Codec", codec); @@ -467,8 +467,8 @@ } DCHECK_CALLED_ON_VALID_SEQUENCE(self->sequence_checker_); if (!status.is_ok()) { - self->HandleError( - self->logger_->MakeException("Encoding error.", std::move(status))); + self->HandleError(self->logger_->MakeEncodingError("Encoding error.", + std::move(status))); } req->EndTracing(); @@ -477,7 +477,7 @@ if (data->channel_count() != active_config_->options.channels || data->sample_rate() != active_config_->options.sample_rate) { - HandleError(logger_->MakeException( + HandleError(logger_->MakeEncodingError( "Input audio buffer is incompatible with codec parameters", media::EncoderStatus(media::EncoderStatus::Codes::kEncoderFailedEncode) .WithData("channels", data->channel_count())
diff --git a/third_party/blink/renderer/modules/webcodecs/codec_logger.h b/third_party/blink/renderer/modules/webcodecs/codec_logger.h index dfc901f..2afb12d003 100644 --- a/third_party/blink/renderer/modules/webcodecs/codec_logger.h +++ b/third_party/blink/renderer/modules/webcodecs/codec_logger.h
@@ -106,7 +106,7 @@ // the given |status| in |media_log_|. // Since |status| can come from platform codecs, its contents won't be // surfaced to JS, since we could leak important information. - DOMException* MakeException(std::string error_msg, StatusImpl status) { + DOMException* MakeOperationError(std::string error_msg, StatusImpl status) { media_log_->NotifyError(status); if (!status_code_) @@ -116,13 +116,37 @@ error_msg.c_str()); } - // Convenience wrapper for MakeException(), where |error_msg| is shared for - // both the exception message and the status message. - DOMException* MakeException( + // Convenience wrapper for MakeOperationError(), where |error_msg| is shared + // for both the exception message and the status message. + DOMException* MakeOperationError( std::string error_msg, typename StatusImpl::Codes code, const base::Location& location = base::Location::Current()) { - return MakeException(error_msg, StatusImpl(code, error_msg, location)); + return MakeOperationError(error_msg, StatusImpl(code, error_msg, location)); + } + + // Creates an EncodingError DOMException with the given |error_msg|, and logs + // the given |status| in |media_log_|. + // Since |status| can come from platform codecs, its contents won't be + // surfaced to JS, since we could leak important information. + DOMException* MakeEncodingError(std::string error_msg, StatusImpl status) { + media_log_->NotifyError(status); + + if (!status_code_) { + status_code_ = status.code(); + } + + return MakeGarbageCollected<DOMException>(DOMExceptionCode::kEncodingError, + error_msg.c_str()); + } + + // Convenience wrapper for MakeEncodingError(), where |error_msg| is shared + // for both the exception message and the status message. + DOMException* MakeEncodingError( + std::string error_msg, + typename StatusImpl::Codes code, + const base::Location& location = base::Location::Current()) { + return MakeEncodingError(error_msg, StatusImpl(code, error_msg, location)); } // Safe to use on any thread. |this| should still outlive users of log().
diff --git a/third_party/blink/renderer/modules/webcodecs/decoder_template.cc b/third_party/blink/renderer/modules/webcodecs/decoder_template.cc index 6d047fc..e75d98f 100644 --- a/third_party/blink/renderer/modules/webcodecs/decoder_template.cc +++ b/third_party/blink/renderer/modules/webcodecs/decoder_template.cc
@@ -350,7 +350,7 @@ decoder_ = Traits::CreateDecoder(*ExecutionContext::From(script_state_), gpu_factories_.value(), logger_->log()); if (!decoder()) { - Shutdown(logger_->MakeException( + Shutdown(logger_->MakeOperationError( "Internal error: Could not create decoder.", media::DecoderStatus::Codes::kFailedToCreateDecoder)); return; @@ -387,9 +387,9 @@ DCHECK_GT(num_pending_decodes_, 0u); if (!decoder()) { - Shutdown( - logger_->MakeException("Decoding error: no decoder found.", - media::DecoderStatus::Codes::kNotInitialized)); + Shutdown(logger_->MakeEncodingError( + "Decoding error: no decoder found.", + media::DecoderStatus::Codes::kNotInitialized)); return false; } @@ -402,10 +402,11 @@ // The request may be invalid, if so report that now. if (!request->decoder_buffer || request->decoder_buffer->data_size() == 0) { if (request->status.is_ok()) { - Shutdown(logger_->MakeException("Null or empty decoder buffer.", - media::DecoderStatus::Codes::kFailed)); + Shutdown( + logger_->MakeEncodingError("Null or empty decoder buffer.", + media::DecoderStatus::Codes::kFailed)); } else { - Shutdown(logger_->MakeException("Decoder error.", request->status)); + Shutdown(logger_->MakeEncodingError("Decoder error.", request->status)); } return false; @@ -607,7 +608,7 @@ pending_request_->type == Request::Type::kFlush); if (!status.is_ok()) { - Shutdown(logger_->MakeException("Error during flush.", status)); + Shutdown(logger_->MakeEncodingError("Error during flush.", status)); return; } @@ -664,7 +665,7 @@ } else { error_message = "Decoder initialization error."; } - Shutdown(logger_->MakeException(error_message, status)); + Shutdown(logger_->MakeOperationError(error_message, status)); return; } @@ -708,7 +709,7 @@ if (!status.is_ok() && status.code() != media::DecoderStatus::Codes::kAborted) { - Shutdown(logger_->MakeException("Decoding error.", std::move(status))); + Shutdown(logger_->MakeEncodingError("Decoding error.", std::move(status))); return; } @@ -749,8 +750,9 @@ auto output_or_error = MakeOutput(std::move(output), context); if (!output_or_error.has_value()) { - Shutdown(logger_->MakeException("Error creating output from decoded data", - std::move(output_or_error).error())); + Shutdown( + logger_->MakeEncodingError("Error creating output from decoded data", + std::move(output_or_error).error())); return; }
diff --git a/third_party/blink/renderer/modules/webcodecs/encoder_base.cc b/third_party/blink/renderer/modules/webcodecs/encoder_base.cc index 3c325cd..925f9f86 100644 --- a/third_party/blink/renderer/modules/webcodecs/encoder_base.cc +++ b/third_party/blink/renderer/modules/webcodecs/encoder_base.cc
@@ -149,8 +149,7 @@ // Remove exceptions relating to cloning closed input. exception_state.ClearException(); - exception_state.ThrowDOMException(DOMExceptionCode::kOperationError, - "Cannot encode closed input."); + exception_state.ThrowTypeError("Cannot encode closed input."); return; } @@ -343,8 +342,8 @@ if (status.is_ok()) { req->resolver.Release()->Resolve(); } else { - self->HandleError( - self->logger_->MakeException("Flushing error.", std::move(status))); + self->HandleError(self->logger_->MakeEncodingError("Flushing error.", + std::move(status))); req->resolver.Release()->Reject(); } req->EndTracing();
diff --git a/third_party/blink/renderer/modules/webcodecs/video_encoder.cc b/third_party/blink/renderer/modules/webcodecs/video_encoder.cc index 377a2624..3035124 100644 --- a/third_party/blink/renderer/modules/webcodecs/video_encoder.cc +++ b/third_party/blink/renderer/modules/webcodecs/video_encoder.cc
@@ -694,7 +694,7 @@ media_encoder_ = CreateMediaVideoEncoder(*active_config_, gpu_factories); if (!media_encoder_) { - HandleError(logger_->MakeException( + HandleError(logger_->MakeOperationError( "Encoder creation error.", media::EncoderStatus( media::EncoderStatus::Codes::kEncoderInitializationError, @@ -740,7 +740,7 @@ } self->HandleError( - self->logger_->MakeException(error_message, std::move(status))); + self->logger_->MakeOperationError(error_message, std::move(status))); } else { UMA_HISTOGRAM_ENUMERATION("Blink.WebCodecs.VideoEncoder.Codec", codec, media::VideoCodec::kMaxValue); @@ -1027,7 +1027,8 @@ active_encodes_--; if (!status.is_ok()) { - HandleError(logger_->MakeException("Encoding error.", std::move(status))); + HandleError( + logger_->MakeEncodingError("Encoding error.", std::move(status))); } request->EndTracing(); ProcessRequests(); @@ -1096,7 +1097,7 @@ } DCHECK_CALLED_ON_VALID_SEQUENCE(self->sequence_checker_); if (!status.is_ok()) { - self->HandleError(self->logger_->MakeException( + self->HandleError(self->logger_->MakeOperationError( "Encoder initialization error.", std::move(status))); self->blocking_request_in_progress_ = false; req->EndTracing();
diff --git a/third_party/blink/renderer/platform/graphics/test/mock_compositor_frame_sink.h b/third_party/blink/renderer/platform/graphics/test/mock_compositor_frame_sink.h index 6b9e14c..3e59679 100644 --- a/third_party/blink/renderer/platform/graphics/test/mock_compositor_frame_sink.h +++ b/third_party/blink/renderer/platform/graphics/test/mock_compositor_frame_sink.h
@@ -13,6 +13,7 @@ #include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/cpp/bindings/receiver.h" #include "services/viz/public/mojom/compositing/compositor_frame_sink.mojom-blink.h" +#include "services/viz/public/mojom/compositing/layer_context.mojom-blink.h" #include "testing/gmock/include/gmock/gmock.h" #include "third_party/blink/public/mojom/frame_sinks/embedded_frame_sink.mojom-blink-forward.h" @@ -64,6 +65,8 @@ MOCK_METHOD1(SetPreferredFrameInterval, void(base::TimeDelta)); MOCK_METHOD1(InitializeCompositorFrameSinkType, void(viz::mojom::CompositorFrameSinkType)); + MOCK_METHOD1(BindLayerContext, + void(viz::mojom::blink::PendingLayerContextPtr)); MOCK_METHOD1(SetThreadIds, void(const WTF::Vector<int32_t>&)); private:
diff --git a/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc b/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc index d5260d8..c0a5ea7 100644 --- a/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc +++ b/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc
@@ -30,6 +30,7 @@ #include "services/viz/public/cpp/gpu/context_provider_command_buffer.h" #include "services/viz/public/mojom/compositing/compositor_frame_sink.mojom-blink.h" #include "services/viz/public/mojom/compositing/frame_sink_bundle.mojom-blink.h" +#include "services/viz/public/mojom/compositing/layer_context.mojom-blink.h" #include "services/viz/public/mojom/hit_test/hit_test_region_list.mojom-blink.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/blink/public/common/thread_safe_browser_interface_broker_proxy.h" @@ -152,6 +153,9 @@ bundle_->InitializeCompositorFrameSinkType(frame_sink_id_.sink_id(), type); } + void BindLayerContext( + viz::mojom::blink::PendingLayerContextPtr context) override {} + #if BUILDFLAG(IS_ANDROID) void SetThreadIds(const WTF::Vector<int32_t>& thread_ids) override { bundle_->SetThreadIds(frame_sink_id_.sink_id(), thread_ids);
diff --git a/third_party/blink/renderer/platform/graphics/video_frame_submitter_test.cc b/third_party/blink/renderer/platform/graphics/video_frame_submitter_test.cc index 6ef6725f..5887c8e 100644 --- a/third_party/blink/renderer/platform/graphics/video_frame_submitter_test.cc +++ b/third_party/blink/renderer/platform/graphics/video_frame_submitter_test.cc
@@ -31,6 +31,7 @@ #include "mojo/public/cpp/bindings/receiver.h" #include "mojo/public/cpp/bindings/remote.h" #include "services/viz/public/mojom/compositing/compositor_frame_sink.mojom-blink.h" +#include "services/viz/public/mojom/compositing/layer_context.mojom-blink.h" #include "services/viz/public/mojom/hit_test/hit_test_region_list.mojom-blink.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -116,6 +117,8 @@ MOCK_METHOD1(DidDeleteSharedBitmap, void(const gpu::Mailbox& id)); MOCK_METHOD1(InitializeCompositorFrameSinkType, void(viz::mojom::CompositorFrameSinkType)); + MOCK_METHOD1(BindLayerContext, + void(viz::mojom::blink::PendingLayerContextPtr)); MOCK_METHOD1(SetThreadIds, void(const WTF::Vector<int32_t>&)); private:
diff --git a/third_party/blink/renderer/platform/widget/input/widget_input_handler_manager.cc b/third_party/blink/renderer/platform/widget/input/widget_input_handler_manager.cc index 12ed57ee..fe2da01 100644 --- a/third_party/blink/renderer/platform/widget/input/widget_input_handler_manager.cc +++ b/third_party/blink/renderer/platform/widget/input/widget_input_handler_manager.cc
@@ -601,28 +601,26 @@ event->EventPointer()->SetTimeStamp(base::TimeTicks::Now()); } - // TODO(b/224960731): Fix tests and add - // `DCHECK(!arrived_in_browser_main_timestamp.is_null())`. - // We expect that `arrived_in_browser_main_timestamp` is always - // found, but there are a lot of tests where this component is not set. - // Currently EventMetrics knows how to handle null timestamp, so we - // don't process it here. - const base::TimeTicks arrived_in_browser_main_timestamp = - event->Event() - .GetEventLatencyMetadata() - .arrived_in_browser_main_timestamp; std::unique_ptr<cc::EventMetrics> metrics; if (event->Event().IsGestureScroll()) { const auto& gesture_event = static_cast<const WebGestureEvent&>(event->Event()); const bool is_inertial = gesture_event.InertialPhase() == WebGestureEvent::InertialPhaseState::kMomentum; - //'scrolls_blocking_touch_dispatched_to_renderer' can be null. It is set - // by the Browser only if the corresponding TouchMove was blocking. - base::TimeTicks blocking_touch_dispatched_to_renderer_timestamp = - event->Event() - .GetEventLatencyMetadata() - .scrolls_blocking_touch_dispatched_to_renderer; + + // TODO(b/224960731): It is not recommended to use LatencyInfo. So we need + // to create a separate field with "arrived_in_browser_main" timestamp in + // WebInputEvent and use it here. + base::TimeTicks arrived_in_browser_main_timestamp; + event->latency_info().FindLatency( + ui::LatencyComponentType::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, + &(arrived_in_browser_main_timestamp)); + // TODO(b/224960731): Fix tests and add + // `DCHECK(!arrived_in_browser_main_timestamp.is_null())`. + // We expect that `INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT` is always + // found, but there are a lot of tests where this component is not set. + // Currently EventMetrics knows how to handle null timestamp, so we + // don't process it here. if (gesture_event.GetType() == WebInputEvent::Type::kGestureScrollUpdate) { metrics = cc::ScrollUpdateEventMetrics::Create( @@ -634,15 +632,13 @@ gesture_event.data.scroll_update.delta_y, event->Event().TimeStamp(), arrived_in_browser_main_timestamp, base::IdType64<class ui::LatencyInfo>( - event->latency_info().trace_id()), - blocking_touch_dispatched_to_renderer_timestamp); + event->latency_info().trace_id())); has_seen_first_gesture_scroll_update_after_begin_ = true; } else { metrics = cc::ScrollEventMetrics::Create( gesture_event.GetTypeAsUiEventType(), gesture_event.GetScrollInputType(), is_inertial, - event->Event().TimeStamp(), arrived_in_browser_main_timestamp, - blocking_touch_dispatched_to_renderer_timestamp); + event->Event().TimeStamp(), arrived_in_browser_main_timestamp); has_seen_first_gesture_scroll_update_after_begin_ = false; } } else if (WebInputEvent::IsPinchGestureEventType(event->Event().GetType())) { @@ -653,8 +649,7 @@ gesture_event.GetScrollInputType(), event->Event().TimeStamp()); } else { metrics = cc::EventMetrics::Create(event->Event().GetTypeAsUiEventType(), - event->Event().TimeStamp(), - arrived_in_browser_main_timestamp); + event->Event().TimeStamp()); } if (uses_input_handler_) {
diff --git a/third_party/blink/tools/blinkpy/tool/commands/lint_wpt.py b/third_party/blink/tools/blinkpy/tool/commands/lint_wpt.py index 9d781c52..68ddf852 100644 --- a/third_party/blink/tools/blinkpy/tool/commands/lint_wpt.py +++ b/third_party/blink/tools/blinkpy/tool/commands/lint_wpt.py
@@ -4,6 +4,7 @@ """Lint WPT files and metadata.""" import argparse +import collections import contextlib import enum import io @@ -160,7 +161,7 @@ implementation_statuses = {'implementing', 'not-implementing', 'default'} -class MetadataUnnecessaryCondition(MetadataRule): +class MetadataConditionsUnnecessary(MetadataRule): name = 'META-CONDITIONS-UNNECESSARY' description = '%(section_type)s key %(key)r always has value %(value)r' to_fix = """ @@ -186,6 +187,16 @@ """ +class MetadataUnknownPropValue(MetadataRule): + name = 'META-UNKNOWN-PROP-VALUE' + description = ('%(section_type)s key %(key)r %(condition)s compares ' + '%(prop)r against unrecognized value %(value)r') + to_fix = """ + Check that all property values are valid and spelled correctly: + https://chromium.googlesource.com/chromium/src/+/HEAD/docs/testing/web_platform_tests_wptrunner.md#conditional-values + """ + + LintError = Tuple[str, str, str, Optional[int]] ValueNode = Union[wptnode.ValueNode, wptnode.AtomNode, wptnode.ListNode] Condition = Optional[wptnode.Node] @@ -280,6 +291,8 @@ # also provided to the error message formatter. self.context = {} self.errors = set() + # Check that all configurations have the same keys. + assert len(set({frozenset(config.data) for config in configs})) == 1 @contextlib.contextmanager def using_context(self, **context): @@ -347,7 +360,9 @@ if node.data not in valid_keys: self._error(MetadataUnknownKey) else: - self._check_conditions(node) + with self.using_context( + prop_comparisons=collections.defaultdict(set)): + self._check_conditions(node) def _get_conditional_values( self, @@ -399,14 +414,21 @@ if (len([condition for condition in conditions if condition]) > 0 and len(unique_values) == 1): - self._error(MetadataUnnecessaryCondition, + self._error(MetadataConditionsUnnecessary, value=_format_node(values[0])) - else: - # No need to show that condition branches are unreachable if no - # conditions are necessary in the first place. - for i in conditions_not_taken: - self._error(MetadataUnreachableValue, - condition=_format_condition(conditions[i])) + return + # No need to show condition-related errors if no conditions are + # necessary in the first place. + for i in conditions_not_taken: + self._error(MetadataUnreachableValue, + condition=_format_condition(conditions[i])) + for prop, values in self.context['prop_comparisons'].items(): + unknown_values = values - {config[prop] for config in self.configs} + for value in unknown_values: + self._error(MetadataUnknownPropValue, + prop=prop, + value=value, + condition=_format_condition(condition)) def _eval_condition_taken(self, condition: Condition, run_info: metadata.RunInfo) -> bool: @@ -415,6 +437,22 @@ self.expr_data = run_info.data return self.visit(condition) + def visit_BinaryExpressionNode(self, + node: wptnode.BinaryExpressionNode) -> bool: + # Evaluate the result first to check for unknown properties, which will + # raise a `KeyError`. + result = super().visit_BinaryExpressionNode(node) + _, operand0, operand1 = node.children + # Canonicalize operand order. + operand0, operand1 = sorted( + [operand0, operand1], + key=lambda operand: isinstance(operand, wptnode.VariableNode)) + if (isinstance(operand0, (wptnode.NumberNode, wptnode.StringNode)) + and isinstance(operand1, wptnode.VariableNode)): + value, prop = operand0.data, operand1.data + self.context['prop_comparisons'][prop].add(value) + return result + def visit_ListNode(self, node: wptnode.ListNode) -> Tuple[Union[bool, str]]: key = self.context['key']
diff --git a/third_party/blink/tools/blinkpy/tool/commands/lint_wpt_unittest.py b/third_party/blink/tools/blinkpy/tool/commands/lint_wpt_unittest.py index a8d1511d..24f40d652 100644 --- a/third_party/blink/tools/blinkpy/tool/commands/lint_wpt_unittest.py +++ b/third_party/blink/tools/blinkpy/tool/commands/lint_wpt_unittest.py
@@ -483,3 +483,28 @@ description, "Test key 'expected' condition " "'if (os == \"linux\") or (prduct == \"chrome\")' " "uses unrecognized property 'prduct'") + + def test_metadata_unknown_prop_value(self): + unrecognized_os, unrecognized_product = self._check_metadata("""\ + [reftest.html] + # Note that both keys are reachable by some test configuration. + disabled: + if os == "mac" or os == "fuchsia": wontfix + expected: + if os == "mac" or (os == "linux" and "contentshell" != product): FAIL + """) + name, description, path, _ = unrecognized_os + self.assertEqual(name, 'META-UNKNOWN-PROP-VALUE') + self.assertEqual(path, 'reftest.html.ini') + self.assertEqual( + description, "Test key 'disabled' condition " + "'if (os == \"mac\") or (os == \"fuchsia\")' " + "compares 'os' against unrecognized value 'fuchsia'") + name, description, path, _ = unrecognized_product + self.assertEqual(name, 'META-UNKNOWN-PROP-VALUE') + self.assertEqual(path, 'reftest.html.ini') + self.assertEqual( + description, + "Test key 'expected' condition 'if (os == \"mac\") or " + "((os == \"linux\") and (\"contentshell\" != product))' " + "compares 'product' against unrecognized value 'contentshell'")
diff --git a/third_party/blink/tools/blinkpy/web_tests/port/base.py b/third_party/blink/tools/blinkpy/web_tests/port/base.py index fed9bc43..e352459 100644 --- a/third_party/blink/tools/blinkpy/web_tests/port/base.py +++ b/third_party/blink/tools/blinkpy/web_tests/port/base.py
@@ -127,6 +127,8 @@ # contain all the disc artifacts created by web tests ARTIFACTS_SUB_DIR = 'layout-test-results' +ENABLE_THREADED_COMPOSITING_FLAG = '--enable-threaded-compositing' + class Port(object): """Abstract class for Port-specific hooks for the web_test package.""" @@ -1625,6 +1627,11 @@ file_name = 'trace_layout_test_{}_{}.json'.format( self._filesystem.sanitize_filename(test_name), current_time) args.append('--trace-startup-file=' + file_name) + + if self._is_in_allowlist_for_threaded_compositing(test_name): + if (ENABLE_THREADED_COMPOSITING_FLAG not in args): + args.append(ENABLE_THREADED_COMPOSITING_FLAG) + return args @memoized @@ -2519,6 +2526,12 @@ return suite.args return [] + def _is_in_allowlist_for_threaded_compositing(self, test_name): + # We start with a very simple and small subset of the tests to create + # the infrastructure for an allowlist and plan to move to an external + # file soon. + return test_name.startswith("vibration") + def _build_path(self, *comps): """Returns a path from the build directory.""" return self._build_path_with_target(self._options.target, *comps)
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index 6821caf..4124ac70 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -858,7 +858,7 @@ crbug.com/1044742 external/wpt/css/compositing/mix-blend-mode/mix-blend-mode-filter.html [ Failure ] crbug.com/1044742 external/wpt/css/compositing/mix-blend-mode/mix-blend-mode-stacking-context-001.html [ Failure ] crbug.com/1044742 [ Mac10.13 ] external/wpt/css/compositing/mix-blend-mode/mix-blend-mode-video.html [ Failure ] -crbug.com/1044742 [ Mac10.14 ] external/wpt/css/compositing/mix-blend-mode/mix-blend-mode-video.html [ Failure Crash ] +crbug.com/1044742 [ Mac10.14 ] external/wpt/css/compositing/mix-blend-mode/mix-blend-mode-video.html [ Crash Failure ] crbug.com/1044742 [ Mac10.15 ] external/wpt/css/compositing/mix-blend-mode/mix-blend-mode-video.html [ Failure ] crbug.com/1044742 [ Mac11 ] external/wpt/css/compositing/mix-blend-mode/mix-blend-mode-video.html [ Failure ] crbug.com/1044742 [ Mac11-arm64 ] external/wpt/css/compositing/mix-blend-mode/mix-blend-mode-video.html [ Failure ] @@ -2723,7 +2723,7 @@ crbug.com/1088475 [ Fuchsia ] external/wpt/webvtt/rendering/cues-with-video/processing-model/embedded_style_media_queries_resized.html [ Failure Pass Timeout ] crbug.com/1088475 [ Linux ] external/wpt/webvtt/rendering/cues-with-video/processing-model/embedded_style_media_queries_resized.html [ Failure Pass Timeout ] crbug.com/1088475 [ Mac10.13 ] external/wpt/webvtt/rendering/cues-with-video/processing-model/embedded_style_media_queries_resized.html [ Failure Pass Timeout ] -crbug.com/1088475 [ Mac10.14 ] external/wpt/webvtt/rendering/cues-with-video/processing-model/embedded_style_media_queries_resized.html [ Failure Crash ] +crbug.com/1088475 [ Mac10.14 ] external/wpt/webvtt/rendering/cues-with-video/processing-model/embedded_style_media_queries_resized.html [ Crash Failure ] crbug.com/1088475 [ Mac10.15 ] external/wpt/webvtt/rendering/cues-with-video/processing-model/embedded_style_media_queries_resized.html [ Failure Pass Timeout ] crbug.com/1088475 [ Mac11 ] external/wpt/webvtt/rendering/cues-with-video/processing-model/embedded_style_media_queries_resized.html [ Failure Pass Timeout ] crbug.com/1088475 [ Mac11-arm64 ] external/wpt/webvtt/rendering/cues-with-video/processing-model/embedded_style_media_queries_resized.html [ Failure Pass Timeout ] @@ -2956,6 +2956,20 @@ crbug.com/626703 external/wpt/css/css-multicol/file-control-crash.html [ Crash ] # ====== New tests from wpt-importer added here ====== +crbug.com/626703 external/wpt/css/mediaqueries/scripting-print-noscript.html [ Failure ] +crbug.com/626703 external/wpt/css/mediaqueries/scripting-print-script.html [ Failure ] +crbug.com/626703 external/wpt/css/selectors/selectors-4/lang-002.html [ Failure ] +crbug.com/626703 external/wpt/css/selectors/selectors-4/lang-003.html [ Failure ] +crbug.com/626703 external/wpt/css/selectors/selectors-4/lang-004.html [ Failure ] +crbug.com/626703 external/wpt/css/selectors/selectors-4/lang-007.html [ Failure ] +crbug.com/626703 external/wpt/css/selectors/selectors-4/lang-008.html [ Failure ] +crbug.com/626703 external/wpt/css/selectors/selectors-4/lang-009.html [ Failure ] +crbug.com/626703 external/wpt/css/selectors/selectors-4/lang-010.html [ Failure ] +crbug.com/626703 external/wpt/css/selectors/selectors-4/lang-011.html [ Failure ] +crbug.com/626703 external/wpt/css/selectors/selectors-4/lang-012.html [ Failure ] +crbug.com/626703 external/wpt/css/selectors/selectors-4/lang-015.html [ Failure ] +crbug.com/626703 [ Linux ] external/wpt/mediacapture-record/passthrough/MediaRecorder-passthrough.https.html [ Timeout ] +crbug.com/626703 [ Mac11 ] external/wpt/mediacapture-record/passthrough/MediaRecorder-passthrough.https.html [ Timeout ] crbug.com/626703 external/wpt/css/css-color/system-color-hightlights-vs-getSelection-001.html [ Failure ] crbug.com/626703 [ Linux ] external/wpt/mediacapture-record/MediaRecorder-mimetype.html [ Timeout ] crbug.com/626703 [ Mac10.14 ] external/wpt/mediacapture-record/MediaRecorder-mimetype.html [ Timeout ] @@ -6861,7 +6875,14 @@ crbug.com/1432448 external/wpt/webnn/* [ Failure ] # Sheriff 2023-04-12 -crbug.com/1432666 [ Mac ] external/wpt/mediacapture-record/passthrough/MediaRecorder-passthrough.https.html [ Failure Pass ] +crbug.com/1432666 [ Mac10.13 ] external/wpt/mediacapture-record/passthrough/MediaRecorder-passthrough.https.html [ Failure Pass ] +crbug.com/1432666 [ Mac10.14 ] external/wpt/mediacapture-record/passthrough/MediaRecorder-passthrough.https.html [ Failure Pass ] +crbug.com/1432666 [ Mac10.15 ] external/wpt/mediacapture-record/passthrough/MediaRecorder-passthrough.https.html [ Failure Pass ] +crbug.com/1432666 [ Mac11-arm64 ] external/wpt/mediacapture-record/passthrough/MediaRecorder-passthrough.https.html [ Failure Pass ] +crbug.com/1432666 [ Mac12 ] external/wpt/mediacapture-record/passthrough/MediaRecorder-passthrough.https.html [ Failure Pass ] +crbug.com/1432666 [ Mac12-arm64 ] external/wpt/mediacapture-record/passthrough/MediaRecorder-passthrough.https.html [ Failure Pass ] +crbug.com/1432666 [ Mac13 ] external/wpt/mediacapture-record/passthrough/MediaRecorder-passthrough.https.html [ Failure Pass ] +crbug.com/1432666 [ Mac13-arm64 ] external/wpt/mediacapture-record/passthrough/MediaRecorder-passthrough.https.html [ Failure Pass ] # Sheriff 2023-04-13 crbug.com/1432763 [ Linux ] external/wpt/fetch/metadata/generated/element-picture.https.sub.html [ Pass Timeout ]
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 7d825c2..e4ff798 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
@@ -18601,7 +18601,7 @@ ] ], "scroll-timeline-specified-scroller-print.html": [ - "7e5b6607b6e9e99705022e10310816f2862732d8", + "05fab3e46ad22d01d26d5fe5ba90edb4dab798f3", [ null, [ @@ -110776,6 +110776,19 @@ {} ] ], + "dynamic-align-self-001.html": [ + "208c006d2d056888dba662ea593410970e848ca9", + [ + null, + [ + [ + "/css/reference/ref-filled-green-100px-square.xht", + "==" + ] + ], + {} + ] + ], "flex-abspos-staticpos-align-self-safe-001.html": [ "b7302cb962dbff9bfc99592ac7a2d2f2aae52b21", [ @@ -112910,6 +112923,19 @@ {} ] ], + "flex-aspect-ratio-img-row-017.html": [ + "b2408159b5af0c445333b4a3e6ab0d9d4353d78f", + [ + null, + [ + [ + "/css/reference/ref-filled-green-100px-square.xht", + "==" + ] + ], + {} + ] + ], "flex-basis-001.html": [ "85e3bc69c435da542f520bc0e5b9b0afe911f0ad", [ @@ -120344,6 +120370,19 @@ {} ] ], + "grandchild-span-height.html": [ + "c087edb68d48036f5b3a45114a62d9db03a5a86e", + [ + null, + [ + [ + "/css/reference/ref-filled-green-100px-square.xht", + "==" + ] + ], + {} + ] + ], "grid-flex-item-001.html": [ "67ee0fb001d7b136f026190bfee0940aeb4ff849", [ @@ -120422,6 +120461,19 @@ {} ] ], + "grid-flex-item-007.html": [ + "bdea17d0692981c4742448f1c429e90236418858", + [ + null, + [ + [ + "/css/reference/ref-filled-green-100px-square.xht", + "==" + ] + ], + {} + ] + ], "image-items-flake-001.html": [ "90319f1ad83d26d414d8ddcd4a9ab59042a4bd62", [ @@ -121728,6 +121780,19 @@ {} ] ], + "table-as-flex-item-max-content.html": [ + "c7316aab950ddb1ceb6f05933ae9f1cec481f191", + [ + null, + [ + [ + "/css/reference/ref-filled-green-100px-square.xht", + "==" + ] + ], + {} + ] + ], "table-as-item-auto-min-width.html": [ "66a77327f0f25e07db87e342ebb590358d045f7a", [ @@ -136870,7 +136935,7 @@ ] ], "image-orientation-none-cross-origin.html": [ - "e36c1295d31d43e48a6745021be3346838431158", + "ec139d4e229224de8c9953ecf748af2cf28cb197", [ null, [ @@ -244103,6 +244168,32 @@ {} ] ], + "scripting-print-noscript.html": [ + "1d1af708fd7e746ef991d2067a5a32b150672893", + [ + null, + [ + [ + "/css/mediaqueries/scripting-print-noscript-ref.html", + "==" + ] + ], + {} + ] + ], + "scripting-print-script.html": [ + "e80dba4d83f586df8ba48fde04356a0361861b69", + [ + null, + [ + [ + "/css/mediaqueries/scripting-print-script-ref.html", + "==" + ] + ], + {} + ] + ], "viewport-script-dynamic.html": [ "7433877972b09b3a03cd9f8a11dcd3efd1aa01d6", [ @@ -248030,6 +248121,216 @@ {} ] ], + "selectors-4": { + "lang-000.html": [ + "1d66bebbc6b53706ae782eec7b6a70cbaba3ec7f", + [ + null, + [ + [ + "/css/selectors/selectors-4/lang-000-ref.html", + "==" + ] + ], + {} + ] + ], + "lang-001.html": [ + "908643fca81d533e76869c6af874fb3797991bfc", + [ + null, + [ + [ + "/css/selectors/selectors-4/lang-000-ref.html", + "==" + ] + ], + {} + ] + ], + "lang-002.html": [ + "0be426c66e7d4e1e12de1778db3256752a7a560a", + [ + null, + [ + [ + "/css/selectors/selectors-4/lang-000-ref.html", + "==" + ] + ], + {} + ] + ], + "lang-003.html": [ + "a3e5340b6e915d32963261669991d4040df7f096", + [ + null, + [ + [ + "/css/selectors/selectors-4/lang-000-ref.html", + "==" + ] + ], + {} + ] + ], + "lang-004.html": [ + "d592997270746bb0cbfa286dad65d3539e519ecb", + [ + null, + [ + [ + "/css/selectors/selectors-4/lang-000-ref.html", + "==" + ] + ], + {} + ] + ], + "lang-005.html": [ + "816dfc9b5034e8d9787be254660012e70b60c55d", + [ + null, + [ + [ + "/css/selectors/selectors-4/lang-000-ref.html", + "==" + ] + ], + {} + ] + ], + "lang-006.html": [ + "d249a4c8c06a5e9a10b40df6a9bab68f367a69d2", + [ + null, + [ + [ + "/css/selectors/selectors-4/lang-000-ref.html", + "==" + ] + ], + {} + ] + ], + "lang-007.html": [ + "a21506d94c1125da970792b3e2da5a542f96e332", + [ + null, + [ + [ + "/css/selectors/selectors-4/lang-000-ref.html", + "==" + ] + ], + {} + ] + ], + "lang-008.html": [ + "77f77a884ac5088c360c34971eec637e48c42cff", + [ + null, + [ + [ + "/css/selectors/selectors-4/lang-000-ref.html", + "==" + ] + ], + {} + ] + ], + "lang-009.html": [ + "bf2e9883916ea0e219a968b7dd6b0457e312d794", + [ + null, + [ + [ + "/css/selectors/selectors-4/lang-000-ref.html", + "==" + ] + ], + {} + ] + ], + "lang-010.html": [ + "081c9207add489896a7db13d946658d249bd893b", + [ + null, + [ + [ + "/css/selectors/selectors-4/lang-000-ref.html", + "==" + ] + ], + {} + ] + ], + "lang-011.html": [ + "5620317a14be99de361c456dbea873bdd294562f", + [ + null, + [ + [ + "/css/selectors/selectors-4/lang-000-ref.html", + "==" + ] + ], + {} + ] + ], + "lang-012.html": [ + "f299e22eaecd2bde8351b01fca62ed8eaf2eab49", + [ + null, + [ + [ + "/css/selectors/selectors-4/lang-000-ref.html", + "==" + ] + ], + {} + ] + ], + "lang-013.html": [ + "34303d97805386d7ca1ece6a61ebcdf1977f748d", + [ + null, + [ + [ + "/css/selectors/selectors-4/lang-000-ref.html", + "==" + ] + ], + {} + ] + ], + "lang-014.html": [ + "2d064c8d29b60fbb0d3351c6c019cbc3aca85521", + [ + null, + [ + [ + "/css/selectors/selectors-4/lang-000-ref.html", + "==" + ] + ], + {} + ] + ], + "lang-015.html": [ + "4d90b080f39607f09a63fe28756a6a51542094af", + [ + null, + [ + [ + "/css/selectors/selectors-4/lang-000-ref.html", + "==" + ] + ], + {} + ] + ] + }, "selectors-attr-many.html": [ "b38b8f52cfa7ef4290ecaa271b5bec95f676011d", [ @@ -249383,7 +249684,7 @@ }, "filters": { "2d.filter.canvasFilterObject.dropShadow.tentative.html": [ - "22c6a6547f23650f1f2f3d8a0cd57816386066a5", + "712716d9f01e8384c8a616d8d832c4fcbc94b7f0", [ null, [ @@ -250655,7 +250956,7 @@ "offscreen": { "filters": { "2d.filter.canvasFilterObject.dropShadow.tentative.html": [ - "04cf86d204ce8e143c6056eaf6499a3f768a4dec", + "043265279054d6d6852626700f6692a8b2413a6c", [ null, [ @@ -250668,7 +250969,7 @@ ] ], "2d.filter.canvasFilterObject.dropShadow.tentative.w.html": [ - "8d5e2da1586a56943588f9d343e96e7c32233386", + "de72f5fe3d9fa07c4a12906fc0fef2ac909ba6ed", [ null, [ @@ -269374,11 +269675,11 @@ "support": { ".cache": { "gitignore2.json": [ - "fb67ea1db4520c1c9de6d60c661b4c68eef2335c", + "1c376ec726001351bcb99f7d7d52408bb26060c4", [] ], "mtime.json": [ - "38c343141c3b7b7309e1733a4174d62a0a76699a", + "1f3cee39d216df08639f1757489e81fba625175f", [] ] }, @@ -269444,10 +269745,6 @@ ], "FileAPI": { "BlobURL": { - "cross-partition.tentative.https-expected.txt": [ - "baf1499f392564b77983a515b960d6849445989e", - [] - ], "cross-partition.tentative.https.html.ini": [ "eb7eb82c1ad85fcff850c80bf9f81a55b8b7d523", [] @@ -271457,7 +271754,7 @@ [] ], "reports.py": [ - "432f5c61d5e9c452a24e8985b846da0ce7079c0c", + "4d4c3fd5ec739e23d8a136070050e8d31733c969", [] ] } @@ -288647,11 +288944,11 @@ [] ], "import-conditions-expected.txt": [ - "e1615689ea83cfadf93534f90e8f41460ebe7ea0", + "cdcdc59bba332c229c883a9461e6bce7ca0fa372", [] ], "import-conditions.html.ini": [ - "f849a37e94532cb2c83104e2e8cefe1ac71000ae", + "5fe16a522e9d0df2672ec4d1b99c99bb08f64e6d", [] ], "important-prop-ref.html": [ @@ -292303,6 +292600,10 @@ [] ], "abspos": { + "dynamic-align-self-001.html.ini": [ + "14f97016c847bfe7f2cfa813b0c31edb24af63b3", + [] + ], "flex-abspos-staticpos-align-content-002-expected.txt": [ "03063a3bcf60c04a2b4fa9f692af19accba9c1ca", [] @@ -294116,6 +294417,10 @@ [] ] }, + "justify-content-007.html.ini": [ + "ea29b95ecec1c1d29c829371a9786ae86f08e47a", + [] + ], "order": { "order-abs-children-painting-order.html.ini": [ "5065278c599a2da10c5cf1021e13a4a439c70a83", @@ -304236,7 +304541,7 @@ [] ], "baseline-001.html.ini": [ - "a20c5862f445060ac235a6fc9ef0f4992aa3482b", + "4c85dd9b7193428d24f01b2fc1e9ca7d29415d19", [] ], "grid-gap-001-ref.html": [ @@ -304544,7 +304849,7 @@ [] ], "subgrid-baseline-001.html.ini": [ - "714bf4bc043e6d3a1114a38a1655cb32f33eac16", + "c181d4a8d962469dd2f1764ca1bb7918d899ba2a", [] ], "subgrid-baseline-002-ref.html": [ @@ -304552,7 +304857,7 @@ [] ], "subgrid-baseline-002.html.ini": [ - "c8f5d5e48be8ad5beb292de4b0b9e096c087a92d", + "e93ab475c911afec99ee01f28bff235a3a943922", [] ], "subgrid-baseline-003-ref.html": [ @@ -304959,7 +305264,7 @@ [] ], "image-orientation-none-cross-origin-ref.html": [ - "c4d72fc823f3e98d7184c0536805b6f6e8be6f7c", + "a54aa3870f669108afcd535766331cf4e43dbbe0", [] ], "image-orientation-none-cross-origin-svg-ref.html": [ @@ -323346,6 +323651,10 @@ "e4d46ead9136c13c6033481d5f3e8fd09047883c", [] ], + "preserve3d-and-flattening-z-order-004.html.ini": [ + "9fdf89b3e6b5d5de5e0987ac93b05ac258b4cf47", + [] + ], "preserve3d-and-flattening-z-order-005.html.ini": [ "4213558575242110a545f45c46c0513103bb6fe2", [] @@ -325983,6 +326292,10 @@ "b4a6cd0424faf240ea0c27138ce860cae893b015", [] ], + "kind-of-widget-fallback-button-border-image-width-001.html.ini": [ + "1844f8148e078025305bbee81e80e1091d402d1e", + [] + ], "kind-of-widget-fallback-color-input-background-attachment-001.html.ini": [ "af8320f8847d4948398b722cc08cff19e152181b", [] @@ -326172,7 +326485,7 @@ [] ], "kind-of-widget-fallback-input-search-border-inline-start-width-001.html.ini": [ - "4c3c8c359dada68fde75e2e51aa3b0528208089f", + "c81ecad2ba02fb5eb9e1adaf58d1de50df2d9d53", [] ], "kind-of-widget-fallback-input-search-border-left-color-001.html.ini": [ @@ -326515,6 +326828,10 @@ "ee737becadbdfae290cdb1d571146cff26e9cce7", [] ], + "kind-of-widget-fallback-input-text-border-start-start-radius-001.html.ini": [ + "7889dd6c42a26abdf2fa0d3b5a1f25ecda464ba2", + [] + ], "kind-of-widget-fallback-input-text-border-top-color-001.html.ini": [ "ba05f649f0ed735eaaec24e14f887181dcc6022a", [] @@ -333412,6 +333729,10 @@ "999894eb81f29dc441731d46772539db6b41ed2a", [] ], + "backdrop-filters-brightness.html.ini": [ + "a95d0fb793c07b57e380d0d72eafdc6a502b81f4", + [] + ], "backdrop-filters-contrast-ref.html": [ "01b38f7b33762fba831c9d5b92a448a8991218e0", [] @@ -334310,6 +334631,26 @@ "b24009718e8958e6e753249b691b1bce2d3f47f0", [] ], + "scripting-print-noscript-ref.html": [ + "2dd7aff83136a14dd9559249615438183d3b0d88", + [] + ], + "scripting-print-noscript.html.ini": [ + "f8256a3571751ec315c9743226636d05fdff3667", + [] + ], + "scripting-print-script-ref.html": [ + "d2da3f840586d803c83dc6bba11080e7b27d88ad", + [] + ], + "scripting-print-script.html.ini": [ + "2143b97f4b4b810d80150c326dd0484d02280623", + [] + ], + "scripting.html.ini": [ + "cfe3783f2c342e818eff0077d5181ea7b045f362", + [] + ], "support": { "media_queries_iframe.html": [ "890eb6c46113afbaf1dc88188c52a791623590a8", @@ -335294,6 +335635,52 @@ "6523fd3b64fbf10693c9d6c9a05b2da6328d6684", [] ], + "selectors-4": { + "lang-000-ref.html": [ + "466e9f464b906a114094b87249130bc8ff585a3b", + [] + ], + "lang-002.html.ini": [ + "de628205133b42a518a700b685b39f2670f8980e", + [] + ], + "lang-003.html.ini": [ + "10dbf116fb30481044c42a5365691fc22750e029", + [] + ], + "lang-004.html.ini": [ + "0d17f9d2379b27df8311b95ba0bc976fc3e17b9d", + [] + ], + "lang-007.html.ini": [ + "6d4b6e19bf29fba66e273e89bb6d6590e692e76a", + [] + ], + "lang-008.html.ini": [ + "fdb6efba6d30b9c31f29ccf1f06f6869cbd38f87", + [] + ], + "lang-009.html.ini": [ + "066833d397a872690fa38dd485c83673859528be", + [] + ], + "lang-010.html.ini": [ + "15ec088e45e9112593cfbd5bcae6d606223ac0fe", + [] + ], + "lang-011.html.ini": [ + "b168bf5cd3af3dbb7a74e2022a0d0e41c10893c8", + [] + ], + "lang-012.html.ini": [ + "cdc6bafba438cac45f3359a15f5d27a9d67ee232", + [] + ], + "lang-015.html.ini": [ + "98c067ba50e7f05cd0469a462088437d31a98870", + [] + ] + }, "selectors-attr-many-ref.html": [ "7d8a9f6d89d103373f81fa2f09c478b12e49ee7b", [] @@ -345549,7 +345936,7 @@ }, "script-tests": { "FileSystemBaseHandle-IndexedDB.js": [ - "15a0c2a3b579b308dfef01b0e1f9fa542641aaee", + "9e114619bf2caad6bbf53d25035c880818910dfa", [] ], "FileSystemBaseHandle-buckets.js": [ @@ -349957,7 +350344,7 @@ }, "filters": { "2d.filter.canvasFilterObject.dropShadow.tentative-expected.html": [ - "90f406fed9fd8545a352f2c213ace27b9556d3d7", + "8327b5cad483fd95393b8bf347452899992686d7", [] ] }, @@ -351011,7 +351398,7 @@ }, "filters": { "2d.filter.canvasFilterObject.dropShadow.tentative-expected.html": [ - "90f406fed9fd8545a352f2c213ace27b9556d3d7", + "8327b5cad483fd95393b8bf347452899992686d7", [] ] }, @@ -351513,7 +351900,7 @@ [] ], "filters.yaml": [ - "bdf3dcfe9fc47be1e8f8f562a619640fc05cc3b0", + "246b73e7f1a91863d9c2e05938c0d931cd1b1489", [] ], "layers.yaml": [ @@ -371213,6 +371600,10 @@ "aca65aa87cb2e022790e1660c5928d3b0c9da7fe", [] ], + "MediaStreamTrack-MediaElement-disabled-video-is-black.https.html.ini": [ + "e289c3ad6f7ef7926da5be1b5bbefa7e3b3b508c", + [] + ], "MediaStreamTrack-iframe-audio-transfer.https.html.ini": [ "8f1e84e28c10c1aa66945d52ceac7792ebcd4a0f", [] @@ -372048,6 +372439,10 @@ "f1c508edb00f094291f5e43e242b43b92d8bff5d", [] ], + "navigate-destination-dynamic-index.html.ini": [ + "9329a66bcec8d69d6ace3e1354e2eca928babad3", + [] + ], "navigate-history-back-after-fragment.html.ini": [ "16dd23c3d415061624dd5de59a8bbe379ad40eea", [] @@ -377585,7 +377980,7 @@ [] ], "mock-pressure-service.js": [ - "91efe529f2af9951f4f21c1c74038291152dbc93", + "e41464eefc32e154e29e48085a770b908e926437", [] ], "mock-pressure-service.js.headers": [ @@ -378088,7 +378483,7 @@ [] ], "scroll-timeline-specified-scroller-ref.html": [ - "9074f2454b1a81c7bd51b6af9167680e11496798", + "d2f2d8f73d71f84c0c1111e6f923929acdb22a3a", [] ] }, @@ -378141,6 +378536,14 @@ "view-timeline-inset-computed.html.ini": [ "f53ae66ef45d6a9ad008407d8659e1e3c395bf29", [] + ], + "view-timeline-lookup-expected.txt": [ + "58d0663a9332f29ca1c3b452b6f74f9791387d8d", + [] + ], + "view-timeline-lookup.html.ini": [ + "911d046f3635c8ccb228c1c27868c803a9031136", + [] ] }, "idlharness.window-expected.txt": [ @@ -381789,6 +382192,16 @@ "1fc6dd5522acbaea255f0d13c18ba4ab0a683fda", [] ], + "leaktests": { + "html-collection-expected.txt": [ + "4097c365a1c9e02a67b989a952582f4151229771", + [] + ], + "html-collection.html.ini": [ + "956589fdb72d4b3ebcef8e2c67175a610b41add4", + [] + ] + }, "reference": { "empty.html": [ "0e76edd65b7baf5316fc9d0c4da59a3502e4c27a", @@ -389672,7 +390085,7 @@ [] ], "fixtures_bidi.py": [ - "9407dc160704524e589dadd07a686d1d6dc40f4d", + "612718b89e57e6867b85e8d818fe30810859a1aa", [] ], "fixtures_http.py": [ @@ -389680,7 +390093,7 @@ [] ], "helpers.py": [ - "b0c065dca1189b711c44d23454760fde0181244c", + "45f4f4d23922dc3bf28d4d3117208f70ef90ca7f", [] ], "html": { @@ -392285,6 +392698,22 @@ "3291dcef88d077daf5e6b8a226e8081b9e43b627", [] ], + "datagrams.https.any-expected.txt": [ + "cdb67a1ed4ec1d30102afc1cdfb007fb0e8c82ed", + [] + ], + "datagrams.https.any.serviceworker-expected.txt": [ + "cdb67a1ed4ec1d30102afc1cdfb007fb0e8c82ed", + [] + ], + "datagrams.https.any.sharedworker-expected.txt": [ + "cdb67a1ed4ec1d30102afc1cdfb007fb0e8c82ed", + [] + ], + "datagrams.https.any.worker-expected.txt": [ + "cdb67a1ed4ec1d30102afc1cdfb007fb0e8c82ed", + [] + ], "handlers": { "abort-stream-from-server.py": [ "1d92b705e6de05e2cf56476698560511410df3c7", @@ -392353,7 +392782,7 @@ ], "resources": { "webtransport-test-helpers.sub.js": [ - "733153e12027d1e47fd823fa4fa8b47b1717b91f", + "9f9127b22f96da1c8dc84465d33e5c5e476f4262", [] ] } @@ -393422,7 +393851,7 @@ [] ], "non-standard-pseudo-elements.html.ini": [ - "2b6d832072013fee23f5824567691ad81ba91001", + "04e50d9b2b06a76ac60c36de1f9c20b944caaa39", [] ], "single_quote-ref.html": [ @@ -422265,7 +422694,7 @@ ] ], "compute_pressure_basic_async.tentative.https.window.js": [ - "3a9a32dedc0ea819c7eea013a5b22925960fba72", + "a70ffa98b130d3298b0f7f428ae027992058ff55", [ "compute-pressure/compute_pressure_basic_async.tentative.https.window.html", { @@ -422335,7 +422764,7 @@ ] ], "compute_pressure_duplicate_updates.tentative.https.window.js": [ - "3c312ca5b1fb6bc0693e6626063075bcb0e6e8ae", + "6318c0e88fb4336bef892727eac07b6a3c15d67e", [ "compute-pressure/compute_pressure_duplicate_updates.tentative.https.window.html", { @@ -422353,7 +422782,7 @@ ] ], "compute_pressure_factors.tentative.https.window.js": [ - "6d8d2208887007e429269b26cfd2891dfc497a29", + "fc2775559647ab6e06b9167ecae608c17d52c709", [ "compute-pressure/compute_pressure_factors.tentative.https.window.html", { @@ -422477,7 +422906,7 @@ ] ], "compute_pressure_timestamp.tentative.https.window.js": [ - "b9b932e64fcfedb03e7038ce5a963df2a1610336", + "aae56180aa3014e6faaa20d2dc421d9393e0ca42", [ "compute-pressure/compute_pressure_timestamp.tentative.https.window.html", { @@ -422495,7 +422924,7 @@ ] ], "compute_pressure_update_toJSON.tentative.https.window.js": [ - "7f3acf3e07fb0f537b057ac3d9181559dafd1c2f", + "f21cd464c6630eec60b89ead8510081c4b77d0fa", [ "compute-pressure/compute_pressure_update_toJSON.tentative.https.window.html", { @@ -433766,6 +434195,13 @@ {} ] ], + "display-none-dont-cancel.tentative.html": [ + "6ae115803b820ffdb51169c38769ee51f5062652", + [ + null, + {} + ] + ], "event-dispatch.tentative.html": [ "3e577d6ea6c67269766ed9ec38d13bd4cbda435c", [ @@ -435891,7 +436327,7 @@ ] ], "import-conditions.html": [ - "0bb09754702ce2c4f2655f2ec1c01ec8f78a661d", + "e5e1c685a9e214af6f0cd4a9eefa4f67056665e8", [ null, {} @@ -436051,6 +436487,13 @@ null, {} ] + ], + "supports-import-parsing.html": [ + "58e1f7cd165381d7ab53a6eb6feb03bbc976ef97", + [ + null, + {} + ] ] }, "presentational-hints-cascade.html": [ @@ -438831,6 +439274,13 @@ {} ] ], + "fieldset-as-container-justify-center.tentative.html": [ + "a1d7564e8a766d34e566df937ef2d6fd6def627b", + [ + null, + {} + ] + ], "flex-aspect-ratio-img-column-011.html": [ "f716d5ad6c896624577b253ea37e66954c08c358", [ @@ -439857,6 +440307,13 @@ {} ] ], + "justify-content-007.html": [ + "2ce9177a76639f1bbfaedb736d4ed620d6e1b3d1", + [ + null, + {} + ] + ], "justify-content_space-between-002.html": [ "fde1a7312408d02fe3843452585de2ee660ae6f7", [ @@ -465038,6 +465495,13 @@ {} ] ], + "scripting.html": [ + "de047cb463cff5c1d8af268f1e08908c9684fe8c", + [ + null, + {} + ] + ], "test_media_queries.html": [ "20fca4affd24e5a3d1335b9d39420f653c7cd9fb", [ @@ -465989,7 +466453,7 @@ ] ], "css3-selectors-lang-014.html": [ - "5e68d50d5a07211dcc1cb70235da5efa96e38759", + "411d50d35e50f46609fa98a6c60b3ef1065aa5a1", [ null, {} @@ -515912,56 +516376,56 @@ }, "filters": { "2d.filter.canvasFilterObject.blur.exceptions.tentative.html": [ - "d64b81026ad5f60494b2df0db50b11fb01bfb255", + "77818444c87c90312000dc6a601eb5985be1f070", [ null, {} ] ], "2d.filter.canvasFilterObject.colorMatrix.tentative.html": [ - "678a722520a98bb0039c3c0fb846c320fd943800", + "a56840e60739638fbf54e1363d119fab56dca3e3", [ null, {} ] ], "2d.filter.canvasFilterObject.componentTransfer.discrete.tentative.html": [ - "0ecd132c8efa286b90f5a2777e1351c3204316d0", + "c54299ff2a5a45f66bf67ff31d1945c201ed4f82", [ null, {} ] ], "2d.filter.canvasFilterObject.componentTransfer.gamma.tentative.html": [ - "4ef30c9249bb01fa1780f8ab07d677b087073ff2", + "110cd2396ea893dd9586098e9810399f63a179f2", [ null, {} ] ], "2d.filter.canvasFilterObject.componentTransfer.identity.tentative.html": [ - "25eda36d96b08779e73cb385ae5496e623976461", + "96a3e4936ee2640f792b971ff4b9f702e7e3b79f", [ null, {} ] ], "2d.filter.canvasFilterObject.componentTransfer.linear.tentative.html": [ - "c45f5586009150b862acd6b3398ca53350456baa", + "10f9931cc6430ef84b2314add5581c09136122b7", [ null, {} ] ], "2d.filter.canvasFilterObject.componentTransfer.table.tentative.html": [ - "b561cb6fd3f0a8d293941bffada44c70416d266a", + "7e743bf34f008d0b4579183d8f28ad2aa0624a81", [ null, {} ] ], "2d.filter.canvasFilterObject.convolveMatrix.exceptions.tentative.html": [ - "b85b742b3ebb2c26ed9b17b6683b6b510268ee84", + "b994a91842c031f05cd1650ee8078a62a0825416", [ null, {} @@ -515975,14 +516439,14 @@ ] ], "2d.filter.canvasFilterObject.tentative.html": [ - "3a32eb6a55a2487449b982cb0dda11815e782218", + "a4625db01977fe277d3b0543dd80146b7ce47f55", [ null, {} ] ], "2d.filter.canvasFilterObject.turbulence.inputTypes.tentative.html": [ - "1f9d978ac8c29f8e51075cd119240d3921411b6b", + "64f909a7fdb25ee209ba4aeb6fd3830b5b6a7e48", [ null, {} @@ -525058,112 +525522,112 @@ }, "filters": { "2d.filter.canvasFilterObject.blur.exceptions.tentative.html": [ - "6ce6fb633f8c08e0b168a810350d862b14838b8f", + "f5332780c82b41dab06cb18d1d78990724426a50", [ null, {} ] ], "2d.filter.canvasFilterObject.blur.exceptions.tentative.worker.js": [ - "a44868f585c67ccee883b06bc6681b4c88bb4f7f", + "61f10308801caa7e3c276aa4db4b7cf6158e4d84", [ "html/canvas/offscreen/filters/2d.filter.canvasFilterObject.blur.exceptions.tentative.worker.html", {} ] ], "2d.filter.canvasFilterObject.colorMatrix.tentative.html": [ - "3eda41776c0ef289c23991bc9e88219a974829fd", + "f3dd3037bb7ab7b9e82fbab0590d8bfe508f8f46", [ null, {} ] ], "2d.filter.canvasFilterObject.colorMatrix.tentative.worker.js": [ - "105f312b9ceae0243b27234934477568493861df", + "19d57b61e53242a4c0144b87c060dfad708bfada", [ "html/canvas/offscreen/filters/2d.filter.canvasFilterObject.colorMatrix.tentative.worker.html", {} ] ], "2d.filter.canvasFilterObject.componentTransfer.discrete.tentative.html": [ - "7cb8b0dd143602bb2fb6893b63b6bebaf23a3bf0", + "dd6fc9ee5ff1694e6a19b87a83c24ef2d32e2dbd", [ null, {} ] ], "2d.filter.canvasFilterObject.componentTransfer.discrete.tentative.worker.js": [ - "f1274f14253c559ccfe9939abbc87c62884ff7c0", + "79a5cd2475ca911c061b898881d2474ee556531d", [ "html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.discrete.tentative.worker.html", {} ] ], "2d.filter.canvasFilterObject.componentTransfer.gamma.tentative.html": [ - "388fdca6f9d8db49680b506c918a163935d25908", + "f2a9fcfd49a4a66f0a1283f41a8a5346e0a4e769", [ null, {} ] ], "2d.filter.canvasFilterObject.componentTransfer.gamma.tentative.worker.js": [ - "14bf50f89dde725304dbcbdb9f8ea65447c373ca", + "a36fa19a5efad6948108a3cfd7c337daca1f5f76", [ "html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.gamma.tentative.worker.html", {} ] ], "2d.filter.canvasFilterObject.componentTransfer.identity.tentative.html": [ - "44eb7184956bd4b535d8c097237a90e358d8e1b2", + "33aae01eb056f9c37f4254b1aa4ad16c49aa267a", [ null, {} ] ], "2d.filter.canvasFilterObject.componentTransfer.identity.tentative.worker.js": [ - "ae749673f4362ea4aade37ffdc55986e77735a6c", + "7236c7087a174372a271e9c043d149faefbf6d42", [ "html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.identity.tentative.worker.html", {} ] ], "2d.filter.canvasFilterObject.componentTransfer.linear.tentative.html": [ - "d24a9e8608d1b2c2d404579b9e122522c7965e2e", + "23731a1286ce723473b2268dc1d1530d6af028dc", [ null, {} ] ], "2d.filter.canvasFilterObject.componentTransfer.linear.tentative.worker.js": [ - "5117d4a1b3b0d683146a9ee39eb1b30966cb72b7", + "9a4499d4d6b70114fd9225172a04cf5ac9ef8c4e", [ "html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.linear.tentative.worker.html", {} ] ], "2d.filter.canvasFilterObject.componentTransfer.table.tentative.html": [ - "a704557cc54551a70dc8087130ae270ba79ad558", + "c11e6adb9109972b1c0d2a6da7e847e2aeecc047", [ null, {} ] ], "2d.filter.canvasFilterObject.componentTransfer.table.tentative.worker.js": [ - "e2463eb9e7663b0409b6ea661d333d500e08a9e1", + "8ff791d3bb986733308320a158c3a8f3d17b9f08", [ "html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.table.tentative.worker.html", {} ] ], "2d.filter.canvasFilterObject.convolveMatrix.exceptions.tentative.html": [ - "0a6bddc56d7b339dad16db40531d8832d08c3624", + "c4b6df8e0db0bec1dcff080436c0daba92ccdadc", [ null, {} ] ], "2d.filter.canvasFilterObject.convolveMatrix.exceptions.tentative.worker.js": [ - "bce4c0be158aafce773333805f2e8b0ce7644873", + "f7e616e7a63fc32dc6da14acec08c4255f24ee3c", [ "html/canvas/offscreen/filters/2d.filter.canvasFilterObject.convolveMatrix.exceptions.tentative.worker.html", {} @@ -525184,28 +525648,28 @@ ] ], "2d.filter.canvasFilterObject.tentative.html": [ - "75d369cad2f9e0c3a7674537badd49fdfa79c74e", + "4d80dddf0071467eabde32c85d0dd5b30da2dcbb", [ null, {} ] ], "2d.filter.canvasFilterObject.tentative.worker.js": [ - "30772a39d102169cc5d04b79fe83c037f66085a4", + "48c4a0448d95e596c7d46e5c38a05f33ab29efd9", [ "html/canvas/offscreen/filters/2d.filter.canvasFilterObject.tentative.worker.html", {} ] ], "2d.filter.canvasFilterObject.turbulence.inputTypes.tentative.html": [ - "610dca9feaf59afd413aec78f291ba14607a53d6", + "2ed61e66d0335be76c33a71a30cfb18d5304bf03", [ null, {} ] ], "2d.filter.canvasFilterObject.turbulence.inputTypes.tentative.worker.js": [ - "76673fab9a7e6a16c4340021961c8180c6253ca4", + "1bed65ad156a78121ad52d6448dc7107995986e1", [ "html/canvas/offscreen/filters/2d.filter.canvasFilterObject.turbulence.inputTypes.tentative.worker.html", {} @@ -540308,8 +540772,15 @@ ] ] }, - "http-equiv-and-name.html": [ - "144217df3848851445f78d4e1b725dc1d479584e", + "http-equiv-and-name-1.html": [ + "ac82e3396d6258e2fea86dbac65a12b12304b751", + [ + null, + {} + ] + ], + "http-equiv-and-name-2.html": [ + "b73013a341b9774dc3ad1f3154df47e365a816be", [ null, {} @@ -568428,7 +568899,7 @@ ], "cross-window": { "click-crossdocument-crossorigin-sameorigindomain.sub.html": [ - "676672a230f15030eee9b10a0380ed3b3006b840", + "004e1a75e3d8ca38c5634424a4816c577e705479", [ null, {} @@ -568442,35 +568913,35 @@ ] ], "click-crossdocument-sameorigin.html": [ - "41c3ca71eef1d5eaafb1eff0bbe5eb70799a1ce2", + "683875d0062e3b0d56428c0827822bf75b10e68e", [ null, {} ] ], "click-samedocument-crossorigin-sameorigindomain.sub.html": [ - "a467ecf9d73d88af6537a234125e4ef15dd05d00", + "60d1653a3ab17aa5a392e97bdc91734024c16a51", [ null, {} ] ], "click-samedocument-crossorigin.html": [ - "b9fa97f6d526ae395402dac8b8d6c59988a404b0", + "ee01e7f1f2d8d31f2596fcf3ecb77c22004c7201", [ null, {} ] ], "click-samedocument-sameorigin.html": [ - "566bea3dc7e9b58baff552e219f85be75a6fdb08", + "eaa7b52345722801885f1d5ef8f9f51002375d2d", [ null, {} ] ], "location-crossdocument-crossorigin-sameorigindomain.sub.html": [ - "77a5873c0838f8452dafc4bdca785944dbd92ef0", + "cee7d95b9ecf678982eba240d96e6787647beaaf", [ null, {} @@ -568484,35 +568955,35 @@ ] ], "location-crossdocument-sameorigin.html": [ - "41ac1b037506f12a86dec1ab10df1d917bc1ba72", + "d0dad46b72ab9476c15860b8d0249bdd23c5421a", [ null, {} ] ], "location-samedocument-crossorigin-sameorigindomain.sub.html": [ - "1eda74e982831088f7b70d0175fb954583044db8", + "156d1cb3cfd1f3f469c68de21b0aebc9e9b94615", [ null, {} ] ], "location-samedocument-crossorigin.html": [ - "5679236a7ddca9b6ac7e3627652ba4faaa29fee4", + "6d73262dea0153a61a7f146105cbbcbbc4a4280f", [ null, {} ] ], "location-samedocument-sameorigin.html": [ - "a7e4181c3a19f0449e0fce7457c664d94edcd932", + "6516a602395065f6447be7e4e0c52c99559473d8", [ null, {} ] ], "open-crossdocument-crossorigin-sameorigindomain.sub.html": [ - "ea9ea479c34733c46f8312a72dd6ca2900c5680c", + "1c411d986682ed7aeb06aa79f481815795677fa6", [ null, {} @@ -568526,35 +568997,35 @@ ] ], "open-crossdocument-sameorigin.html": [ - "478483e238d7271e65af53c4a29b861b11d44efd", + "c91689341e85e8a1053c311580e622449ab77be4", [ null, {} ] ], "open-samedocument-crossorigin-sameorigindomain.sub.html": [ - "324adb32a45922d605ad2df350188ee05200171c", + "74a6cae2461835429a0181538e529ae05a12f0e9", [ null, {} ] ], "open-samedocument-crossorigin.html": [ - "23dceb04204841a66b28bc55001742f091e1117a", + "9b31744ba384e12cd031c0ccba68e13936dab5b6", [ null, {} ] ], "open-samedocument-sameorigin.html": [ - "9ca853180343f69cee1896837f77c21b485fa08b", + "c357072e09d1d00832616fba9886b4f8eac63c02", [ null, {} ] ], "submit-crossdocument-crossorigin-sameorigindomain.sub.html": [ - "f611034617401e8497567c825d27ef245d75bf01", + "ffdaac7ccdd6428ba03fb00600a79bd3e15a9e86", [ null, {} @@ -568568,28 +569039,28 @@ ] ], "submit-crossdocument-sameorigin.html": [ - "05347335a192a65306b652ff7c680dc7279e15d8", + "b54a5a440b05cbd54c2a9dce2bcd73bc2a635e29", [ null, {} ] ], "submit-samedocument-crossorigin-sameorigindomain.sub.html": [ - "9e64a0124daf5f549daf12f5c13a5793da254584", + "e9ab17243e5836f25542669b5973639f7787c09d", [ null, {} ] ], "submit-samedocument-crossorigin.html": [ - "e53a1f93e7a7a063c050c1419760d9a1fed8f1e8", + "69b12f279594387134c9082258b94a82d6b5dba3", [ null, {} ] ], "submit-samedocument-sameorigin.html": [ - "43aa3226fcd6fc99d86eab400fbdea75d2d2a6c0", + "8a0e1f1fb69635ba8595c4ed5f4ec3c85d2e642e", [ null, {} @@ -568758,14 +569229,14 @@ ] ], "navigate-anchor-cross-origin.html": [ - "d8f2e383124be56d493d6d67b47d9664f62f2a94", + "ee0992485078fd85d1c2099e7c74440407c111b4", [ null, {} ] ], "navigate-anchor-download-userInitiated.html": [ - "90a612b75886963b2bf706fcfb934637d9a903ec", + "b9506984dad8d8cd65b6d80c084922c59ed319ac", [ null, { @@ -568774,28 +569245,28 @@ ] ], "navigate-anchor-download.html": [ - "c5ca306b7908d518a7e105d5dcf39e312a07a6bc", + "05fb0ecf2fe6f60577fed75e2ca6fc57677cac0f", [ null, {} ] ], "navigate-anchor-fragment.html": [ - "b7706b7debea3cdf5cc943f96ec4a099c4c02acb", + "51221ebcad381b04600835bbc765e82dafa9d4b2", [ null, {} ] ], "navigate-anchor-same-origin-cross-document.html": [ - "b8e925a4dbacd54399f2ad96eb21f8b6481caf8c", + "68f5bf0627c123f1fe954d109924c2c1a5ab7170", [ null, {} ] ], "navigate-anchor-userInitiated.html": [ - "b746bbe3f028c25c4038d9e1b4f748f7b93289d7", + "39192c915132485a512a353d7f6e2c5693cf4cdf", [ null, { @@ -568804,35 +569275,49 @@ ] ], "navigate-anchor-with-target.html": [ - "c2053a37b09a45610dbbb43fdd0780a24614b4e8", + "6407b963beb7cd8a321574faab8b942e887959ae", + [ + null, + {} + ] + ], + "navigate-destination-after-detach.html": [ + "1dcb6cac4377ab79551ec51382308d6d669b5670", + [ + null, + {} + ] + ], + "navigate-destination-dynamic-index.html": [ + "2e0f1ea49730fcdcf07f483188b01d5350540069", [ null, {} ] ], "navigate-destination-getState-back-forward.html": [ - "c118aa7a1f3867990beed09786cc6778858f5a2f", + "c8b1043aba6f5ee4605ee461b4f0ab1bc4136077", [ null, {} ] ], "navigate-destination-getState-navigate.html": [ - "9c34c5753a1197631cd1770284dfb012bb0192f6", + "5dac40de566e9e42a5e2f08ec0a7a2882f318b51", [ null, {} ] ], "navigate-destination-getState-reload.html": [ - "b3afb72482c8fd545a044e4923c8b0820c7a9bf9", + "a180e086a94b084bb8df4a6a315444551ea57158", [ null, {} ] ], "navigate-form-get.html": [ - "69a49eb08a67711178dd8ef1a9f35c3c807d55d4", + "87a102ddc0598f9903c630c5c1add3075dbbdcdb", [ null, {} @@ -568853,7 +569338,7 @@ ] ], "navigate-form-userInitiated.html": [ - "454f0773962f326f1ae66ee4d5a470fc1abf50ff", + "40c5905447c59fc0ed1d873d3248c39a49163db0", [ null, { @@ -568862,14 +569347,14 @@ ] ], "navigate-form-with-target.html": [ - "b23ab3a70ccb2bb724cde932bbd3fc91f711177a", + "f6fe05c938f2fb88289c3a95bfab2f809d11177b", [ null, {} ] ], "navigate-form.html": [ - "b537a9b58f090c8f7ce76bb06433ae5a9c8b93a6", + "c57d72c3deb0f7714bf78630afe6a39d87569f01", [ null, {} @@ -568904,42 +569389,42 @@ ] ], "navigate-history-go-0.html": [ - "96d98cf44c8261a777d37b31785137897f3429c8", + "b1f41425b62f833474b85dd3049d1c33ea3095d9", [ null, {} ] ], "navigate-history-pushState.html": [ - "2f8c81c7090cb9441210936f1d63a016cca29ccc", + "266309a79e13a4e5239853316089c19a729a5ba2", [ null, {} ] ], "navigate-history-replaceState.html": [ - "d8417fbfd308ae9a7120b6a8040d401b5384084a", + "ea6d3df455dc74fb27e964a4f41eabdf611ab5f5", [ null, {} ] ], "navigate-iframe-location.html": [ - "059b995011836619c46a0d8c95bef56c82cceaec", + "25d51476f3ffeea34583254a9e8162c507915408", [ null, {} ] ], "navigate-location.html": [ - "c5aa0be97a47be497f019c8a9cd6fc03db022bd3", + "a4d0c60776dc0eb21996ffa8abb92e884995b9dd", [ null, {} ] ], "navigate-meta-refresh.html": [ - "1f8ed306851fd469e7ebbdeac3695b16ab47421e", + "9fa59b29f240014e86e7a379cfd3b56a490dc853", [ null, {} @@ -568967,7 +569452,7 @@ ] ], "navigate-navigation-navigate.html": [ - "76f98c72361060fa5fbc842fecdfa00c737cd56c", + "ffc8ea867f71f3c23290813a1e90065341f68c81", [ null, {} @@ -568981,21 +569466,21 @@ ] ], "navigate-to-srcdoc.html": [ - "26ad135b6ad0b7718c97f2914d60dfc2bbb9dea0", + "8bbb66a31fdfee846444dc2c2e338fb7669bfff7", [ null, {} ] ], "navigate-window-open-self.html": [ - "274c8bc4d5762fd47314b4534a79145da31b5f8a", + "a6e443fd5a115edd7dea6f5cd40abfb3386c937c", [ null, {} ] ], "navigate-window-open.html": [ - "afc998271f6e96f206ecea45368a275f44400b79", + "1fe2402bc91e524371cb0f998e6477000ad96357", [ null, {} @@ -593510,7 +593995,7 @@ "scroll-animations": { "css": { "animation-duration-auto.tentative.html": [ - "f44a682890d8e25fa5f92e06591b7e22b00a26a3", + "375489c26a4f49aa3f8bb1f3b4f24d19654ab549", [ null, {} @@ -593629,7 +594114,7 @@ ] ], "progress-based-animation-timeline.html": [ - "2e910cbe51efbf4bdcd73eca85c9bed1c39d09e6", + "3f1aeed0ae9bdd6f19550cab37f92f1437619634", [ null, {} @@ -593664,7 +594149,7 @@ ] ], "scroll-timeline-axis-writing-mode.html": [ - "37b4dfdf549e52943c5e8a35683cc6a998442db4", + "958ce4964e844bcf8d94699b4a8bbc5e29df8e2f", [ null, {} @@ -593790,7 +594275,7 @@ ] ], "timeline-offset-keyframes-hidden-subject.html": [ - "047acfed33f36adb3afca0655c99e75a707f3976", + "389c8baca3ad035df1de6767ac9abc6265756808", [ null, {} @@ -593804,7 +594289,7 @@ ] ], "timeline-range-name-offset-in-keyframes.tentative.html": [ - "a0d1bd92f0907f26b98843cac21d306a0848949c", + "7bae49c2e97dcc8c22b3f071256fdfd9cca699c2", [ null, {} @@ -593818,7 +594303,7 @@ ] ], "view-timeline-animation.html": [ - "b816bb689732b3be59df48c0653ed892dc70cdd4", + "73189b85917314e497cf0cb70d2e22986c230997", [ null, {} @@ -593860,7 +594345,7 @@ ] ], "view-timeline-inset-animation.html": [ - "a95086b62bf338ea338345990a11735f7f594e23", + "a7e807c2e819dd0678178171816af5569b3aadff", [ null, {} @@ -593881,14 +594366,14 @@ ] ], "view-timeline-keyframe-boundary-interpolation.html": [ - "1dc766d961c5dd513e3d0912d01468279044648e", + "04eb648949057b6452d96b2f4ba55a1cb9f467e2", [ null, {} ] ], "view-timeline-lookup.html": [ - "c1797c7ba1c37177f413ed1396ddb3e8b61660dc", + "b8a5b0008be1a0b9285fd52b3ecd666f39ab6a3e", [ null, {} @@ -600325,7 +600810,7 @@ ] ], "html-collection.html": [ - "2f3d49ec267b83c64d37641ce50b22c9b26aa0df", + "1ce2cf34401dff1bb63b1955d93b3c79ab7886ea", [ null, {} @@ -601099,6 +601584,13 @@ ] }, "shared-storage": { + "insecure-context.tentative.http.html": [ + "7ddf02f861aaba92db75ac47c85dfcab4a7c8861", + [ + null, + {} + ] + ], "select-url-permissions-policy-default.tentative.https.sub.html": [ "67911388ec0f41790d8c7c678256f153765a6294", [ @@ -633282,7 +633774,7 @@ ] ], "RTCRtpTransceiver-headerExtensionControl.html": [ - "b6dc7da5d4076d113419888e814e445e9dd2c40a", + "79eba02727bb35b745cee0a3b6246e37fb216e06", [ null, {} @@ -646042,7 +646534,7 @@ ] ], "datagrams.https.any.js": [ - "b96b36fc369f1dbb929ce0f44dcf7ae18ffc8e22", + "dc7133bb867e203ee651d887b64e48782dc3c58b", [ "webtransport/datagrams.https.any.html", { @@ -646388,7 +646880,7 @@ ] ], "streams-echo.https.any.js": [ - "32781419ebf7bd83d376419ca07e2829196ed4db", + "18ebe123a417a919530dcbf31a441b141848cbd4", [ "webtransport/streams-echo.https.any.html", { @@ -670247,7 +670739,7 @@ ] ], "key_events.py": [ - "8dbe024d18396f010b2dcac7281b8436b5b69c65", + "9f912684c76f4e6b7347c8a08a8b9e9559d6d6bd", [ null, { @@ -670455,7 +670947,7 @@ ] ], "sequence.py": [ - "75143d85ca600b3e3a2d7d5ac3679a26b7d7bf5a", + "24ca16c86043ac091b5173fcc3e8571a50107eca", [ null, {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-cascade/import-conditions-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-cascade/import-conditions-expected.txt index e1615689..cdcdc59 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-cascade/import-conditions-expected.txt +++ b/third_party/blink/web_tests/external/wpt/css/css-cascade/import-conditions-expected.txt
@@ -1,8 +1,24 @@ This is a testharness.js-based test. FAIL supports(display:block) is a valid import condition assert_equals: expected "rgb(0, 128, 0)" but got "rgb(255, 0, 0)" +FAIL supports((display:flex)) is a valid import condition assert_equals: expected "rgb(0, 128, 0)" but got "rgb(255, 0, 0)" +FAIL supports((display:block) and (display:flex)) is a valid import condition assert_equals: expected "rgb(0, 128, 0)" but got "rgb(255, 0, 0)" +PASS supports((display:block) and (foo:bar)) is not a valid import condition +FAIL supports((display:block) or (display:flex)) is a valid import condition assert_equals: expected "rgb(0, 128, 0)" but got "rgb(255, 0, 0)" +FAIL supports((display:block) or (foo:bar)) is a valid import condition assert_equals: expected "rgb(0, 128, 0)" but got "rgb(255, 0, 0)" +PASS supports(not (display: flex)) is not a valid import condition +FAIL supports(display: block !important) is a valid import condition assert_equals: expected "rgb(0, 128, 0)" but got "rgb(255, 0, 0)" PASS supports(foo:bar) is not a valid import condition FAIL supports(display:block) (width >= 0px) is a valid import condition assert_equals: expected "rgb(0, 128, 0)" but got "rgb(255, 0, 0)" PASS (width >= 0px) supports(foo:bar) is not a valid import condition PASS (width >= 0px) supports(display:block) is not a valid import condition +FAIL supports(selector(a)) is a valid import condition assert_equals: expected "rgb(0, 128, 0)" but got "rgb(255, 0, 0)" +FAIL supports(selector(p a)) is a valid import condition assert_equals: expected "rgb(0, 128, 0)" but got "rgb(255, 0, 0)" +FAIL supports(selector(p > a)) is a valid import condition assert_equals: expected "rgb(0, 128, 0)" but got "rgb(255, 0, 0)" +FAIL supports(selector(p + a)) is a valid import condition assert_equals: expected "rgb(0, 128, 0)" but got "rgb(255, 0, 0)" +FAIL supports(font-tech(color-COLRv1)) is a valid import condition assert_equals: expected "rgb(0, 128, 0)" but got "rgb(255, 0, 0)" +PASS supports(font-tech(invalid)) is not a valid import condition +FAIL supports(font-format(opentype)) is a valid import condition assert_equals: expected "rgb(0, 128, 0)" but got "rgb(255, 0, 0)" +FAIL supports(font-format(woff)) is a valid import condition assert_equals: expected "rgb(0, 128, 0)" but got "rgb(255, 0, 0)" +PASS supports(font-format(invalid)) is not a valid import condition Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/css/css-cascade/import-conditions.html b/third_party/blink/web_tests/external/wpt/css/css-cascade/import-conditions.html index 0bb0975..e5e1c685 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-cascade/import-conditions.html +++ b/third_party/blink/web_tests/external/wpt/css/css-cascade/import-conditions.html
@@ -14,6 +14,34 @@ matches: true }, { + importCondition: "supports((display:flex))", + matches: true + }, + { + importCondition: "supports((display:block) and (display:flex))", + matches: true + }, + { + importCondition: "supports((display:block) and (foo:bar))", + matches: false + }, + { + importCondition: "supports((display:block) or (display:flex))", + matches: true + }, + { + importCondition: "supports((display:block) or (foo:bar))", + matches: true + }, + { + importCondition: "supports(not (display: flex))", + matches: false + }, + { + importCondition: "supports(display: block !important)", + matches: true + }, + { importCondition: "supports(foo:bar)", matches: false }, @@ -28,7 +56,49 @@ { importCondition: "(width >= 0px) supports(display:block)", matches: false - } + }, + + // selector() + { + importCondition: "supports(selector(a))", + matches: true + }, + { + importCondition: "supports(selector(p a))", + matches: true + }, + { + importCondition: "supports(selector(p > a))", + matches: true + }, + { + importCondition: "supports(selector(p + a))", + matches: true + }, + + // font-tech() + { + importCondition: "supports(font-tech(color-COLRv1))", + matches: true + }, + { + importCondition: "supports(font-tech(invalid))", + matches: false + }, + + // font-format() + { + importCondition: "supports(font-format(opentype))", + matches: true + }, + { + importCondition: "supports(font-format(woff))", + matches: true + }, + { + importCondition: "supports(font-format(invalid))", + matches: false + }, ]; let target = document.getElementById("target"); for (let testCase of testCases) {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-cascade/import-conditions.html.ini b/third_party/blink/web_tests/external/wpt/css/css-cascade/import-conditions.html.ini index f849a37..5fe16a5 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-cascade/import-conditions.html.ini +++ b/third_party/blink/web_tests/external/wpt/css/css-cascade/import-conditions.html.ini
@@ -1,6 +1,42 @@ [import-conditions.html] + [supports((display:block) and (display:flex)) is a valid import condition] + expected: FAIL + + [supports((display:block) or (display:flex)) is a valid import condition] + expected: FAIL + + [supports((display:block) or (foo:bar)) is a valid import condition] + expected: FAIL + + [supports((display:flex)) is a valid import condition] + expected: FAIL + + [supports(display: block !important) is a valid import condition] + expected: FAIL + [supports(display:block) (width >= 0px) is a valid import condition] expected: FAIL [supports(display:block) is a valid import condition] expected: FAIL + + [supports(font-format(opentype)) is a valid import condition] + expected: FAIL + + [supports(font-format(woff)) is a valid import condition] + expected: FAIL + + [supports(font-tech(color-COLRv1)) is a valid import condition] + expected: FAIL + + [supports(selector(a)) is a valid import condition] + expected: FAIL + + [supports(selector(p + a)) is a valid import condition] + expected: FAIL + + [supports(selector(p > a)) is a valid import condition] + expected: FAIL + + [supports(selector(p a)) is a valid import condition] + expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-cascade/parsing/supports-import-parsing.html b/third_party/blink/web_tests/external/wpt/css/css-cascade/parsing/supports-import-parsing.html new file mode 100644 index 0000000..58e1f7c --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-cascade/parsing/supports-import-parsing.html
@@ -0,0 +1,74 @@ +<!doctype html> +<meta charset="utf-8"> +<title>@import rule with supports parsing / serialization</title> +<link rel="author" href="mailto:oj@oojmed.com"> +<link rel="help" href="https://drafts.csswg.org/css-cascade-4/#at-import"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + function setupSheet(rule) { + const style = document.createElement("style"); + document.head.append(style); + const {sheet} = style; + const {cssRules} = sheet; + + assert_equals(cssRules.length, 0, "Sheet should have no rules"); + sheet.insertRule(rule); + assert_equals(cssRules.length, 1, "Sheet should have 1 rule"); + + return {sheet, cssRules}; + } + + function test_valid_supports_import(rule, serialized) { + if (serialized === undefined) + serialized = rule; + + test(function() { + const {sheet, cssRules} = setupSheet(rule); + + const serialization = cssRules[0].cssText; + assert_equals(serialization, serialized, 'serialization should be canonical'); + + sheet.deleteRule(0); + assert_equals(cssRules.length, 0, 'Sheet should have no rule'); + sheet.insertRule(serialization); + assert_equals(cssRules.length, 1, 'Sheet should have 1 rule'); + + assert_equals(cssRules[0].cssText, serialization, 'serialization should round-trip'); + }, rule + ' should be a valid supports() import rule'); + } + + function test_invalid_supports_import(rule) { + test(function() { + const {sheet, cssRules} = setupSheet(rule); + + sheet.deleteRule(0); + assert_equals(cssRules.length, 0, 'Sheet should have no rule'); + }, rule + ' should still be a valid import rule with an invalid supports() declaration'); + } + + test_valid_supports_import('@import url("nonexist.css") supports();'); + test_valid_supports_import('@import url("nonexist.css") supports(display:block);'); + test_valid_supports_import('@import url("nonexist.css") supports((display:flex));'); + test_valid_supports_import('@import url("nonexist.css") supports(not (display: flex));'); + test_valid_supports_import('@import url("nonexist.css") supports((display: flex) and (display: block));'); + test_valid_supports_import('@import url("nonexist.css") supports((display: flex) or (display: block));'); + test_valid_supports_import('@import url("nonexist.css") supports((display: flex) or (foo: bar));'); + test_valid_supports_import('@import url("nonexist.css") supports(display: block !important);'); + + test_valid_supports_import('@import url("nonexist.css") supports(selector(a));'); + test_valid_supports_import('@import url("nonexist.css") supports(selector(p a));'); + test_valid_supports_import('@import url("nonexist.css") supports(selector(p > a));'); + test_valid_supports_import('@import url("nonexist.css") supports(selector(p + a));'); + + test_valid_supports_import('@import url("nonexist.css") supports(font-tech(color-colrv1));'); + test_valid_supports_import('@import url("nonexist.css") supports(font-format(opentype));'); + + test_valid_supports_import('@import url(nonexist.css) supports(display:block);', + '@import url("nonexist.css") supports(display:block);'); + + test_valid_supports_import('@import "nonexist.css" supports(display:block);', + '@import url("nonexist.css") supports(display:block);'); + + test_invalid_supports_import('@import url("nonexist.css") supports;'); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-flexbox/abspos/dynamic-align-self-001.html.ini b/third_party/blink/web_tests/external/wpt/css/css-flexbox/abspos/dynamic-align-self-001.html.ini new file mode 100644 index 0000000..14f97016 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-flexbox/abspos/dynamic-align-self-001.html.ini
@@ -0,0 +1,2 @@ +[dynamic-align-self-001.html] + expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-flexbox/justify-content-007.html.ini b/third_party/blink/web_tests/external/wpt/css/css-flexbox/justify-content-007.html.ini new file mode 100644 index 0000000..ea29b95 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-flexbox/justify-content-007.html.ini
@@ -0,0 +1,3 @@ +[justify-content-007.html] + [.flexitem + .flexitem 1] + expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/subgrid/baseline-001.html.ini b/third_party/blink/web_tests/external/wpt/css/css-grid/subgrid/baseline-001.html.ini index a20c5862..4c85dd9b 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-grid/subgrid/baseline-001.html.ini +++ b/third_party/blink/web_tests/external/wpt/css/css-grid/subgrid/baseline-001.html.ini
@@ -1,2 +1,4 @@ [baseline-001.html] - expected: CRASH + expected: + if (product == "content_shell") and (os == "win") and (port == "win10.20h2"): CRASH + FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/subgrid/subgrid-baseline-001.html.ini b/third_party/blink/web_tests/external/wpt/css/css-grid/subgrid/subgrid-baseline-001.html.ini index 714bf4b..c181d4a 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-grid/subgrid/subgrid-baseline-001.html.ini +++ b/third_party/blink/web_tests/external/wpt/css/css-grid/subgrid/subgrid-baseline-001.html.ini
@@ -1,2 +1,4 @@ [subgrid-baseline-001.html] - expected: CRASH + expected: + if (product == "content_shell") and (os == "win"): CRASH + FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/subgrid/subgrid-baseline-002.html.ini b/third_party/blink/web_tests/external/wpt/css/css-grid/subgrid/subgrid-baseline-002.html.ini index c8f5d5e..e93ab475 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-grid/subgrid/subgrid-baseline-002.html.ini +++ b/third_party/blink/web_tests/external/wpt/css/css-grid/subgrid/subgrid-baseline-002.html.ini
@@ -1,2 +1,2 @@ [subgrid-baseline-002.html] - expected: CRASH + expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-images/image-orientation/image-orientation-none-cross-origin.html b/third_party/blink/web_tests/external/wpt/css/css-images/image-orientation/image-orientation-none-cross-origin.html index e36c1295..ec139d4 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-images/image-orientation/image-orientation-none-cross-origin.html +++ b/third_party/blink/web_tests/external/wpt/css/css-images/image-orientation/image-orientation-none-cross-origin.html
@@ -22,7 +22,7 @@ <body> <p>The following images should not be identical.</p> <p>The image should not rotate respecting their EXIF orientation because - image-orientation: none is specified.</p> + image-orientation: none is specified and the request is same origin.</p> <div><img src="support/exif-orientation-3-lr.jpg"/></div> <p>This image should rotate respecting their EXIF orientation because @@ -30,16 +30,25 @@ <div><img id="corsImage" src="support/exif-orientation-3-lr.jpg"/></div> <p>The image should not rotate respecting their EXIF orientation because - image-orientation: none is specified.</p> + image-orientation: none is specified and the request is CORS anonymous.</p> + <div><img id="corsAnonymousImg" crossorigin="anonymous" src="support/exif-orientation-3-lr.jpg"/></div> + + <p>The image should not rotate respecting their EXIF orientation because + image-orientation: none is specified and the request is CORS + use-credentials.</p> + <div><img id="corsUseCredsImg" crossorigin="use-credentials" src="support/exif-orientation-3-lr.jpg"/></div> + + <p>The image should not rotate respecting their EXIF orientation because + image-orientation: none is specified and the image source is a blob.</p> <div><img id="blobImage"/></div> <p>The image should not rotate respecting their EXIF orientation because - image-orientation: none is specified.</p> + image-orientation: none is specified and the image source is a data url.</p> <div><img id="dataImage"/></div> </body> <script> const testImage = 'support/exif-orientation-3-lr.jpg'; - let sPendingImagesToLoad = 3; + let sPendingImagesToLoad = 5; function pendingImageLoaded() { if (!--sPendingImagesToLoad) { @@ -51,6 +60,19 @@ img.onload = pendingImageLoaded; img.src = img.src.replace(new URL(img.src).origin, get_host_info().HTTP_REMOTE_ORIGIN) + const corsAnonImg = document.getElementById('corsAnonymousImg') + corsAnonImg.onload = pendingImageLoaded; + corsAnonImg.src = corsAnonImg.src.replace(new URL(corsAnonImg.src).origin, + get_host_info().HTTP_REMOTE_ORIGIN) + + "?pipe=header(Access-Control-Allow-Origin,*)"; + + const corsUseCredsImg = document.getElementById('corsUseCredsImg') + corsUseCredsImg.onload = pendingImageLoaded; + corsUseCredsImg.src = corsUseCredsImg.src.replace(new URL(corsUseCredsImg.src).origin, + get_host_info().HTTP_REMOTE_ORIGIN) + + "?pipe=header(Access-Control-Allow-Credentials,true)" + + "|header(Access-Control-Allow-Origin," + location.origin + ")"; + const blobImg = document.getElementById('blobImage'); fetch(testImage).then((resp) => { return resp.blob();
diff --git a/third_party/blink/web_tests/external/wpt/css/css-images/image-orientation/reference/image-orientation-none-cross-origin-ref.html b/third_party/blink/web_tests/external/wpt/css/css-images/image-orientation/reference/image-orientation-none-cross-origin-ref.html index c4d72fc..a54aa38 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-images/image-orientation/reference/image-orientation-none-cross-origin-ref.html +++ b/third_party/blink/web_tests/external/wpt/css/css-images/image-orientation/reference/image-orientation-none-cross-origin-ref.html
@@ -19,7 +19,7 @@ <body> <p>The following images should not be identical.</p> <p>The image should not rotate respecting their EXIF orientation because - image-orientation: none is specified.</p> + image-orientation: none is specified and the request is same origin.</p> <div><img src="../support/exif-orientation-3-lr.jpg"/></div> <p>This image should rotate respecting their EXIF orientation because @@ -27,11 +27,20 @@ <div><img src="../support/exif-orientation-3-lr.jpg" style="image-orientation: from-image" /></div> <p>The image should not rotate respecting their EXIF orientation because - image-orientation: none is specified.</p> + image-orientation: none is specified and the request is CORS anonymous.</p> <div><img src="../support/exif-orientation-3-lr.jpg"/></div> <p>The image should not rotate respecting their EXIF orientation because - image-orientation: none is specified.</p> + image-orientation: none is specified and the request is CORS + use-credentials.</p> + <div><img src="../support/exif-orientation-3-lr.jpg"/></div> + + <p>The image should not rotate respecting their EXIF orientation because + image-orientation: none is specified and the image source is a blob.</p> + <div><img src="../support/exif-orientation-3-lr.jpg"/></div> + + <p>The image should not rotate respecting their EXIF orientation because + image-orientation: none is specified and the image source is a data url.</p> <div><img src="../support/exif-orientation-3-lr.jpg"/></div> </body> </html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transforms/preserve3d-and-flattening-z-order-004.html.ini b/third_party/blink/web_tests/external/wpt/css/css-transforms/preserve3d-and-flattening-z-order-004.html.ini new file mode 100644 index 0000000..9fdf89b --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-transforms/preserve3d-and-flattening-z-order-004.html.ini
@@ -0,0 +1,3 @@ +[preserve3d-and-flattening-z-order-004.html] + expected: + if (product == "content_shell") and (os == "mac") and (port == "mac13"): FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-button-border-image-width-001.html.ini b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-button-border-image-width-001.html.ini new file mode 100644 index 0000000..1844f81 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-button-border-image-width-001.html.ini
@@ -0,0 +1,3 @@ +[kind-of-widget-fallback-button-border-image-width-001.html] + expected: + if (product == "content_shell") and (os == "win") and (port == "win11"): FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-search-border-inline-start-width-001.html.ini b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-search-border-inline-start-width-001.html.ini index 4c3c8c35..c81ecad 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-search-border-inline-start-width-001.html.ini +++ b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-search-border-inline-start-width-001.html.ini
@@ -1,3 +1,4 @@ [kind-of-widget-fallback-input-search-border-inline-start-width-001.html] expected: + if (product == "content_shell") and (os == "mac") and (port == "mac13"): FAIL if (product == "content_shell") and (os == "linux"): FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-text-border-start-start-radius-001.html.ini b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-text-border-start-start-radius-001.html.ini new file mode 100644 index 0000000..7889dd6 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-text-border-start-start-radius-001.html.ini
@@ -0,0 +1,3 @@ +[kind-of-widget-fallback-input-text-border-start-start-radius-001.html] + expected: + if (product == "content_shell") and (os == "mac") and (port == "mac13"): FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filters-brightness.html.ini b/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filters-brightness.html.ini new file mode 100644 index 0000000..a95d0fb --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filters-brightness.html.ini
@@ -0,0 +1,3 @@ +[backdrop-filters-brightness.html] + expected: + if (product == "content_shell") and (os == "mac") and (port == "mac13-arm64"): FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/mediaqueries/scripting-print-noscript-ref.html b/third_party/blink/web_tests/external/wpt/css/mediaqueries/scripting-print-noscript-ref.html new file mode 100644 index 0000000..2dd7aff8 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/mediaqueries/scripting-print-noscript-ref.html
@@ -0,0 +1,4 @@ +<!DOCTYPE html> +<noscript> + Script is disabled +</noscript>
diff --git a/third_party/blink/web_tests/external/wpt/css/mediaqueries/scripting-print-noscript.html b/third_party/blink/web_tests/external/wpt/css/mediaqueries/scripting-print-noscript.html new file mode 100644 index 0000000..1d1af70 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/mediaqueries/scripting-print-noscript.html
@@ -0,0 +1,13 @@ +<!DOCTYPE html> +<link rel="help" href="https://drafts.csswg.org/mediaqueries/#scripting"> +<link rel="match" href="scripting-print-noscript-ref.html"> +<style> + @media (scripting) { + #noscript { + display: none; + } + } +</style> +<div id="noscript"> + Script is disabled +</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/mediaqueries/scripting-print-noscript.html.ini b/third_party/blink/web_tests/external/wpt/css/mediaqueries/scripting-print-noscript.html.ini new file mode 100644 index 0000000..f8256a3 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/mediaqueries/scripting-print-noscript.html.ini
@@ -0,0 +1,2 @@ +[scripting-print-noscript.html] + expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/mediaqueries/scripting-print-script-ref.html b/third_party/blink/web_tests/external/wpt/css/mediaqueries/scripting-print-script-ref.html new file mode 100644 index 0000000..d2da3f84 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/mediaqueries/scripting-print-script-ref.html
@@ -0,0 +1,4 @@ +<!DOCTYPE html> +<div> + Script is enabled +</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/mediaqueries/scripting-print-script.html b/third_party/blink/web_tests/external/wpt/css/mediaqueries/scripting-print-script.html new file mode 100644 index 0000000..e80dba4d --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/mediaqueries/scripting-print-script.html
@@ -0,0 +1,17 @@ +<!DOCTYPE html> +<link rel="help" href="https://drafts.csswg.org/mediaqueries/#scripting"> +<link rel="match" href="scripting-print-script-ref.html"> +<style> + #script { + display: none; + } + + @media (scripting) { + #script { + display: block; + } + } +</style> +<div id="script"> + Script is enabled +</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/mediaqueries/scripting-print-script.html.ini b/third_party/blink/web_tests/external/wpt/css/mediaqueries/scripting-print-script.html.ini new file mode 100644 index 0000000..2143b97f --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/mediaqueries/scripting-print-script.html.ini
@@ -0,0 +1,2 @@ +[scripting-print-script.html] + expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/mediaqueries/scripting.html b/third_party/blink/web_tests/external/wpt/css/mediaqueries/scripting.html new file mode 100644 index 0000000..de047cb --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/mediaqueries/scripting.html
@@ -0,0 +1,26 @@ +<!DOCTYPE html> +<link rel="help" href="https://drafts.csswg.org/mediaqueries-5/#scripting"> +<script type="text/javascript" src="/resources/testharness.js"></script> +<script type="text/javascript" src="/resources/testharnessreport.js"></script> +<script type="text/javascript" src="resources/matchmedia-utils.js"></script> + +<script> +query_should_be_known("(scripting)"); +query_should_be_known("(scripting: enabled)"); +query_should_be_known("(scripting: initial-only)"); +query_should_be_known("(scripting: none)"); + +query_should_be_unknown("(scripting: 0)"); +query_should_be_unknown("(scripting: 10px)"); +query_should_be_unknown("(scripting: invalid)"); + +test(() => { + let match_enabled = window.matchMedia("(scripting: enabled)"); + assert_true(match_enabled.matches); +}, "Check that scripting currently matches 'enabled'"); + +test(() => { + let booleanContext = window.matchMedia("(scripting)"); + assert_true(booleanContext.matches); +}, "Check that scripting currently evaluates to true in the boolean context"); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/mediaqueries/scripting.html.ini b/third_party/blink/web_tests/external/wpt/css/mediaqueries/scripting.html.ini new file mode 100644 index 0000000..cfe3783 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/mediaqueries/scripting.html.ini
@@ -0,0 +1,18 @@ +[scripting.html] + [Check that scripting currently evaluates to true in the boolean context] + expected: FAIL + + [Check that scripting currently matches 'enabled'] + expected: FAIL + + [Should be known: '(scripting)'] + expected: FAIL + + [Should be known: '(scripting: enabled)'] + expected: FAIL + + [Should be known: '(scripting: initial-only)'] + expected: FAIL + + [Should be known: '(scripting: none)'] + expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/i18n/css3-selectors-lang-014.html b/third_party/blink/web_tests/external/wpt/css/selectors/i18n/css3-selectors-lang-014.html index 5e68d50..411d50d 100644 --- a/third_party/blink/web_tests/external/wpt/css/selectors/i18n/css3-selectors-lang-014.html +++ b/third_party/blink/web_tests/external/wpt/css/selectors/i18n/css3-selectors-lang-014.html
@@ -28,8 +28,8 @@ <script> test(function() { assert_equals(document.getElementById('colonlangcontroltest').offsetWidth, 0) -assert_equals(document.getElementById('box').offsetWidth, 50); -}, "A :lang value with language and region subtags will NOT match a lang attribute value with language, script and region subtags."); +assert_in_array(document.getElementById('box').offsetWidth, [50, 100]); +}, "A :lang value with language and region subtags will match a lang attribute value with language, script and region subtags under CSS Selectors 4, but not Selectors 3."); </script> <div id='log'></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-000-ref.html b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-000-ref.html new file mode 100644 index 0000000..466e9f4 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-000-ref.html
@@ -0,0 +1,11 @@ +<!DOCTYPE html> +<html lang="en-US"> +<meta charset="utf-8"> +<title>CSS Selectors 4 - :lang matching reference</title> +<link rel="author" title="Jonathan Kew" href="mailto:jkew@mozilla.com"> + +<style> +div.test { color: green; } +</style> + +<div class="test">This should be green</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-000.html b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-000.html new file mode 100644 index 0000000..1d66beb --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-000.html
@@ -0,0 +1,13 @@ +<!DOCTYPE html> +<html lang="en-US"> +<meta charset="utf-8"> +<title>CSS Selectors 4 - :lang matching</title> +<link rel="author" title="Jonathan Kew" href="mailto:jkew@mozilla.com"> +<link rel="help" href="https://drafts.csswg.org/selectors-4/#the-lang-pseudo"> +<link rel="match" href="lang-000-ref.html"> + +<style> +:lang(en-US) { color: green; } +</style> + +<div class="test">This should be green</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-001.html b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-001.html new file mode 100644 index 0000000..908643fc --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-001.html
@@ -0,0 +1,14 @@ +<!DOCTYPE html> +<html lang="en-US"> +<meta charset="utf-8"> +<title>CSS Selectors 4 - :lang matching</title> +<link rel="author" title="Jonathan Kew" href="mailto:jkew@mozilla.com"> +<link rel="help" href="https://drafts.csswg.org/selectors-4/#the-lang-pseudo"> +<link rel="match" href="lang-000-ref.html"> + +<style> +div.test { color: red; } +:lang(fr) { color: green; } +</style> + +<div class="test"><span lang="fr">This should be green</span></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-002.html b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-002.html new file mode 100644 index 0000000..0be426c6 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-002.html
@@ -0,0 +1,14 @@ +<!DOCTYPE html> +<html lang="en-US"> +<meta charset="utf-8"> +<title>CSS Selectors 4 - :lang matching</title> +<link rel="author" title="Jonathan Kew" href="mailto:jkew@mozilla.com"> +<link rel="help" href="https://drafts.csswg.org/selectors-4/#the-lang-pseudo"> +<link rel="match" href="lang-000-ref.html"> + +<style> +div.test { color: red; } +:lang("FR") { color: green; } +</style> + +<div class="test"><span lang="fr">This should be green</span></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-002.html.ini b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-002.html.ini new file mode 100644 index 0000000..de628205 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-002.html.ini
@@ -0,0 +1,2 @@ +[lang-002.html] + expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-003.html b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-003.html new file mode 100644 index 0000000..a3e5340 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-003.html
@@ -0,0 +1,14 @@ +<!DOCTYPE html> +<html lang="en-US"> +<meta charset="utf-8"> +<title>CSS Selectors 4 - :lang matching</title> +<link rel="author" title="Jonathan Kew" href="mailto:jkew@mozilla.com"> +<link rel="help" href="https://drafts.csswg.org/selectors-4/#the-lang-pseudo"> +<link rel="match" href="lang-000-ref.html"> + +<style> +div.test { color: red; } +:lang("Fr") { color: green; } +</style> + +<div class="test"><span lang="fR">This should be green</span></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-003.html.ini b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-003.html.ini new file mode 100644 index 0000000..10dbf11 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-003.html.ini
@@ -0,0 +1,2 @@ +[lang-003.html] + expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-004.html b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-004.html new file mode 100644 index 0000000..d592997 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-004.html
@@ -0,0 +1,14 @@ +<!DOCTYPE html> +<html lang="en-US"> +<meta charset="utf-8"> +<title>CSS Selectors 4 - :lang matching</title> +<link rel="author" title="Jonathan Kew" href="mailto:jkew@mozilla.com"> +<link rel="help" href="https://drafts.csswg.org/selectors-4/#the-lang-pseudo"> +<link rel="match" href="lang-000-ref.html"> + +<style> +div.test { color: red; } +:lang("fr") { color: green; } +</style> + +<div class="test"><span lang="fr-CH">This should be green</span></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-004.html.ini b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-004.html.ini new file mode 100644 index 0000000..0d17f9d --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-004.html.ini
@@ -0,0 +1,2 @@ +[lang-004.html] + expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-005.html b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-005.html new file mode 100644 index 0000000..816dfc9b --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-005.html
@@ -0,0 +1,14 @@ +<!DOCTYPE html> +<html lang="en-US"> +<meta charset="utf-8"> +<title>CSS Selectors 4 - :lang matching</title> +<link rel="author" title="Jonathan Kew" href="mailto:jkew@mozilla.com"> +<link rel="help" href="https://drafts.csswg.org/selectors-4/#the-lang-pseudo"> +<link rel="match" href="lang-000-ref.html"> + +<style> +div.test { color: green; } +:lang("fr-CH") { color: red; } +</style> + +<div class="test"><span lang="fr">This should be green</span></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-006.html b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-006.html new file mode 100644 index 0000000..d249a4c --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-006.html
@@ -0,0 +1,14 @@ +<!DOCTYPE html> +<html lang="en-US"> +<meta charset="utf-8"> +<title>CSS Selectors 4 - :lang matching</title> +<link rel="author" title="Jonathan Kew" href="mailto:jkew@mozilla.com"> +<link rel="help" href="https://drafts.csswg.org/selectors-4/#the-lang-pseudo"> +<link rel="match" href="lang-000-ref.html"> + +<style> +div.test { color: green; } +:lang("fr-CH") { color: red; } +</style> + +<div class="test"><span lang="fr-FR">This should be green</span></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-007.html b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-007.html new file mode 100644 index 0000000..a21506d --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-007.html
@@ -0,0 +1,14 @@ +<!DOCTYPE html> +<html lang="en-US"> +<meta charset="utf-8"> +<title>CSS Selectors 4 - :lang matching</title> +<link rel="author" title="Jonathan Kew" href="mailto:jkew@mozilla.com"> +<link rel="help" href="https://drafts.csswg.org/selectors-4/#the-lang-pseudo"> +<link rel="match" href="lang-000-ref.html"> + +<style> +div.test { color: red; } +:lang("*-CH") { color: green; } +</style> + +<div class="test"><span lang="fr-CH">This should be green</span></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-007.html.ini b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-007.html.ini new file mode 100644 index 0000000..6d4b6e1 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-007.html.ini
@@ -0,0 +1,2 @@ +[lang-007.html] + expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-008.html b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-008.html new file mode 100644 index 0000000..77f77a8 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-008.html
@@ -0,0 +1,14 @@ +<!DOCTYPE html> +<html lang="en-US"> +<meta charset="utf-8"> +<title>CSS Selectors 4 - :lang matching</title> +<link rel="author" title="Jonathan Kew" href="mailto:jkew@mozilla.com"> +<link rel="help" href="https://drafts.csswg.org/selectors-4/#the-lang-pseudo"> +<link rel="match" href="lang-000-ref.html"> + +<style> +div.test { color: red; } +:lang("*-Latn") { color: green; } +</style> + +<div class="test"><span lang="fr-Latn-FR">This should be green</span></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-008.html.ini b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-008.html.ini new file mode 100644 index 0000000..fdb6efba --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-008.html.ini
@@ -0,0 +1,2 @@ +[lang-008.html] + expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-009.html b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-009.html new file mode 100644 index 0000000..bf2e988 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-009.html
@@ -0,0 +1,14 @@ +<!DOCTYPE html> +<html lang="en-US"> +<meta charset="utf-8"> +<title>CSS Selectors 4 - :lang matching</title> +<link rel="author" title="Jonathan Kew" href="mailto:jkew@mozilla.com"> +<link rel="help" href="https://drafts.csswg.org/selectors-4/#the-lang-pseudo"> +<link rel="match" href="lang-000-ref.html"> + +<style> +div.test { color: red; } +:lang("fr-FR") { color: green; } +</style> + +<div class="test"><span lang="fr-Latn-FR">This should be green</span></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-009.html.ini b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-009.html.ini new file mode 100644 index 0000000..066833d --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-009.html.ini
@@ -0,0 +1,2 @@ +[lang-009.html] + expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-010.html b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-010.html new file mode 100644 index 0000000..081c920 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-010.html
@@ -0,0 +1,14 @@ +<!DOCTYPE html> +<html lang="en-US"> +<meta charset="utf-8"> +<title>CSS Selectors 4 - :lang matching</title> +<link rel="author" title="Jonathan Kew" href="mailto:jkew@mozilla.com"> +<link rel="help" href="https://drafts.csswg.org/selectors-4/#the-lang-pseudo"> +<link rel="match" href="lang-000-ref.html"> + +<style> +div.test { color: red; } +:lang("*-FR") { color: green; } +</style> + +<div class="test"><span lang="fr-Latn-FR">This should be green</span></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-010.html.ini b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-010.html.ini new file mode 100644 index 0000000..15ec088e --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-010.html.ini
@@ -0,0 +1,2 @@ +[lang-010.html] + expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-011.html b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-011.html new file mode 100644 index 0000000..5620317 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-011.html
@@ -0,0 +1,14 @@ +<!DOCTYPE html> +<html lang="en-US"> +<meta charset="utf-8"> +<title>CSS Selectors 4 - :lang matching</title> +<link rel="author" title="Jonathan Kew" href="mailto:jkew@mozilla.com"> +<link rel="help" href="https://drafts.csswg.org/selectors-4/#the-lang-pseudo"> +<link rel="match" href="lang-000-ref.html"> + +<style> +div.test { color: red; } +:lang("fr", "nl", "de") { color: green; } +</style> + +<div class="test"><span lang="fr-Latn-FR">This should be green</span></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-011.html.ini b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-011.html.ini new file mode 100644 index 0000000..b168bf5 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-011.html.ini
@@ -0,0 +1,2 @@ +[lang-011.html] + expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-012.html b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-012.html new file mode 100644 index 0000000..f299e22 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-012.html
@@ -0,0 +1,14 @@ +<!DOCTYPE html> +<html lang="en-US"> +<meta charset="utf-8"> +<title>CSS Selectors 4 - :lang matching</title> +<link rel="author" title="Jonathan Kew" href="mailto:jkew@mozilla.com"> +<link rel="help" href="https://drafts.csswg.org/selectors-4/#the-lang-pseudo"> +<link rel="match" href="lang-000-ref.html"> + +<style> +div.test { color: red; } +:lang(de, nl, fr) { color: green; } +</style> + +<div class="test"><span lang="fr-Latn-FR">This should be green</span></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-012.html.ini b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-012.html.ini new file mode 100644 index 0000000..cdc6baf --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-012.html.ini
@@ -0,0 +1,2 @@ +[lang-012.html] + expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-013.html b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-013.html new file mode 100644 index 0000000..34303d9 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-013.html
@@ -0,0 +1,14 @@ +<!DOCTYPE html> +<html lang="en-US"> +<meta charset="utf-8"> +<title>CSS Selectors 4 - :lang matching</title> +<link rel="author" title="Jonathan Kew" href="mailto:jkew@mozilla.com"> +<link rel="help" href="https://drafts.csswg.org/selectors-4/#the-lang-pseudo"> +<link rel="match" href="lang-000-ref.html"> + +<style> +div.test { color: green; } +:lang(de, nl, 0, fr) { color: red; } +</style> + +<div class="test"><span lang="fr">This should be green</span></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-014.html b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-014.html new file mode 100644 index 0000000..2d064c8 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-014.html
@@ -0,0 +1,14 @@ +<!DOCTYPE html> +<html lang="en-US"> +<meta charset="utf-8"> +<title>CSS Selectors 4 - :lang matching</title> +<link rel="author" title="Jonathan Kew" href="mailto:jkew@mozilla.com"> +<link rel="help" href="https://drafts.csswg.org/selectors-4/#the-lang-pseudo"> +<link rel="match" href="lang-000-ref.html"> + +<style> +div.test { color: green; } +:lang(0) { color: red; } +</style> + +<div class="test"><span lang="0">This should be green</span></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-015.html b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-015.html new file mode 100644 index 0000000..4d90b080 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-015.html
@@ -0,0 +1,14 @@ +<!DOCTYPE html> +<html lang="en-US"> +<meta charset="utf-8"> +<title>CSS Selectors 4 - :lang matching</title> +<link rel="author" title="Jonathan Kew" href="mailto:jkew@mozilla.com"> +<link rel="help" href="https://drafts.csswg.org/selectors-4/#the-lang-pseudo"> +<link rel="match" href="lang-000-ref.html"> + +<style> +div.test { color: red; } +:lang(\*-FR) { color: green; } +</style> + +<div class="test"><span lang="fr-Latn-FR">This should be green</span></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-015.html.ini b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-015.html.ini new file mode 100644 index 0000000..98c067ba --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/selectors/selectors-4/lang-015.html.ini
@@ -0,0 +1,2 @@ +[lang-015.html] + expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/fs/script-tests/FileSystemBaseHandle-IndexedDB.js b/third_party/blink/web_tests/external/wpt/fs/script-tests/FileSystemBaseHandle-IndexedDB.js index 15a0c2a3..9e114619 100644 --- a/third_party/blink/web_tests/external/wpt/fs/script-tests/FileSystemBaseHandle-IndexedDB.js +++ b/third_party/blink/web_tests/external/wpt/fs/script-tests/FileSystemBaseHandle-IndexedDB.js
@@ -119,3 +119,27 @@ assert_equals(result.value.length, value.length); await assert_equals_cloned_handles(result.value, value); }, 'Store handle in IndexedDB using inline keys.'); + +directory_test(async (t, root_dir) => { + const expected_root_name = ''; + assert_equals(root_dir.name, expected_root_name); + + const db = await createDatabase(t, db => { + const store = db.createObjectStore('store', {keyPath: 'key'}); + }); + + const value = [ root_dir ]; + let tx = db.transaction('store', 'readwrite'); + let store = tx.objectStore('store'); + await promiseForRequest(t, store.put({key: 'key', value})); + await promiseForTransaction(t, tx); + + tx = db.transaction('store', 'readonly'); + store = tx.objectStore('store'); + const result = await promiseForRequest(t, store.get('key')); + await promiseForTransaction(t, tx); + + const actual = result.value[ 0 ]; + assert_equals(actual.name, expected_root_name); + assert_true(await root_dir.isSameEntry(actual)); +}, 'Store and retrieve the root directory from IndexedDB.');
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/document-metadata/the-meta-element/http-equiv-and-name-1.html b/third_party/blink/web_tests/external/wpt/html/semantics/document-metadata/the-meta-element/http-equiv-and-name-1.html new file mode 100644 index 0000000..ac82e339 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/semantics/document-metadata/the-meta-element/http-equiv-and-name-1.html
@@ -0,0 +1,23 @@ +<!doctype html> +<title>Setting both http-equiv and name attributes on a meta element</title> +<meta http-equiv=content-language name=color-scheme content=dark> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="color-scheme/support/compute-root-color-scheme.js"></script> +<!-- + NOTE: This test assumes that the browser's default color-scheme is "light", + see https://github.com/web-platform-tests/wpt/pull/31268 for reasoning +--> +<script> + // This creates a test() + assert_root_color_scheme("dark", "<meta> set the color-scheme to dark"); + + // We can't test content-language against :lang(), because CSS Selectors 4 + // references BCP 47 syntax and RFC4647 "Matching of Language Tags", but + // "dark" is not a well-formed BCP 47 tag and therefore cannot be matched. + // Therefore, the test that content-language gets set is split off to a + // separate testcase using a well-formed lang tag as the content. + // test(() => { + // assert_equals(document.querySelector(":root:lang(dark)"), document.documentElement); + // }, "<meta> set the content-language to dark"); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/document-metadata/the-meta-element/http-equiv-and-name-2.html b/third_party/blink/web_tests/external/wpt/html/semantics/document-metadata/the-meta-element/http-equiv-and-name-2.html new file mode 100644 index 0000000..b73013a --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/semantics/document-metadata/the-meta-element/http-equiv-and-name-2.html
@@ -0,0 +1,13 @@ +<!doctype html> +<title>Setting both http-equiv and name attributes on a meta element</title> +<meta http-equiv=content-language name=color-scheme content=de-DE> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + // We don't attempt to test the color-scheme here because "de-DE" is not a valid + // value for it. + + test(() => { + assert_equals(document.querySelector(":root:lang(de-DE)"), document.documentElement); + }, "<meta> set the content-language to de-DE"); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/document-metadata/the-meta-element/http-equiv-and-name.html b/third_party/blink/web_tests/external/wpt/html/semantics/document-metadata/the-meta-element/http-equiv-and-name.html deleted file mode 100644 index 144217df..0000000 --- a/third_party/blink/web_tests/external/wpt/html/semantics/document-metadata/the-meta-element/http-equiv-and-name.html +++ /dev/null
@@ -1,18 +0,0 @@ -<!doctype html> -<title>Setting both http-equiv and name attributes on a meta element</title> -<meta http-equiv=content-language name=color-scheme content=dark> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<script src="color-scheme/support/compute-root-color-scheme.js"></script> -<!-- - NOTE: This test assumes that the browser's default color-scheme is "light", - see https://github.com/web-platform-tests/wpt/pull/31268 for reasoning ---> -<script> - // This creates a test() - assert_root_color_scheme("dark", "<meta> set the color-scheme to dark"); - - test(() => { - assert_equals(document.querySelector(":root:lang(dark)"), document.documentElement); - }, "<meta> set the content-language to dark"); -</script>
diff --git a/third_party/blink/web_tests/external/wpt/mediacapture-streams/MediaStreamTrack-MediaElement-disabled-video-is-black.https.html.ini b/third_party/blink/web_tests/external/wpt/mediacapture-streams/MediaStreamTrack-MediaElement-disabled-video-is-black.https.html.ini new file mode 100644 index 0000000..e289c3ad --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/mediacapture-streams/MediaStreamTrack-MediaElement-disabled-video-is-black.https.html.ini
@@ -0,0 +1,4 @@ +[MediaStreamTrack-MediaElement-disabled-video-is-black.https.html] + [Test that frames don't flow for a disabled video track] + expected: + if product == "chrome": [FAIL, PASS]
diff --git a/third_party/blink/web_tests/external/wpt/navigation-api/navigate-event/navigate-destination-dynamic-index.html.ini b/third_party/blink/web_tests/external/wpt/navigation-api/navigate-event/navigate-destination-dynamic-index.html.ini new file mode 100644 index 0000000..9329a66 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/navigation-api/navigate-event/navigate-destination-dynamic-index.html.ini
@@ -0,0 +1,4 @@ +[navigate-destination-dynamic-index.html] + [navigate event destination.index should be dynamic] + expected: + if product == "chrome": FAIL
diff --git a/third_party/blink/web_tests/external/wpt/scroll-animations/css/scroll-timeline-attachment.html b/third_party/blink/web_tests/external/wpt/scroll-animations/css/scroll-timeline-attachment.html new file mode 100644 index 0000000..78ca2574 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/scroll-animations/css/scroll-timeline-attachment.html
@@ -0,0 +1,296 @@ +<!DOCTYPE html> +<title>Scroll Timeline Attachment</title> +<link rel="help" src="https://github.com/w3c/csswg-drafts/issues/7759"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/web-animations/testcommon.js"></script> + +<main id=main></main> +<script> + function inflate(t, template) { + t.add_cleanup(() => main.replaceChildren()); + main.append(template.content.cloneNode(true)); + main.offsetTop; + } + + async function scrollTop(e, value) { + e.scrollTop = value; + await waitForNextFrame(); + } +</script> +<style> + @keyframes anim { + from { width: 0px; --applied:true; } + to { width: 200px; --applied:true; } + } + + .scroller { + overflow-y: hidden; + width: 200px; + height: 200px; + } + .scroller > .content { + margin: 400px 0px; + width: 100px; + height: 100px; + background-color: green; + } + .target { + background-color: coral; + width: 0px; + animation: anim auto linear; + animation-timeline: t1; + } + .timeline { + scroll-timeline-name: t1; + } + .local { + scroll-timeline-attachment: local; + } + .defer { + scroll-timeline-attachment: defer; + } + .ancestor { + scroll-timeline-attachment: ancestor; + } + +</style> + + +<!-- Basic Behavior --> + +<template id=scroll_timeline_defer> + <div class="timeline defer"> + <div class=target>Test</div> + <div class="scroller timeline ancestor"> + <div class=content></div> + </div> + </div> +</template> +<script> + promise_test(async (t) => { + inflate(t, scroll_timeline_defer); + let scroller = main.querySelector('.scroller'); + let target = main.querySelector('.target'); + await scrollTop(scroller, 350); // 50% + assert_equals(getComputedStyle(target).width, '100px'); // 0px => 200px, 50% + }, 'Descendant can attach to deferred timeline'); +</script> + +<template id=scroll_timeline_defer_no_attach> + <div class="timeline defer"> + <div class=target>Test</div> + <div class="scroller timeline"> + <div class=content></div> + </div> + </div> +</template> +<script> + promise_test(async (t) => { + inflate(t, scroll_timeline_defer_no_attach); + let scroller = main.querySelector('.scroller'); + let target = main.querySelector('.target'); + await scrollTop(scroller, 350); // 50% + assert_equals(getComputedStyle(target).width, '0px'); + assert_equals(getComputedStyle(target).getPropertyValue('--applied'), ''); + }, 'Deferred timeline with no attachments'); +</script> + +<template id=scroll_timeline_local_ancestor> + <div class="scroller timeline local"> + <div class=content> + <div class=target>Test</div> + <div class="scroller timeline ancestor"> + <div class=content></div> + </div> + </div> + </div> +</template> +<script> + promise_test(async (t) => { + inflate(t, scroll_timeline_local_ancestor); + let scroller = main.querySelector('.scroller'); + let target = main.querySelector('.target'); + await scrollTop(scroller, 350); // 50% + assert_equals(getComputedStyle(target).width, '100px'); // 0px => 200px, 50% + }, 'Timeline with ancestor attachment does not attach to local'); +</script> + +<template id=scroll_timeline_defer_two_attachments> + <div class="timeline defer"> + <div class=target>Test</div> + <div class="scroller timeline ancestor"> + <div class=content></div> + </div> + <!-- Extra attachment --> + <div class="timeline ancestor"></div> + </div> +</template> +<script> + promise_test(async (t) => { + inflate(t, scroll_timeline_defer_two_attachments); + let scroller = main.querySelector('.scroller'); + let target = main.querySelector('.target'); + await scrollTop(scroller, 350); // 50% + assert_equals(getComputedStyle(target).width, '0px'); + assert_equals(getComputedStyle(target).getPropertyValue('--applied'), ''); + }, 'Deferred timeline with two attachments'); +</script> + +<!-- Effective Axis of ScrollTimeline --> + +<template id=scroll_timeline_defer_axis> + <div class="timeline defer" style="scroll-timeline-axis:inline"> + <div class=target>Test</div> + <div class="scroller timeline ancestor" style="scroll-timeline-axis:vertical"> + <div class=content></div> + </div> + </div> +</template> +<script> + promise_test(async (t) => { + inflate(t, scroll_timeline_defer_axis); + let target = main.querySelector('.target'); + assert_equals(target.getAnimations().length, 1); + let anim = target.getAnimations()[0]; + assert_not_equals(anim.timeline, null); + assert_equals(anim.timeline.axis, 'vertical'); + }, 'Axis of deferred timeline is taken from attached timeline'); +</script> + + +<template id=scroll_timeline_defer_axis_multiple> + <div class="timeline defer" style="scroll-timeline-axis:inline"> + <div class=target>Test</div> + <div class="scroller timeline ancestor" style="scroll-timeline-axis:vertical"> + <div class=content></div> + </div> + <!-- Extra attachment --> + <div class="timeline ancestor"></div> + </div> +</template> +<script> + promise_test(async (t) => { + inflate(t, scroll_timeline_defer_axis_multiple); + let target = main.querySelector('.target'); + assert_equals(target.getAnimations().length, 1); + let anim = target.getAnimations()[0]; + assert_not_equals(anim.timeline, null); + assert_equals(anim.timeline.axis, 'block'); + }, 'Axis of deferred timeline with multiple attachments'); +</script> + + +<!-- Dynamic Reattachment --> + + +<template id=scroll_timeline_reattach> + <div class="timeline defer"> + <div class=target>Test</div> + <div class="scroller timeline ancestor"> + <div class=content></div> + </div> + <div class="scroller timeline"> + <div class=content></div> + </div> + </div> +</template> +<script> + promise_test(async (t) => { + inflate(t, scroll_timeline_reattach); + let scrollers = main.querySelectorAll('.scroller'); + assert_equals(scrollers.length, 2); + let target = main.querySelector('.target'); + await scrollTop(scrollers[0], 350); // 50% + await scrollTop(scrollers[1], 175); // 25% + + // Attached to scrollers[0]. + assert_equals(getComputedStyle(target).width, '100px'); // 0px => 200px, 50% + + // Reattach to scrollers[1]. + scrollers[0].classList.remove('ancestor'); + scrollers[1].classList.add('ancestor'); + + await waitForNextFrame(); + assert_equals(getComputedStyle(target).width, '50px'); // 0px => 200px, 25% + }, 'Dynamically re-attaching'); +</script> + + +<template id=scroll_timeline_dynamic_attach_second> + <div class="timeline defer"> + <div class=target>Test</div> + <div class="scroller timeline"> + <div class=content></div> + </div> + <div class="scroller timeline"> + <div class=content></div> + </div> + </div> +</template> +<script> + promise_test(async (t) => { + inflate(t, scroll_timeline_dynamic_attach_second); + let scrollers = main.querySelectorAll('.scroller'); + assert_equals(scrollers.length, 2); + let target = main.querySelector('.target'); + await scrollTop(scrollers[0], 350); // 50% + await scrollTop(scrollers[1], 175); // 25% + + // Attached to no timelines initially: + assert_equals(getComputedStyle(target).width, '0px'); + assert_equals(getComputedStyle(target).getPropertyValue('--applied'), ''); + + // Attach to scrollers[0]. + scrollers[0].classList.add('ancestor'); + await waitForNextFrame(); + assert_equals(getComputedStyle(target).width, '100px'); // 0px => 200px, 50% + + // Also attach scrollers[1]. + scrollers[1].classList.add('ancestor'); + + await waitForNextFrame(); + assert_equals(getComputedStyle(target).width, '0px'); + assert_equals(getComputedStyle(target).getPropertyValue('--applied'), ''); + }, 'Dynamically attaching'); +</script> + + +<template id=scroll_timeline_dynamic_detach_second> + <div class="timeline defer"> + <div class=target>Test</div> + <div class="scroller timeline ancestor"> + <div class=content></div> + </div> + <div class="scroller timeline ancestor"> + <div class=content></div> + </div> + </div> +</template> +<script> + promise_test(async (t) => { + inflate(t, scroll_timeline_dynamic_detach_second); + let scrollers = main.querySelectorAll('.scroller'); + assert_equals(scrollers.length, 2); + let target = main.querySelector('.target'); + await scrollTop(scrollers[0], 350); // 50% + await scrollTop(scrollers[1], 175); // 25% + + // Attached to two timelines initially: + assert_equals(getComputedStyle(target).width, '0px'); + assert_equals(getComputedStyle(target).getPropertyValue('--applied'), ''); + + // Detach scrollers[1]. + scrollers[1].classList.remove('ancestor'); + + await waitForNextFrame(); + assert_equals(getComputedStyle(target).width, '100px'); // 0px => 200px, 50% + + // Also detach scrollers[0]. + scrollers[0].classList.remove('ancestor'); + + await waitForNextFrame(); + assert_equals(getComputedStyle(target).width, '0px'); + assert_equals(getComputedStyle(target).getPropertyValue('--applied'), ''); + }, 'Dynamically detaching'); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/scroll-animations/css/timeline-offset-keyframes-hidden-subject.html b/third_party/blink/web_tests/external/wpt/scroll-animations/css/timeline-offset-keyframes-hidden-subject.html index 047acfe..389c8ba 100644 --- a/third_party/blink/web_tests/external/wpt/scroll-animations/css/timeline-offset-keyframes-hidden-subject.html +++ b/third_party/blink/web_tests/external/wpt/scroll-animations/css/timeline-offset-keyframes-hidden-subject.html
@@ -62,7 +62,10 @@ async function runTest() { promise_test(async t => { await waitForNextFrame(); - const anim = document.getAnimations()[0]; + const anims = document.getAnimations(); + assert_equals(anims.length, 1, + "Should have one animation attatched to the view-timeline"); + const anim = anims[0]; await anim.ready; await waitForNextFrame();
diff --git a/third_party/blink/web_tests/external/wpt/scroll-animations/css/timeline-range-name-offset-in-keyframes.tentative.html b/third_party/blink/web_tests/external/wpt/scroll-animations/css/timeline-range-name-offset-in-keyframes.tentative.html index a0d1bd9..7bae49c 100644 --- a/third_party/blink/web_tests/external/wpt/scroll-animations/css/timeline-range-name-offset-in-keyframes.tentative.html +++ b/third_party/blink/web_tests/external/wpt/scroll-animations/css/timeline-range-name-offset-in-keyframes.tentative.html
@@ -51,7 +51,6 @@ // scrollTop=200 to 400 is the entry range container.scrollTop = 200; await waitForNextFrame(); - const anim = document.getAnimations()[0]; assert_equals(getComputedStyle(subject).opacity, '0', 'Effect at entry 0%');
diff --git a/third_party/blink/web_tests/external/wpt/scroll-animations/css/view-timeline-animation.html b/third_party/blink/web_tests/external/wpt/scroll-animations/css/view-timeline-animation.html index b816bb6..73189b8 100644 --- a/third_party/blink/web_tests/external/wpt/scroll-animations/css/view-timeline-animation.html +++ b/third_party/blink/web_tests/external/wpt/scroll-animations/css/view-timeline-animation.html
@@ -1,5 +1,6 @@ <!DOCTYPE html> <title>Animations using view-timeline</title> +<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1"> <link rel="help" src="https://drafts.csswg.org/scroll-animations-1/#view-timelines-named"> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script>
diff --git a/third_party/blink/web_tests/external/wpt/scroll-animations/css/view-timeline-attachment.html b/third_party/blink/web_tests/external/wpt/scroll-animations/css/view-timeline-attachment.html new file mode 100644 index 0000000..47f4444 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/scroll-animations/css/view-timeline-attachment.html
@@ -0,0 +1,338 @@ +<!DOCTYPE html> +<title>View Timeline Attachment</title> +<link rel="help" src="https://github.com/w3c/csswg-drafts/issues/7759"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/web-animations/testcommon.js"></script> + +<main id=main></main> +<script> + function inflate(t, template) { + t.add_cleanup(() => main.replaceChildren()); + main.append(template.content.cloneNode(true)); + main.offsetTop; + } + + async function scrollTop(e, value) { + e.scrollTop = value; + await waitForNextFrame(); + } +</script> +<style> + @keyframes anim { + from { width: 0px; --applied:true; } + to { width: 200px; --applied:true; } + } + + .scroller { + overflow-y: hidden; + width: 200px; + height: 200px; + } + .scroller > .content { + margin: 400px 0px; + width: 100px; + height: 100px; + background-color: green; + } + .target { + background-color: coral; + width: 0px; + animation: anim auto linear; + animation-timeline: t1; + } + /* + .defer { + view-timeline-name: t1; + view-timeline-attachment: defer; + } + */ + .timeline { + view-timeline-name: t1; + } + .local { + view-timeline-attachment: local; + } + .defer { + view-timeline-attachment: defer; + } + .ancestor { + view-timeline-attachment: ancestor; + } + +</style> + +<!-- Basic Behavior --> + +<template id=view_timeline_defer> + <div class="timeline defer"> + <div class=target>Test</div> + <div class=scroller> + <div class="content timeline ancestor"></div> + </div> + </div> +</template> +<script> + promise_test(async (t) => { + inflate(t, view_timeline_defer); + let scroller = main.querySelector('.scroller'); + let target = main.querySelector('.target'); + await scrollTop(scroller, 350); // 50% + assert_equals(getComputedStyle(target).width, '100px'); // 0px => 200px, 50% + }, 'Descendant can attach to deferred timeline'); +</script> + +<template id=view_timeline_defer_no_attach> + <div class="timeline defer"> + <div class=target>Test</div> + <div class=scroller> + <div class="timeline content"></div> + </div> + </div> +</template> +<script> + promise_test(async (t) => { + inflate(t, view_timeline_defer_no_attach); + let scroller = main.querySelector('.scroller'); + let target = main.querySelector('.target'); + await scrollTop(scroller, 350); // 50% + assert_equals(getComputedStyle(target).width, '0px'); + assert_equals(getComputedStyle(target).getPropertyValue('--applied'), ''); + }, 'Deferred timeline with no attachments'); +</script> + +<template id=view_timeline_defer_two_attachments> + <div class="timeline defer"> + <div class=target>Test</div> + <div class=scroller> + <div class="content timeline ancestor"></div> + <!-- Extra attachment --> + <div class="timeline ancestor"></div> + </div> + </div> +</template> +<script> + promise_test(async (t) => { + inflate(t, view_timeline_defer_two_attachments); + let scroller = main.querySelector('.scroller'); + let target = main.querySelector('.target'); + await scrollTop(scroller, 350); // 50% + assert_equals(getComputedStyle(target).width, '0px'); + assert_equals(getComputedStyle(target).getPropertyValue('--applied'), ''); + }, 'Deferred timeline with two attachments'); +</script> + +<!-- Effective Axis of ViewTimeline --> + +<template id=view_timeline_defer_axis> + <div class="timeline defer" style="view-timeline-axis:inline"> + <div class=target>Test</div> + <div class=scroller> + <div class="content timeline ancestor" style="view-timeline-axis:vertical"></div> + </div> + </div> +</template> +<script> + promise_test(async (t) => { + inflate(t, view_timeline_defer_axis); + let target = main.querySelector('.target'); + assert_equals(target.getAnimations().length, 1); + let anim = target.getAnimations()[0]; + assert_not_equals(anim.timeline, null); + assert_equals(anim.timeline.axis, 'vertical'); + }, 'Axis of deferred timeline is taken from attached timeline'); +</script> + +<template id=view_timeline_defer_axis_multiple> + <div class="timeline defer" style="view-timeline-axis:inline"> + <div class=target>Test</div> + <div class=scroller> + <div class="content timeline ancestor" style="view-timeline-axis:vertical"></div> + <!-- Extra attachment --> + <div class="timeline ancestor"></div> + </div> + </div> +</template> +<script> + promise_test(async (t) => { + inflate(t, view_timeline_defer_axis_multiple); + let target = main.querySelector('.target'); + assert_equals(target.getAnimations().length, 1); + let anim = target.getAnimations()[0]; + assert_not_equals(anim.timeline, null); + assert_equals(anim.timeline.axis, 'block'); + }, 'Axis of deferred timeline with multiple attachments'); +</script> + +<!-- Effective Inset of ViewTimeline --> + +<template id=view_timeline_inset> + <div class="timeline defer" style="view-timeline-inset:0px"> + <div class=target>Test</div> + <div class=scroller> + <div class="content timeline ancestor" style="view-timeline-inset:50px"></div> + </div> + </div> +</template> +<script> + promise_test(async (t) => { + inflate(t, view_timeline_inset); + let scroller = main.querySelector('.scroller'); + let target = main.querySelector('.target'); + + // Range: [200, 500] + [50, -50] (inset) = [250, 450] + await scrollTop(scroller, 300); // 25% + assert_equals(getComputedStyle(target).width, '50px'); // 0px => 200px, 25% + }, 'Inset of deferred timeline is taken from attached timeline'); +</script> + +<!-- Dynamic Reattachment --> + +<template id=view_timeline_reattach> + <div class="timeline defer"> + <div class=target>Test</div> + <div class=scroller> + <div class="content timeline ancestor"></div> + </div> + <div class=scroller> + <div class="content timeline"></div> + </div> + </div> +</template> +<script> + promise_test(async (t) => { + inflate(t, view_timeline_reattach); + let scrollers = main.querySelectorAll('.scroller'); + let contents = main.querySelectorAll('.content'); + assert_equals(scrollers.length, 2); + let target = main.querySelector('.target'); + // Range: [200, 500] + await scrollTop(scrollers[0], 350); // 50% + await scrollTop(scrollers[1], 275); // 25% + + // Attached to contents[0]. + assert_equals(getComputedStyle(target).width, '100px'); // 0px => 200px, 50% + + // Reattach to contents[1]. + contents[0].classList.remove('ancestor'); + contents[1].classList.add('ancestor'); + + await waitForNextFrame(); + assert_equals(getComputedStyle(target).width, '50px'); // 0px => 200px, 25% + }, 'Dynamically re-attaching'); +</script> + + +<template id=view_timeline_dynamic_attach_second> + <div class="timeline defer"> + <div class=target>Test</div> + <div class=scroller> + <div class="timeline content"></div> + </div> + <div class=scroller> + <div class="timeline content"></div> + </div> + </div> +</template> +<script> + promise_test(async (t) => { + inflate(t, view_timeline_dynamic_attach_second); + let scrollers = main.querySelectorAll('.scroller'); + let contents = main.querySelectorAll('.content'); + assert_equals(scrollers.length, 2); + let target = main.querySelector('.target'); + // Range: [200, 500] + await scrollTop(scrollers[0], 350); // 50% + await scrollTop(scrollers[1], 275); // 25% + + // Attached to no timelines initially: + assert_equals(getComputedStyle(target).width, '0px'); + assert_equals(getComputedStyle(target).getPropertyValue('--applied'), ''); + + // Attach to contents[0]. + contents[0].classList.add('ancestor'); + await waitForNextFrame(); + assert_equals(getComputedStyle(target).width, '100px'); // 0px => 200px, 50% + + // Also attach contents[1]. + contents[1].classList.add('ancestor'); + + await waitForNextFrame(); + assert_equals(getComputedStyle(target).width, '0px'); + assert_equals(getComputedStyle(target).getPropertyValue('--applied'), ''); + }, 'Dynamically attaching'); +</script> + + +<template id=view_timeline_dynamic_detach_second> + <div class="timeline defer"> + <div class=target>Test</div> + <div class=scroller> + <div class="content timeline ancestor"></div> + </div> + <div class=scroller> + <div class="content timeline ancestor"></div> + </div> + </div> +</template> +<script> + promise_test(async (t) => { + inflate(t, view_timeline_dynamic_detach_second); + let scrollers = main.querySelectorAll('.scroller'); + let contents = main.querySelectorAll('.content'); + assert_equals(scrollers.length, 2); + let target = main.querySelector('.target'); + // Range: [200, 500] + await scrollTop(scrollers[0], 350); // 50% + await scrollTop(scrollers[1], 275); // 25% + + // Attached to two timelines initially: + assert_equals(getComputedStyle(target).width, '0px'); + assert_equals(getComputedStyle(target).getPropertyValue('--applied'), ''); + + // Detach contents[1]. + contents[1].classList.remove('ancestor'); + + await waitForNextFrame(); + assert_equals(getComputedStyle(target).width, '100px'); // 0px => 200px, 50% + + // Also detach contents[0]. + contents[0].classList.remove('ancestor'); + + await waitForNextFrame(); + assert_equals(getComputedStyle(target).width, '0px'); + assert_equals(getComputedStyle(target).getPropertyValue('--applied'), ''); + }, 'Dynamically detaching'); +</script> + +<!-- ViewTimelines and ScrollTimelines --> + +<template id=view_scroll_timeline_defer> + <div style="scroll-timeline: t1 defer"> + <div class=target>Test1</div> + <div class="timeline defer"> + <div class=target>Test2</div> + <div class=scroller style="scroll-timeline: t1 ancestor;"> + <div class="content timeline ancestor" style="view-timeline-inset: 0px 50px"></div> + </div> + </div> + </div> +</template> +<script> + promise_test(async (t) => { + inflate(t, view_scroll_timeline_defer); + let scroller = main.querySelector('.scroller'); + let targets = main.querySelectorAll('.target'); + await scrollTop(scroller, 350); + + // Attached to ScrollTimeline: + // Range: [0, 700] + // 350 => 50% + assert_equals(getComputedStyle(targets[0]).width, '100px'); + + // Attached to ViewTimeline: + // Range: [200, 500] + [50, 0] (inset) = [250, 500] + // 350 => 40% + assert_equals(getComputedStyle(targets[1]).width, '80px'); + }, 'Mixing deferred scroll and view-timelines'); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/scroll-animations/css/view-timeline-inset-animation.html b/third_party/blink/web_tests/external/wpt/scroll-animations/css/view-timeline-inset-animation.html index a95086b6..a7e807c 100644 --- a/third_party/blink/web_tests/external/wpt/scroll-animations/css/view-timeline-inset-animation.html +++ b/third_party/blink/web_tests/external/wpt/scroll-animations/css/view-timeline-inset-animation.html
@@ -1,5 +1,6 @@ <!DOCTYPE html> <title>Animations using view-timeline-inset</title> +<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1"> <link rel="help" src="https://drafts.csswg.org/scroll-animations-1/#propdef-view-timeline-inset"> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script>
diff --git a/third_party/blink/web_tests/external/wpt/scroll-animations/css/view-timeline-keyframe-boundary-interpolation.html b/third_party/blink/web_tests/external/wpt/scroll-animations/css/view-timeline-keyframe-boundary-interpolation.html index 1dc766d9..04eb648 100644 --- a/third_party/blink/web_tests/external/wpt/scroll-animations/css/view-timeline-keyframe-boundary-interpolation.html +++ b/third_party/blink/web_tests/external/wpt/scroll-animations/css/view-timeline-keyframe-boundary-interpolation.html
@@ -80,7 +80,10 @@ promise_test(async t => { await waitForNextFrame(); - const anim = document.getAnimations()[0]; + const anims = document.getAnimations(); + assert_equals(anims.length, 1, + "Should have one animation attatched to the view-timeline"); + const anim = anims[0]; await anim.ready; await waitForNextFrame();
diff --git a/third_party/blink/web_tests/external/wpt/scroll-animations/css/view-timeline-lookup-expected.txt b/third_party/blink/web_tests/external/wpt/scroll-animations/css/view-timeline-lookup-expected.txt new file mode 100644 index 0000000..58d0663a --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/scroll-animations/css/view-timeline-lookup-expected.txt
@@ -0,0 +1,11 @@ +This is a testharness.js-based test. +PASS view-timeline on self +PASS view-timeline on preceding sibling +PASS view-timeline on ancestor +PASS view-timeline on ancestor sibling +PASS view-timeline on ancestor sibling, closest wins +PASS view-timeline on ancestor sibling, skips nonmatching names +PASS view-timeline on ancestor sibling, closer scroll-timeline wins +FAIL view-timeline on ancestor sibling, scroll-timeline wins on same element assert_equals: expected "0" but got "75" +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/scroll-animations/css/view-timeline-lookup.html b/third_party/blink/web_tests/external/wpt/scroll-animations/css/view-timeline-lookup.html index c1797c7b..b8a5b000 100644 --- a/third_party/blink/web_tests/external/wpt/scroll-animations/css/view-timeline-lookup.html +++ b/third_party/blink/web_tests/external/wpt/scroll-animations/css/view-timeline-lookup.html
@@ -260,8 +260,7 @@ }, 'view-timeline on ancestor sibling, closer scroll-timeline wins'); </script> - -<template id=timeline_ancestor_view_timeline_wins_on_same_element> +<template id=timeline_ancestor_scroll_timeline_wins_on_same_element> <style> #timelines { height: 0px; @@ -294,8 +293,11 @@ </template> <script> promise_test(async (t) => { - inflate(t, timeline_ancestor_view_timeline_wins_on_same_element); + inflate(t, timeline_ancestor_scroll_timeline_wins_on_same_element); await waitForNextFrame(); - assert_equals(getComputedStyle(target).zIndex, '75'); - }, 'view-timeline on ancestor sibling, view-timeline wins on same element'); + // In case of a name conflict on the same element, scroll progress timelines + // take precedence over view progress timelines. + // https://drafts.csswg.org/scroll-animations-1/#timeline-scope + assert_equals(getComputedStyle(target).zIndex, '0'); + }, 'view-timeline on ancestor sibling, scroll-timeline wins on same element'); </script>
diff --git a/third_party/blink/web_tests/external/wpt/scroll-animations/css/view-timeline-lookup.html.ini b/third_party/blink/web_tests/external/wpt/scroll-animations/css/view-timeline-lookup.html.ini new file mode 100644 index 0000000..911d046f --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/scroll-animations/css/view-timeline-lookup.html.ini
@@ -0,0 +1,3 @@ +[view-timeline-lookup.html] + [view-timeline on ancestor sibling, scroll-timeline wins on same element] + expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/shadow-dom/leaktests/html-collection-expected.txt b/third_party/blink/web_tests/external/wpt/shadow-dom/leaktests/html-collection-expected.txt new file mode 100644 index 0000000..4097c36 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/shadow-dom/leaktests/html-collection-expected.txt
@@ -0,0 +1,12 @@ +This is a testharness.js-based test. +PASS document.scripts should not contain shadow nodes +PASS document.all should not contain shadow nodes +PASS document.forms should not contain shadow nodes +PASS document.images should not contain shadow nodes +PASS document.links should not contain shadow nodes +PASS document.anchors should not contain shadow nodes +PASS document.embeds should not contain shadow nodes +PASS document.plugins should not contain shadow nodes +FAIL document.applets should not contain any nodes assert_equals: expected 0 but got 1 +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/shadow-dom/leaktests/html-collection.html b/third_party/blink/web_tests/external/wpt/shadow-dom/leaktests/html-collection.html index 2f3d49e..1ce2cf3 100644 --- a/third_party/blink/web_tests/external/wpt/shadow-dom/leaktests/html-collection.html +++ b/third_party/blink/web_tests/external/wpt/shadow-dom/leaktests/html-collection.html
@@ -67,10 +67,13 @@ ['document.links should not contain shadow nodes', 'links'], ['document.anchors should not contain shadow nodes', 'anchors'], ['document.embeds should not contain shadow nodes', 'embeds'], - ['document.plugins should not contain shadow nodes', 'plugins'], - ['document.applets should not contain shadow nodes', 'applets']]; + ['document.plugins should not contain shadow nodes', 'plugins']]; generate_tests(testCollection, testParams); +test(() => { + assert_equals(document.applets.length, 0); +}, 'document.applets should not contain any nodes'); + </script> </html>
diff --git a/third_party/blink/web_tests/external/wpt/shadow-dom/leaktests/html-collection.html.ini b/third_party/blink/web_tests/external/wpt/shadow-dom/leaktests/html-collection.html.ini new file mode 100644 index 0000000..956589f --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/shadow-dom/leaktests/html-collection.html.ini
@@ -0,0 +1,3 @@ +[html-collection.html] + [document.applets should not contain any nodes] + expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/webcodecs/video-encoder.https.any.js b/third_party/blink/web_tests/external/wpt/webcodecs/video-encoder.https.any.js index b5c511d4..229ae32 100644 --- a/third_party/blink/web_tests/external/wpt/webcodecs/video-encoder.https.any.js +++ b/third_party/blink/web_tests/external/wpt/webcodecs/video-encoder.https.any.js
@@ -295,7 +295,7 @@ encoder.configure(defaultConfig); - assert_throws_dom("OperationError", () => { + assert_throws_js(TypeError, () => { encoder.encode(frame); }); }, 'Verify encoding closed frames throws.');
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/perform_actions/key_events.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/perform_actions/key_events.py index 8dbe024..9f912684 100644 --- a/third_party/blink/web_tests/external/wpt/webdriver/tests/perform_actions/key_events.py +++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/perform_actions/key_events.py
@@ -6,7 +6,7 @@ from tests.perform_actions.support.keys import ALL_EVENTS, Keys, ALTERNATIVE_KEY_NAMES from tests.perform_actions.support.refine import get_events, get_keys -from tests.support.helpers import filter_dict +from tests.support.helpers import filter_dict, filter_supported_key_events def test_keyup_only_sends_no_events(session, key_reporter, key_chain): @@ -48,11 +48,7 @@ {"code": code, "key": value, "type": "keyup"}, ] - events = [filter_dict(e, expected[0]) for e in all_events] - if len(events) > 0 and events[0]["code"] is None: - # Remove 'code' entry if browser doesn't support it - expected = [filter_dict(e, {"key": "", "type": ""}) for e in expected] - events = [filter_dict(e, expected[0]) for e in events] + (events, expected) = filter_supported_key_events(all_events, expected) assert events == expected assert len(get_keys(key_reporter)) == 0 @@ -85,12 +81,8 @@ alt_expected[0]["key"] = ALTERNATIVE_KEY_NAMES[event] alt_expected[2]["key"] = ALTERNATIVE_KEY_NAMES[event] - events = [filter_dict(e, expected[0]) for e in all_events] - if len(events) > 0 and events[0]["code"] is None: - # Remove 'code' entry if browser doesn't support it - expected = [filter_dict(e, {"key": "", "type": ""}) for e in expected] - alt_expected = [filter_dict(e, {"key": "", "type": ""}) for e in alt_expected] - events = [filter_dict(e, expected[0]) for e in events] + (_, expected) = filter_supported_key_events(all_events, expected) + (events, alt_expected) = filter_supported_key_events(all_events, alt_expected) if len(events) == 2: # most browsers don't send a keypress for non-printable keys assert events == [expected[0], expected[2]] or events == [alt_expected[0], alt_expected[2]] @@ -124,11 +116,7 @@ {"code": code, "key": value, "type": "keyup"}, ] - events = [filter_dict(e, expected[0]) for e in all_events] - if len(events) > 0 and events[0]["code"] is None: - # Remove 'code' entry if browser doesn't support it - expected = [filter_dict(e, {"key": "", "type": ""}) for e in expected] - events = [filter_dict(e, expected[0]) for e in events] + (events, expected) = filter_supported_key_events(all_events, expected) assert events == expected assert get_keys(key_reporter) == value @@ -148,11 +136,7 @@ {"code": "KeyB", "key": "b", "type": "keypress"}, ] - events = [filter_dict(e, expected[0]) for e in all_events] - if len(events) > 0 and events[0]["code"] is None: - # Remove 'code' entry if browser doesn't support it - expected = [filter_dict(e, {"key": "", "type": ""}) for e in expected] - events = [filter_dict(e, expected[0]) for e in events] + (events, expected) = filter_supported_key_events(all_events, expected) assert events == expected assert get_keys(key_reporter) == "ab" @@ -171,11 +155,7 @@ {"code": "KeyF", "key": "f", "type": "keyup"}, ] - events = [filter_dict(e, expected[0]) for e in all_events] - if len(events) > 0 and events[0]["code"] is None: - # Remove 'code' entry if browser doesn't support it - expected = [filter_dict(e, {"key": "", "type": ""}) for e in expected] - events = [filter_dict(e, expected[0]) for e in events] + (events, expected) = filter_supported_key_events(all_events, expected) assert events == expected assert get_keys(key_reporter) == "ef"
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/release_actions/sequence.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/release_actions/sequence.py index 75143d85..24ca16c86 100644 --- a/third_party/blink/web_tests/external/wpt/webdriver/tests/release_actions/sequence.py +++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/release_actions/sequence.py
@@ -1,7 +1,7 @@ # META: timeout=long from tests.release_actions.support.refine import get_events, get_keys -from tests.support.helpers import filter_dict +from tests.support.helpers import filter_dict, filter_supported_key_events def test_release_no_actions_sends_no_events(session, key_reporter): @@ -25,11 +25,7 @@ {"code": "KeyA", "key": "a", "type": "keyup"}, ] all_events = get_events(session) - events = [filter_dict(e, expected[0]) for e in all_events] - if len(events) > 0 and events[0]["code"] is None: - # Remove 'code' entry if browser doesn't support it - expected = [filter_dict(e, {"key": "", "type": ""}) for e in expected] - events = [filter_dict(e, expected[0]) for e in events] + (events, expected) = filter_supported_key_events(all_events, expected) assert events == expected
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/support/fixtures_bidi.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/support/fixtures_bidi.py index 9407dc1..612718b 100644 --- a/third_party/blink/web_tests/external/wpt/webdriver/tests/support/fixtures_bidi.py +++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/support/fixtures_bidi.py
@@ -334,3 +334,17 @@ return base64.b64decode(image_string_without_data_type) return render_pdf_to_png_bidi + + +@pytest.fixture +def test_actions_page_bidi(bidi_session, url, top_context): + """Navigate to test_actions.html.""" + + async def test_actions_page_bidi(context=top_context): + await bidi_session.browsing_context.navigate( + context=context["context"], + url=url("/webdriver/tests/support/html/test_actions.html"), + wait="complete", + ) + + return test_actions_page_bidi
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/support/helpers.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/support/helpers.py index b0c065d..45f4f4d 100644 --- a/third_party/blink/web_tests/external/wpt/webdriver/tests/support/helpers.py +++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/support/helpers.py
@@ -245,6 +245,16 @@ return {k: source[k] for k in d.keys()} +def filter_supported_key_events(all_events, expected): + events = [filter_dict(e, expected[0]) for e in all_events] + if len(events) > 0 and events[0]["code"] is None: + # Remove 'code' entry if browser doesn't support it + expected = [filter_dict(e, {"key": "", "type": ""}) for e in expected] + events = [filter_dict(e, expected[0]) for e in events] + + return (events, expected) + + def wait_for_new_handle(session, handles_before): def find_new_handle(session): new_handles = list(set(session.handles) - set(handles_before))
diff --git a/third_party/blink/web_tests/external/wpt/webtransport/datagrams.https.any-expected.txt b/third_party/blink/web_tests/external/wpt/webtransport/datagrams.https.any-expected.txt new file mode 100644 index 0000000..cdb67a1 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/webtransport/datagrams.https.any-expected.txt
@@ -0,0 +1,13 @@ +This is a testharness.js-based test. +PASS Datagrams are echoed successfully +PASS Successfully reading datagrams with BYOB reader. +PASS Reading datagrams with insufficient buffer should be rejected. +PASS Transfer max-size datagram +FAIL Fail to transfer max-size+1 datagram assert_equals: expected (undefined) undefined but got (object) object "[object Object]" +PASS Sending and receiving datagrams is ready to use before session is established +PASS Datagram's outgoingHighWaterMark correctly regulates written datagrams +PASS Datagrams read is less than or equal to the incomingHighWaterMark +FAIL Datagram MaxAge getters/setters work correctly assert_equals: expected (number) Infinity but got (object) null +FAIL Datagram HighWaterMark getters/setters work correctly assert_throws_js: function "() => { wt.datagrams.incomingHighWaterMark = -1; }" did not throw +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/webtransport/datagrams.https.any.js b/third_party/blink/web_tests/external/wpt/webtransport/datagrams.https.any.js index b96b36fc..dc7133bb 100644 --- a/third_party/blink/web_tests/external/wpt/webtransport/datagrams.https.any.js +++ b/third_party/blink/web_tests/external/wpt/webtransport/datagrams.https.any.js
@@ -23,6 +23,20 @@ return sentTokens; } +// Write N datagrams without waiting, then wait for them +async function write_N_datagrams(writer, n) { + const encoder = new TextEncoder(); + const sentTokens = []; + const promises = []; + while (sentTokens.length < n) { + const token = sentTokens.length.toString(); + sentTokens.push(token); + promises.push(writer.write(encoder.encode(token))); + } + await Promise.all(promises); + return sentTokens; +} + // Read datagrams until the consumer has received enough i.e. N datagrams. Call // abort() after reading. async function read_datagrams(reader, controller, N) { @@ -156,6 +170,37 @@ }, 'Reading datagrams with insufficient buffer should be rejected.'); promise_test(async t => { + // Establish a WebTransport session. + const wt = new WebTransport(webtransport_url('echo.py')); + await wt.ready; + + const writer = wt.datagrams.writable.getWriter(); + const reader = wt.datagrams.readable.getReader(); + + // Write and read max-size datagram. + await writer.write(new Uint8Array(wt.datagrams.maxDatagramSize)); + const { value: token, done } = await reader.read(); + assert_false(done); + assert_equals(token.length, wt.datagrams.maxDatagramSize); +}, 'Transfer max-size datagram'); + +promise_test(async t => { + // Establish a WebTransport session. + const wt = new WebTransport(webtransport_url('echo.py')); + await wt.ready; + + const writer = wt.datagrams.writable.getWriter(); + const reader = wt.datagrams.readable.getReader(); + + // Write and read max-size datagram. + await writer.write(new Uint8Array(wt.datagrams.maxDatagramSize+1)); + // This should resolve with no datagram sent, which is hard to test for. + // Wait for incoming datagrams to arrive, and if they do, fail. + const result = await Promise.race([reader.read(), wait(500)]); + assert_equals(result, undefined); +}, 'Fail to transfer max-size+1 datagram'); + +promise_test(async t => { // Make a WebTransport connection, but session is not necessarily established. const wt = new WebTransport(webtransport_url('echo.py')); @@ -166,9 +211,10 @@ const signal = controller.signal; // Write and read datagrams. - const N = 1; + const N = 5; + wt.datagrams.outgoingHighWaterMark = N; const [sentTokens, receivedTokens] = await Promise.all([ - write_datagrams(writer, signal), + write_N_datagrams(writer, N), read_datagrams(reader, controller, N) ]); @@ -269,3 +315,56 @@ // incomingHighWaterMark. assert_less_than_equal(receivedDatagrams, N); }, 'Datagrams read is less than or equal to the incomingHighWaterMark'); + +promise_test(async t => { + // Establish a WebTransport session. + const wt = new WebTransport(webtransport_url('echo.py')); + await wt.ready; + + assert_equals(wt.datagrams.incomingMaxAge, Infinity); + assert_equals(wt.datagrams.outgoingMaxAge, Infinity); + + wt.datagrams.incomingMaxAge = 5; + assert_equals(wt.datagrams.incomingMaxAge, 5); + wt.datagrams.outgoingMaxAge = 5; + assert_equals(wt.datagrams.outgoingMaxAge, 5); + + assert_throws_js(RangeError, () => { wt.datagrams.incomingMaxAge = -1; }); + assert_throws_js(RangeError, () => { wt.datagrams.outgoingMaxAge = -1; }); + assert_throws_js(RangeError, () => { wt.datagrams.incomingMaxAge = NaN; }); + assert_throws_js(RangeError, () => { wt.datagrams.outgoingMaxAge = NaN; }); + + wt.datagrams.incomingMaxAge = 0; + assert_equals(wt.datagrams.incomingMaxAge, Infinity); + wt.datagrams.outgoingMaxAge = 0; + assert_equals(wt.datagrams.outgoingMaxAge, Infinity); +}, 'Datagram MaxAge getters/setters work correctly'); + +promise_test(async t => { + // Establish a WebTransport session. + const wt = new WebTransport(webtransport_url('echo.py')); + await wt.ready; + + // Initial values are implementation-defined + assert_greater_than_equal(wt.datagrams.incomingHighWaterMark, 1); + assert_greater_than_equal(wt.datagrams.outgoingHighWaterMark, 1); + + wt.datagrams.incomingHighWaterMark = 5; + assert_equals(wt.datagrams.incomingHighWaterMark, 5); + wt.datagrams.outgoingHighWaterMark = 5; + assert_equals(wt.datagrams.outgoingHighWaterMark, 5); + + assert_throws_js(RangeError, () => { wt.datagrams.incomingHighWaterMark = -1; }); + assert_throws_js(RangeError, () => { wt.datagrams.outgoingHighWaterMark = -1; }); + assert_throws_js(RangeError, () => { wt.datagrams.incomingHighWaterMark = NaN; }); + assert_throws_js(RangeError, () => { wt.datagrams.outgoingHighWaterMark = NaN; }); + + wt.datagrams.incomingHighWaterMark = 0.5; + assert_equals(wt.datagrams.incomingHighWaterMark, 1); + wt.datagrams.outgoingHighWaterMark = 0.5; + assert_equals(wt.datagrams.outgoingHighWaterMark, 1); + wt.datagrams.incomingHighWaterMark = 0; + assert_equals(wt.datagrams.incomingHighWaterMark, 1); + wt.datagrams.outgoingHighWaterMark = 0; + assert_equals(wt.datagrams.outgoingHighWaterMark, 1); +}, 'Datagram HighWaterMark getters/setters work correctly');
diff --git a/third_party/blink/web_tests/external/wpt/webtransport/datagrams.https.any.serviceworker-expected.txt b/third_party/blink/web_tests/external/wpt/webtransport/datagrams.https.any.serviceworker-expected.txt new file mode 100644 index 0000000..cdb67a1 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/webtransport/datagrams.https.any.serviceworker-expected.txt
@@ -0,0 +1,13 @@ +This is a testharness.js-based test. +PASS Datagrams are echoed successfully +PASS Successfully reading datagrams with BYOB reader. +PASS Reading datagrams with insufficient buffer should be rejected. +PASS Transfer max-size datagram +FAIL Fail to transfer max-size+1 datagram assert_equals: expected (undefined) undefined but got (object) object "[object Object]" +PASS Sending and receiving datagrams is ready to use before session is established +PASS Datagram's outgoingHighWaterMark correctly regulates written datagrams +PASS Datagrams read is less than or equal to the incomingHighWaterMark +FAIL Datagram MaxAge getters/setters work correctly assert_equals: expected (number) Infinity but got (object) null +FAIL Datagram HighWaterMark getters/setters work correctly assert_throws_js: function "() => { wt.datagrams.incomingHighWaterMark = -1; }" did not throw +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/webtransport/datagrams.https.any.sharedworker-expected.txt b/third_party/blink/web_tests/external/wpt/webtransport/datagrams.https.any.sharedworker-expected.txt new file mode 100644 index 0000000..cdb67a1 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/webtransport/datagrams.https.any.sharedworker-expected.txt
@@ -0,0 +1,13 @@ +This is a testharness.js-based test. +PASS Datagrams are echoed successfully +PASS Successfully reading datagrams with BYOB reader. +PASS Reading datagrams with insufficient buffer should be rejected. +PASS Transfer max-size datagram +FAIL Fail to transfer max-size+1 datagram assert_equals: expected (undefined) undefined but got (object) object "[object Object]" +PASS Sending and receiving datagrams is ready to use before session is established +PASS Datagram's outgoingHighWaterMark correctly regulates written datagrams +PASS Datagrams read is less than or equal to the incomingHighWaterMark +FAIL Datagram MaxAge getters/setters work correctly assert_equals: expected (number) Infinity but got (object) null +FAIL Datagram HighWaterMark getters/setters work correctly assert_throws_js: function "() => { wt.datagrams.incomingHighWaterMark = -1; }" did not throw +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/webtransport/datagrams.https.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/webtransport/datagrams.https.any.worker-expected.txt new file mode 100644 index 0000000..cdb67a1 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/webtransport/datagrams.https.any.worker-expected.txt
@@ -0,0 +1,13 @@ +This is a testharness.js-based test. +PASS Datagrams are echoed successfully +PASS Successfully reading datagrams with BYOB reader. +PASS Reading datagrams with insufficient buffer should be rejected. +PASS Transfer max-size datagram +FAIL Fail to transfer max-size+1 datagram assert_equals: expected (undefined) undefined but got (object) object "[object Object]" +PASS Sending and receiving datagrams is ready to use before session is established +PASS Datagram's outgoingHighWaterMark correctly regulates written datagrams +PASS Datagrams read is less than or equal to the incomingHighWaterMark +FAIL Datagram MaxAge getters/setters work correctly assert_equals: expected (number) Infinity but got (object) null +FAIL Datagram HighWaterMark getters/setters work correctly assert_throws_js: function "() => { wt.datagrams.incomingHighWaterMark = -1; }" did not throw +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/webtransport/resources/webtransport-test-helpers.sub.js b/third_party/blink/web_tests/external/wpt/webtransport/resources/webtransport-test-helpers.sub.js index 733153e..9f9127b 100644 --- a/third_party/blink/web_tests/external/wpt/webtransport/resources/webtransport-test-helpers.sub.js +++ b/third_party/blink/web_tests/external/wpt/webtransport/resources/webtransport-test-helpers.sub.js
@@ -20,6 +20,23 @@ return first + n + Math.floor(n / 0x1e); } +// Read all chunks from |readable_stream| and return as an array of arrays +async function read_stream(readable_stream) { + const reader = readable_stream.getReader(); + + let chunks = []; + while (true) { + const {value: chunk, done} = await reader.read(); + if (done) { + break; + } + chunks.push(chunk); + } + reader.releaseLock(); + + return chunks; +} + // Read all chunks from |readable_stream|, decode chunks to a utf-8 string, then // return the string. async function read_stream_as_string(readable_stream) {
diff --git a/third_party/blink/web_tests/external/wpt/webtransport/streams-echo.https.any.js b/third_party/blink/web_tests/external/wpt/webtransport/streams-echo.https.any.js index 3278141..18ebe12 100644 --- a/third_party/blink/web_tests/external/wpt/webtransport/streams-echo.https.any.js +++ b/third_party/blink/web_tests/external/wpt/webtransport/streams-echo.https.any.js
@@ -151,3 +151,65 @@ } reader.releaseLock(); }, 'Can read data from a unidirectional stream with BYOB reader'); + +promise_test(async t => { + // Establish a WebTransport session. + const wt = new WebTransport(webtransport_url('echo.py')); + await wt.ready; + + // Create a bidirectional stream. + const bidi_stream = await wt.createBidirectionalStream(); + + // Write a message to the writable end, and close it. + const writer = bidi_stream.writable.getWriter(); + const bytes = new Uint8Array(16384); + const [reply] = await Promise.all([ + read_stream(bidi_stream.readable), + writer.write(bytes), + writer.write(bytes), + writer.write(bytes), + writer.close() + ]); + let len = 0; + for (chunk of reply) { + len += chunk.length; + } + // Check that the message from the readable end matches the writable end. + assert_equals(len, 3*bytes.length); +}, 'Transfer large chunks of data on a bidirectional stream'); + +promise_test(async t => { + // Establish a WebTransport session. + const wt = new WebTransport(webtransport_url('echo.py')); + await wt.ready; + + // Create a unidirectional stream. + const uni_stream = await wt.createUnidirectionalStream(); + + // Write a message to the writable end, and close it. + const writer = uni_stream.getWriter(); + const bytes = new Uint8Array(16384); + await Promise.all([ + writer.write(bytes), + writer.write(bytes), + writer.write(bytes), + writer.close() + ]); + // XXX Update once chrome fixes https://crbug.com/929585 + // The echo handler creates a new unidirectional stream to echo back data from + // the server to client. Accept the unidirectional stream. + const readable = wt.incomingUnidirectionalStreams; + const stream_reader = readable.getReader(); + const { value: recv_stream } = await stream_reader.read(); + stream_reader.releaseLock(); + + // Read the data on the readable end. + const reply = await read_stream(recv_stream); + let len = 0; + for (chunk of reply) { + len += chunk.length; + } + // Check that the message from the readable end matches the writable end. + assert_equals(len, 3*bytes.length); +}, 'Transfer large chunks of data on a unidirectional stream'); +
diff --git a/third_party/blink/web_tests/external/wpt/webvtt/rendering/cues-with-video/processing-model/evil/non-standard-pseudo-elements.html.ini b/third_party/blink/web_tests/external/wpt/webvtt/rendering/cues-with-video/processing-model/evil/non-standard-pseudo-elements.html.ini index 2b6d832..04e50d9b 100644 --- a/third_party/blink/web_tests/external/wpt/webvtt/rendering/cues-with-video/processing-model/evil/non-standard-pseudo-elements.html.ini +++ b/third_party/blink/web_tests/external/wpt/webvtt/rendering/cues-with-video/processing-model/evil/non-standard-pseudo-elements.html.ini
@@ -1,3 +1,3 @@ [non-standard-pseudo-elements.html] expected: - if (product == "content_shell") and (os == "win") and (port == "win11"): FAIL + if (product == "content_shell") and (os == "win"): FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/attribution-reporting/request-format.sub.https.html b/third_party/blink/web_tests/wpt_internal/attribution-reporting/request-format.sub.https.html index 7310c56..006ac69 100644 --- a/third_party/blink/web_tests/wpt_internal/attribution-reporting/request-format.sub.https.html +++ b/third_party/blink/web_tests/wpt_internal/attribution-reporting/request-format.sub.https.html
@@ -9,13 +9,30 @@ <meta name=variant content="?method=script&eligible&expected-eligible=event-source, trigger&expected-support=web"> <meta name=variant content="?method=fetch"> <meta name=variant content="?method=fetch&eligible=event-source&expected-eligible=event-source&expected-support=web"> +<meta name=variant content="?method=xhr"> +<meta name=variant content="?method=xhr&eligible=event-source&expected-eligible=event-source&expected-support=web"> <script src="/resources/testdriver.js"></script> <script src="/resources/testdriver-vendor.js"></script> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> -<script src="/service-workers/service-worker/resources/test-helpers.sub.js"></script> <script src="resources/helpers.js"></script> +<body> <script> +const waitForRequest = async () => { + const url = blankURL(); + url.searchParams.set('get-requests', 'true'); + + for (let i = 0; i < 20; i++) { + const resp = await fetch(url); + const payload = await resp.json(); + if (payload !== null && payload.length > 0) { + return payload; + } + await delay(100); + } + throw new Error('Timeout polling requests'); +}; + const searchParams = new URLSearchParams(location.search); const expected_eligible = searchParams.get('expected-eligible') === null ? undefined : searchParams.get('expected-eligible'); @@ -23,35 +40,25 @@ searchParams.get('expected-support') === null ? undefined : searchParams.get('expected-support'); promise_test(async t => { - const reg = await navigator.serviceWorker.register( - 'resources/attributionsrc-worker.js', {scope: './'}); - t.add_cleanup(() => reg.unregister()); - - const sw = reg.installing || reg.waiting || reg.active; - await wait_for_state(t, sw, 'activated'); - - const p = new Promise(resolve => { - navigator.serviceWorker.addEventListener('message', - e => resolve(e.data), {once: true}); - }); - // Set mixed-case query params to ensure that they are propagated correctly. await registerAttributionSrc(t, { method: 'variant', - extraQueryParams: {'aB': 'Cd'}, + extraQueryParams: {'aB': 'Cd', 'store-request': 'true'}, }); - const message = await p; - assert_equals(message.method, 'GET'); - assert_equals(message.headers['attribution-reporting-eligible'], expected_eligible); - assert_equals(message.headers['attribution-reporting-support'], expected_support); - assert_equals(message.referrer, location.toString()); + const requests = await waitForRequest(); + assert_equals(requests.length, 1); + assert_equals(requests[0].method, 'GET'); + assert_equals(requests[0]['attribution-reporting-eligible'], expected_eligible); + assert_equals(requests[0]['attribution-reporting-support'], expected_support); + assert_equals(requests[0].referer, location.toString()); // TODO(apaseltiner): Test various referrer policies. // TODO(apaseltiner): Test cookie propagation. const expectedURL = blankURL(); expectedURL.searchParams.set('aB', 'Cd'); - assert_equals(message.url, expectedURL.toString()); + expectedURL.searchParams.set('store-request', 'true'); + assert_equals(requests[0].url, expectedURL.toString()); }, 'attributionsrc request has the proper format.'); </script>
diff --git a/third_party/blink/web_tests/wpt_internal/attribution-reporting/resources/attributionsrc-worker.js b/third_party/blink/web_tests/wpt_internal/attribution-reporting/resources/attributionsrc-worker.js deleted file mode 100644 index 8617923a..0000000 --- a/third_party/blink/web_tests/wpt_internal/attribution-reporting/resources/attributionsrc-worker.js +++ /dev/null
@@ -1,27 +0,0 @@ -addEventListener('fetch', event => { - event.waitUntil((async () => { - if (!event.clientId) { - return; - } - - const client = await clients.get(event.clientId); - if (!client) { - return; - } - - const headers = {}; - for (const pair of event.request.headers.entries()) { - headers[pair[0]] = pair[1]; - } - - client.postMessage({ - url: event.request.url, - method: event.request.method, - referrer: event.request.referrer, - headers, - }); - })()); -}); - -addEventListener('activate', event => event.waitUntil(clients.claim())); -addEventListener('install', event => event.waitUntil(skipWaiting()));
diff --git a/third_party/blink/web_tests/wpt_internal/attribution-reporting/resources/attributionsrc-worker.js.headers b/third_party/blink/web_tests/wpt_internal/attribution-reporting/resources/attributionsrc-worker.js.headers deleted file mode 100644 index 980a8349..0000000 --- a/third_party/blink/web_tests/wpt_internal/attribution-reporting/resources/attributionsrc-worker.js.headers +++ /dev/null
@@ -1 +0,0 @@ -Service-Worker-Allowed: ..
diff --git a/third_party/blink/web_tests/wpt_internal/attribution-reporting/resources/helpers.js b/third_party/blink/web_tests/wpt_internal/attribution-reporting/resources/helpers.js index 306a6c6..c41673f 100644 --- a/third_party/blink/web_tests/wpt_internal/attribution-reporting/resources/helpers.js +++ b/third_party/blink/web_tests/wpt_internal/attribution-reporting/resources/helpers.js
@@ -263,20 +263,18 @@ * the source is not done registering after 2 seconds, it times out and throws * an error. */ -const waitForSourceToBeRegistered = async ( - sourceId, - attempt = 0 -) => { - if (attempt > 20) { - throw new Error(`Timeout polling source ${sourceId} registration`); - } +const waitForSourceToBeRegistered = async (sourceId) => { const url = blankURL(); url.searchParams.set("check-source-id", sourceId); - const { status } = await fetch(url); - if (status === 404) { + + for (let i = 0; i < 20; i++) { + const {status} = await fetch(url); + if (status !== 404) { + return; + } await delay(100); - return waitForSourceToBeRegistered(sourceId, attempt + 1); } + throw new Error(`Timeout polling source ${sourceId} registration`); }; const pollEventLevelReports = (origin, interval) =>
diff --git a/third_party/blink/web_tests/wpt_internal/attribution-reporting/resources/reporting_origin.py b/third_party/blink/web_tests/wpt_internal/attribution-reporting/resources/reporting_origin.py index f23d77e..0224678 100644 --- a/third_party/blink/web_tests/wpt_internal/attribution-reporting/resources/reporting_origin.py +++ b/third_party/blink/web_tests/wpt_internal/attribution-reporting/resources/reporting_origin.py
@@ -6,10 +6,13 @@ """ from wptserve.stash import Stash +import json # Key used to access the source IDs in the stash. SOURCES = "9250f93f-2c05-4aae-83b9-2817b0e18b4c" +REQUESTS = "9250f93f-2c05-4aae-83b9-2817b0e18b4d" + def store_source(stash: Stash, source_id: str) -> None: """Stores the source id in the stash, indicating that it's been processed.""" @@ -38,6 +41,36 @@ return True +headers = [ + b"attribution-reporting-eligible", + b"attribution-reporting-support", + b"referer", +] + + +def store_request(request) -> None: + obj = { + "method": request.method, + "url": request.url, + } + for header in headers: + value = request.headers.get(header) + if value is not None: + obj[str(header, "utf-8")] = str(value, "utf-8") + with request.server.stash.lock: + requests = request.server.stash.take(REQUESTS) + if not requests: + requests = [] + requests.append(obj) + request.server.stash.put(REQUESTS, requests) + return None + + +def get_requests(request) -> str: + with request.server.stash.lock: + return json.dumps(request.server.stash.take(REQUESTS)) + + def main(request, response): """ For most requests, simply returns a 200. Actual source/trigger registration @@ -58,6 +91,13 @@ response.status = 200 return + if request.GET.get(b"get-requests"): + return get_requests(request) + + if request.GET.get(b"store-request"): + store_request(request) + return "" + source_id = request.GET.get(b"store-source-id") if source_id: location = (request.url_parts.path + "?redirect-store-source-id=" +
diff --git a/third_party/metrics_proto/README.chromium b/third_party/metrics_proto/README.chromium index aaff61c1..986f66d3 100644 --- a/third_party/metrics_proto/README.chromium +++ b/third_party/metrics_proto/README.chromium
@@ -1,8 +1,8 @@ Name: Metrics Protos Short Name: metrics_proto URL: This is the canonical public repository -Version: 519987140 -Date: 2023/03/28 UTC +Version: 523818867 +Date: 2023/04/12 UTC License: BSD Security Critical: Yes
diff --git a/third_party/metrics_proto/omnibox_event.proto b/third_party/metrics_proto/omnibox_event.proto index 96fa84ed..637c037 100644 --- a/third_party/metrics_proto/omnibox_event.proto +++ b/third_party/metrics_proto/omnibox_event.proto
@@ -14,7 +14,7 @@ import "omnibox_input_type.proto"; // Stores information about an omnibox interaction. -// Next tag: 25 +// Next tag: 27 message OmniboxEventProto { // The timestamp for the event, in seconds. // This value comes from Chromium's TimeTicks::Now(), which is an abstract @@ -568,16 +568,38 @@ // by clicking on a image tile. optional bool is_query_started_from_tile = 21; + enum Feature { + RICH_AUTOCOMPLETION = 0; + SHORT_BOOKMARK_SUGGESTIONS_BY_TOTAL_INPUT_LENGTH = 2; + FUZZY_URL_SUGGESTIONS = 3; + HISTORY_CLUSTER_SUGGESTION = 4; + DOMAIN_SUGGESTIONS = 5; + // Whether the `SearchProvider` response included: + // '"google:fieldtrialtriggered":true'. + REMOTE_SEARCH_FEATURE = 6; + // Like `REMOTE_SEARCH_FEATURE`, but for the `ZeroSearchProvider`. + REMOTE_ZERO_SUGGEST_FEATURE = 7; + SHORTCUT_BOOST = 8; + REMOTE_SECONDARY_ZERO_SUGGEST = 9; + } // The set of features triggered in the most recent query. Each element is a - // value of `OmniboxTriggeredFeatureService::Features` enum in - // components/omnibox/browser/omnibox_triggered_feature_service.h . - repeated int32 feature_triggered = 24; + // value of `Features` enum. + repeated int32 legacy_feature_triggered = 24 [deprecated = true]; // Like above except that the set of features is a union of all features that // triggered within the current omnibox session including the most recent // query. See `AutocompleteController::ResetSession()` for more details on the // definition of a session. - repeated int32 feature_triggered_in_session = 22; + repeated int32 legacy_feature_triggered_in_session = 22 [deprecated = true]; + + // The set of features triggered in the most recent query. + repeated Feature feature_triggered = 25; + + // Like above except that the set of features is a union of all features that + // triggered within the current omnibox session including the most recent + // query. See `AutocompleteController::ResetSession()` for more details on the + // definition of a session. + repeated Feature feature_triggered_in_session = 26; // Profile data of the user. Currently, only logged when there is a URL click. message ProfileData {
diff --git a/third_party/webgpu-cts/ts_sources.txt b/third_party/webgpu-cts/ts_sources.txt index 33fbf8e..f0bb289 100644 --- a/third_party/webgpu-cts/ts_sources.txt +++ b/third_party/webgpu-cts/ts_sources.txt
@@ -371,6 +371,7 @@ src/webgpu/shader/execution/expression/call/builtin/atomicStore.spec.ts src/webgpu/shader/execution/expression/call/builtin/atomicSub.spec.ts src/webgpu/shader/execution/expression/call/builtin/atomicXor.spec.ts +src/webgpu/shader/execution/expression/call/builtin/bitcast.spec.ts src/webgpu/shader/execution/expression/call/builtin/ceil.spec.ts src/webgpu/shader/execution/expression/call/builtin/clamp.spec.ts src/webgpu/shader/execution/expression/call/builtin/cos.spec.ts
diff --git a/tools/chromeos/run_cros.sh b/tools/chromeos/run_cros.sh index 5bbc51f..cdd7040 100755 --- a/tools/chromeos/run_cros.sh +++ b/tools/chromeos/run_cros.sh
@@ -82,13 +82,13 @@ ARGS="--user-data-dir=${USER_DATA_DIR} \ --enable-wayland-server --ash-debug-shortcuts \ --enable-ui-devtools --ash-dev-shortcuts --login-manager \ + --lacros-chrome-additional-args=--gpu-sandbox-start-early \ --login-profile=user --lacros-mojo-socket-for-testing=$LACROS_SOCK_FILE \ --ash-host-window-bounds=${DISPLAY_CONFIG} \ --enable-features=${FEATURES} \ ${TOUCH_DEVICE_OPTION} \ --lacros-chrome-path=${LACROS_BUILD_DIR}" - # --no-sandbox --enable-wayland-server --ash-debug-shortcuts \ # To enable internal display. ARGS="${ARGS} --use-first-display-as-internal" } @@ -103,7 +103,7 @@ check_chrome_dir "$ASH_CHROME_BUILD_DIR" ash-chrome-build-dir if [ $LACROS_ENABLED ]; then - check_chrome_dir "$LACROS_BUILD_DIR" lacros-chrome-build-dir + check_chrome_dir "$LACROS_BUILD_DIR" lacros-build-dir fi ensure_user_dir ${USER_DATA_DIR} "ash-chrome" @@ -144,7 +144,7 @@ -s ${LACROS_SOCK_FILE} \ ${LACROS_BUILD_DIR}/chrome \ --user-data-dir=${lacros_user_data_dir} \ - --enable-ui-devtools + --enable-ui-devtools --gpu-sandbox-start-early } function lacros_log {
diff --git a/tools/clang/scripts/package.py b/tools/clang/scripts/package.py index eda9ddc1..49410a81 100755 --- a/tools/clang/scripts/package.py +++ b/tools/clang/scripts/package.py
@@ -620,58 +620,6 @@ PackageInArchive(clang_format_dir, clang_format_dir) MaybeUpload(args.upload, clang_format_dir + '.t*z', gcs_platform) - # Zip up clang-libs for users who opt into it. We want Clang and LLVM headers - # and libs, as well as a couple binaries. The LLVM parts are needed by the - # Rust build. - clang_libs_dir = 'clang-libs-' + stamp - shutil.rmtree(clang_libs_dir, ignore_errors=True) - os.makedirs(os.path.join(clang_libs_dir, 'include')) - # TODO(danakj): It's possible we need to also include headers from - # LLVM_DIR/clang/lib/AST/ and other subdirs of lib, but we won't include them - # unless we see it's needed, and we can document why. - shutil.copytree(os.path.join(LLVM_DIR, 'clang', 'include', 'clang'), - os.path.join(clang_libs_dir, 'include', 'clang')) - - # Copy LLVM includes. The llvm source and build directory includes must be - # merged. llvm-c for C bindings is also included. - # - # Headers and libs are copied from LLVM_BOOTSTRAP_DIR, not LLVM_RELEASE_DIR, - # because the release libs have LTO so they contain LLVM bitcode while the - # bootstrap libs do not. The Rust build consumes these,the first stage of - # which cannot handle newer LLVM bitcode. The stage 0 rustc is linked against - # an older LLVM. - shutil.copytree(os.path.join(LLVM_DIR, 'llvm', 'include', 'llvm'), - os.path.join(clang_libs_dir, 'include', 'llvm')) - shutil.copytree(os.path.join(LLVM_DIR, 'llvm', 'include', 'llvm-c'), - os.path.join(clang_libs_dir, 'include', 'llvm-c')) - shutil.copytree(os.path.join(LLVM_BOOTSTRAP_DIR, 'include', 'llvm'), - os.path.join(clang_libs_dir, 'include', 'llvm'), - dirs_exist_ok=True) - - # Copy llvm-config and FileCheck which the Rust build needs - os.makedirs(os.path.join(clang_libs_dir, 'bin')) - shutil.copy(os.path.join(LLVM_BOOTSTRAP_DIR, 'bin', 'llvm-config' + exe_ext), - os.path.join(clang_libs_dir, 'bin')) - shutil.copy(os.path.join(LLVM_BOOTSTRAP_DIR, 'bin', 'FileCheck' + exe_ext), - os.path.join(clang_libs_dir, 'bin')) - - os.makedirs(os.path.join(clang_libs_dir, 'lib')) - if sys.platform == 'win32': - clang_libs_want = [ - '*.lib', - ] - else: - clang_libs_want = [ - '*.a', - ] - for lib_path in os.listdir(os.path.join(LLVM_BOOTSTRAP_DIR, 'lib')): - for lib_want in clang_libs_want: - if fnmatch.fnmatch(lib_path, lib_want): - shutil.copy(os.path.join(LLVM_BOOTSTRAP_DIR, 'lib', lib_path), - os.path.join(clang_libs_dir, 'lib')) - PackageInArchive(clang_libs_dir, clang_libs_dir) - MaybeUpload(args.upload, clang_libs_dir + '.t*z', gcs_platform) - if sys.platform == 'darwin': # dsymutil isn't part of the main zip, and it gets periodically # deployed to CIPD (manually, not as part of clang rolls) for use in the
diff --git a/tools/clang/scripts/update.py b/tools/clang/scripts/update.py index d3af79b..98563fd 100755 --- a/tools/clang/scripts/update.py +++ b/tools/clang/scripts/update.py
@@ -61,6 +61,10 @@ def RmTree(dir): """Delete dir.""" def ChmodAndRetry(func, path, _): + # Windows can fail here with file does not exist. Since we're deleting + # everything, we can just ignore this and continue. + if not os.path.exists(path): + return # Subversion can leave read-only files around. if not os.access(path, os.W_OK): os.chmod(path, stat.S_IWUSR) @@ -245,8 +249,7 @@ package_file = 'llvm-code-coverage' elif package_name == 'objdump': package_file = 'llvmobjdump' - elif package_name in ['clang-libs', 'clang-tidy', 'clangd', 'libclang', - 'translation_unit']: + elif package_name in ['clang-tidy', 'clangd', 'libclang', 'translation_unit']: package_file = package_name else: print('Unknown package: "%s".' % package_name)
diff --git a/tools/gritsettings/resource_ids.spec b/tools/gritsettings/resource_ids.spec index d672211..affd2440 100644 --- a/tools/gritsettings/resource_ids.spec +++ b/tools/gritsettings/resource_ids.spec
@@ -345,6 +345,10 @@ "META": {"sizes": {"includes": [500],}}, "includes": [1960], }, + "<(SHARED_INTERMEDIATE_DIR)/chrome/browser/resources/settings_shared/resources.grd": { + "META": {"sizes": {"includes": [20],}}, + "includes": [1970], + }, "<(SHARED_INTERMEDIATE_DIR)/chrome/browser/resources/signin/profile_picker/resources.grd": { "META": {"sizes": {"includes": [50],}}, "includes": [1980],
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl index c4de8e5..210b6d0 100644 --- a/tools/mb/mb_config.pyl +++ b/tools/mb/mb_config.pyl
@@ -517,8 +517,8 @@ 'Chromium iOS Goma RBE ToT': 'ios_device_release_compile_only', - 'chromeos-amd64-generic-rel-goma-rbe-staging': 'chromeos_amd64-generic_use_fake_dbus_clients_vm_optimized', - 'chromeos-amd64-generic-rel-goma-rbe-tot': 'chromeos_amd64-generic_use_fake_dbus_clients_vm_optimized', + 'chromeos-amd64-generic-rel-goma-rbe-staging': 'chromeos_amd64-generic_use_fake_dbus_clients_vm_optimized_goma', + 'chromeos-amd64-generic-rel-goma-rbe-tot': 'chromeos_amd64-generic_use_fake_dbus_clients_vm_optimized_goma', }, 'chromium.goma.fyi': { @@ -544,8 +544,8 @@ 'android-archive-dbg-goma-rbe-canary': 'android_without_codecs_debug_bot', 'android-archive-dbg-goma-rbe-latest': 'android_without_codecs_debug_bot', - 'chromeos-amd64-generic-rel-goma-rbe-canary': 'chromeos_amd64-generic_use_fake_dbus_clients_vm_optimized', - 'chromeos-amd64-generic-rel-goma-rbe-latest': 'chromeos_amd64-generic_use_fake_dbus_clients_vm_optimized', + 'chromeos-amd64-generic-rel-goma-rbe-canary': 'chromeos_amd64-generic_use_fake_dbus_clients_vm_optimized_goma', + 'chromeos-amd64-generic-rel-goma-rbe-latest': 'chromeos_amd64-generic_use_fake_dbus_clients_vm_optimized_goma', 'ios-device-goma-rbe-canary-clobber': 'ios_device_release_compile_only', 'ios-device-goma-rbe-latest-clobber': 'ios_device_release_compile_only', @@ -2047,7 +2047,7 @@ ], 'chromeos_amd64-generic_lacros_official': [ - 'chromeos_amd64-generic-crostoolchain', 'lacros', 'official', 'minimal_symbols', 'cfi', 'thin_lto', + 'chromeos_amd64-generic-crostoolchain', 'lacros', 'official', 'minimal_symbols', 'cfi', 'thin_lto', 'no_reclient', 'goma', ], # This is the same as chromeos_amd64-generic_lacros_official except @@ -2095,15 +2095,15 @@ 'chromeos_amd64-generic-crostoolchain_reclient', 'lacros', 'release', 'is_skylab', ], - 'chromeos_amd64-generic_use_fake_dbus_clients_vm_optimized': [ - 'chromeos_amd64-generic-vm', 'use_fake_dbus_clients', 'also_build_lacros_chrome_for_architecture_amd64', - ], - 'chromeos_amd64-generic_use_fake_dbus_clients_vm_optimized_dchecks_reclient': [ 'chromeos_amd64-generic-vm_reclient', 'use_fake_dbus_clients', 'dcheck_always_on', 'also_build_lacros_chrome_for_architecture_amd64', ], + 'chromeos_amd64-generic_use_fake_dbus_clients_vm_optimized_goma': [ + 'chromeos_amd64-generic-vm', 'use_fake_dbus_clients', 'also_build_lacros_chrome_for_architecture_amd64', 'goma', 'no_reclient', + ], + 'chromeos_arm-generic_cfi_thin_lto_official': [ 'chromeos_device', 'arm-generic', 'cfi_full', 'thin_lto', 'official', 'full_symbols', ], @@ -4033,7 +4033,7 @@ 'chromeos_device': { 'gn_args': 'is_chromeos_device=true ozone_platform_headless=true', - 'mixins': ['dcheck_off', 'goma'], + 'mixins': ['dcheck_off', 'reclient'], }, 'chromeos_device_reclient': {
diff --git a/tools/mb/mb_config_expectations/chrome.json b/tools/mb/mb_config_expectations/chrome.json index f64a491..4859852 100644 --- a/tools/mb/mb_config_expectations/chrome.json +++ b/tools/mb/mb_config_expectations/chrome.json
@@ -147,7 +147,7 @@ "is_official_build": true, "is_skylab": true, "ozone_platform_headless": true, - "use_goma": true + "use_remoteexec": true } }, "chromeos-reven-chrome": {
diff --git a/tools/mb/mb_config_expectations/chromium.goma.fyi.json b/tools/mb/mb_config_expectations/chromium.goma.fyi.json index d159bb46a..573c890 100644 --- a/tools/mb/mb_config_expectations/chromium.goma.fyi.json +++ b/tools/mb/mb_config_expectations/chromium.goma.fyi.json
@@ -202,7 +202,8 @@ "is_chromeos_device": true, "ozone_platform_headless": true, "use_goma": true, - "use_real_dbus_clients": false + "use_real_dbus_clients": false, + "use_remoteexec": false } }, "chromeos-amd64-generic-rel-goma-rbe-latest": { @@ -213,7 +214,8 @@ "is_chromeos_device": true, "ozone_platform_headless": true, "use_goma": true, - "use_real_dbus_clients": false + "use_real_dbus_clients": false, + "use_remoteexec": false } }, "ios-device-goma-rbe-canary-clobber": {
diff --git a/tools/mb/mb_config_expectations/chromium.goma.json b/tools/mb/mb_config_expectations/chromium.goma.json index 390ba1d..5b4f4b91 100644 --- a/tools/mb/mb_config_expectations/chromium.goma.json +++ b/tools/mb/mb_config_expectations/chromium.goma.json
@@ -203,7 +203,8 @@ "is_chromeos_device": true, "ozone_platform_headless": true, "use_goma": true, - "use_real_dbus_clients": false + "use_real_dbus_clients": false, + "use_remoteexec": false } }, "chromeos-amd64-generic-rel-goma-rbe-tot": { @@ -214,7 +215,8 @@ "is_chromeos_device": true, "ozone_platform_headless": true, "use_goma": true, - "use_real_dbus_clients": false + "use_real_dbus_clients": false, + "use_remoteexec": false } } } \ No newline at end of file
diff --git a/tools/mb/mb_config_expectations/tryserver.chrome.json b/tools/mb/mb_config_expectations/tryserver.chrome.json index a76c027..61a6eed 100644 --- a/tools/mb/mb_config_expectations/tryserver.chrome.json +++ b/tools/mb/mb_config_expectations/tryserver.chrome.json
@@ -10,7 +10,7 @@ "ozone_platform_headless": true, "symbol_level": 2, "use_cfi_cast": true, - "use_goma": true, + "use_remoteexec": true, "use_thin_lto": true } }, @@ -25,7 +25,7 @@ "ozone_platform_headless": true, "symbol_level": 2, "use_cfi_cast": true, - "use_goma": true, + "use_remoteexec": true, "use_thin_lto": true } }, @@ -39,8 +39,8 @@ "is_chromeos_device": true, "is_official_build": true, "ozone_platform_headless": true, - "use_goma": true, - "use_real_dbus_clients": false + "use_real_dbus_clients": false, + "use_remoteexec": true } }, "chromeos-betty-pi-arc-cfi-thin-lto-chrome": { @@ -55,7 +55,7 @@ "ozone_platform_headless": true, "symbol_level": 1, "use_cfi_cast": true, - "use_goma": true, + "use_remoteexec": true, "use_thin_lto": true } }, @@ -69,8 +69,8 @@ "is_chromeos_device": true, "is_official_build": true, "ozone_platform_headless": true, - "use_goma": true, - "use_real_dbus_clients": false + "use_real_dbus_clients": false, + "use_remoteexec": true } }, "chromeos-betty-pi-arc-chrome-dchecks": { @@ -83,8 +83,8 @@ "is_chromeos_device": true, "is_official_build": true, "ozone_platform_headless": true, - "use_goma": true, - "use_real_dbus_clients": false + "use_real_dbus_clients": false, + "use_remoteexec": true } }, "chromeos-betty-pi-arc-finch-smoke-chrome": { @@ -97,8 +97,8 @@ "is_chromeos_device": true, "is_official_build": true, "ozone_platform_headless": true, - "use_goma": true, - "use_real_dbus_clients": false + "use_real_dbus_clients": false, + "use_remoteexec": true } }, "chromeos-brya-chrome-skylab": { @@ -111,7 +111,7 @@ "is_official_build": true, "is_skylab": true, "ozone_platform_headless": true, - "use_goma": true + "use_remoteexec": true } }, "chromeos-eve-arc-r-chrome": { @@ -123,7 +123,7 @@ "is_chromeos_device": true, "is_official_build": true, "ozone_platform_headless": true, - "use_goma": true + "use_remoteexec": true } }, "chromeos-eve-chrome": { @@ -136,7 +136,7 @@ "is_chromeos_device": true, "is_official_build": true, "ozone_platform_headless": true, - "use_goma": true + "use_remoteexec": true } }, "chromeos-eve-compile-chrome": { @@ -149,7 +149,7 @@ "is_chromeos_device": true, "is_official_build": true, "ozone_platform_headless": true, - "use_goma": true + "use_remoteexec": true } }, "chromeos-jacuzzi-chrome": { @@ -162,7 +162,7 @@ "is_chromeos_device": true, "is_official_build": true, "ozone_platform_headless": true, - "use_goma": true + "use_remoteexec": true } }, "chromeos-jacuzzi-chrome-skylab": { @@ -187,7 +187,7 @@ "is_chromeos_device": true, "is_official_build": true, "ozone_platform_headless": true, - "use_goma": true + "use_remoteexec": true } }, "chromeos-kevin-chrome": { @@ -200,7 +200,7 @@ "is_chromeos_device": true, "is_official_build": true, "ozone_platform_headless": true, - "use_goma": true + "use_remoteexec": true } }, "chromeos-kevin-compile-chrome": { @@ -213,7 +213,7 @@ "is_chromeos_device": true, "is_official_build": true, "ozone_platform_headless": true, - "use_goma": true + "use_remoteexec": true } }, "chromeos-octopus-chrome": { @@ -226,7 +226,7 @@ "is_chromeos_device": true, "is_official_build": true, "ozone_platform_headless": true, - "use_goma": true + "use_remoteexec": true } }, "chromeos-octopus-chrome-skylab": { @@ -239,7 +239,7 @@ "is_official_build": true, "is_skylab": true, "ozone_platform_headless": true, - "use_goma": true + "use_remoteexec": true } }, "chromeos-octopus-compile-chrome": { @@ -252,7 +252,7 @@ "is_chromeos_device": true, "is_official_build": true, "ozone_platform_headless": true, - "use_goma": true + "use_remoteexec": true } }, "chromeos-reven-chrome": { @@ -265,7 +265,7 @@ "is_chromeos_device": true, "is_official_build": true, "ozone_platform_headless": true, - "use_goma": true + "use_remoteexec": true } }, "chromeos-trogdor-chrome-skylab": { @@ -278,7 +278,7 @@ "is_official_build": true, "is_skylab": true, "ozone_platform_headless": true, - "use_goma": true + "use_remoteexec": true } }, "chromeos-volteer-chrome-skylab": { @@ -291,7 +291,7 @@ "is_official_build": true, "is_skylab": true, "ozone_platform_headless": true, - "use_goma": true + "use_remoteexec": true } }, "lacros-amd64-generic-chrome": { @@ -306,7 +306,7 @@ "ozone_platform_headless": true, "symbol_level": 0, "target_os": "chromeos", - "use_goma": true, + "use_remoteexec": true, "use_thin_lto": true } }, @@ -323,7 +323,7 @@ "ozone_platform_headless": true, "symbol_level": 1, "target_os": "chromeos", - "use_goma": true, + "use_remoteexec": true, "use_thin_lto": true } }, @@ -340,7 +340,7 @@ "ozone_platform_headless": true, "symbol_level": 1, "target_os": "chromeos", - "use_goma": true, + "use_remoteexec": true, "use_thin_lto": true } }, @@ -357,7 +357,7 @@ "ozone_platform_headless": true, "symbol_level": 1, "target_os": "chromeos", - "use_goma": true, + "use_remoteexec": true, "use_thin_lto": true } },
diff --git a/tools/mb/mb_config_expectations/tryserver.chromium.chromiumos.json b/tools/mb/mb_config_expectations/tryserver.chromium.chromiumos.json index cd7a1488..cc6a305 100644 --- a/tools/mb/mb_config_expectations/tryserver.chromium.chromiumos.json +++ b/tools/mb/mb_config_expectations/tryserver.chromium.chromiumos.json
@@ -183,7 +183,7 @@ "is_skylab": true, "ozone_platform_headless": true, "target_os": "chromeos", - "use_goma": true + "use_remoteexec": true } }, "lacros-arm-generic-rel": {
diff --git a/tools/mb/mb_config_expectations/tryserver.chromium.perf.json b/tools/mb/mb_config_expectations/tryserver.chromium.perf.json index b761400..71c68b9a 100644 --- a/tools/mb/mb_config_expectations/tryserver.chromium.perf.json +++ b/tools/mb/mb_config_expectations/tryserver.chromium.perf.json
@@ -100,6 +100,7 @@ "symbol_level": 1, "target_os": "chromeos", "use_goma": true, + "use_remoteexec": false, "use_thin_lto": true } },
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index e3d87b5..09835e9 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -58473,7 +58473,6 @@ <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"/> @@ -58733,6 +58732,7 @@ <int value="-1752853388" label="OmniboxUIExperimentElideToRegistrableDomain:enabled"/> <int value="-1752118355" label="DesktopDetailedLanguageSettings:enabled"/> + <int value="-1752055359" label="AccessCodeCastFreezeUI:enabled"/> <int value="-1751928267" label="disable-icon-ntp"/> <int value="-1751562448" label="OmniboxExpandedStateColors:disabled"/> <int value="-1751492305" label="SupportTool:enabled"/> @@ -60822,6 +60822,7 @@ <int value="-639026783" label="disable-gpu-appcontainer"/> <int value="-638952203" label="RendererSideResourceScheduler:disabled"/> <int value="-638764080" label="EncryptedClientHello:disabled"/> + <int value="-638349846" label="OmniboxWarmRecycledViewPool:disabled"/> <int value="-638177392" label="FuseBoxDebug:enabled"/> <int value="-637297943" label="WebAuthenticationCableSecondFactor:disabled"/> <int value="-637215276" label="QuickAnswersOnEditableText:enabled"/> @@ -61180,7 +61181,6 @@ <int value="-438529902" label="CaptivePortalErrorPage:enabled"/> <int value="-438379844" label="SwapSideVolumeButtonsForOrientation:enabled"/> <int value="-438348502" label="LogUrlScoringSignals:disabled"/> - <int value="-438029951" label="RegionCaptureExperimentalSubtypes:enabled"/> <int value="-437292646" label="DeferBeginMainFrameDuringLoading:enabled"/> <int value="-436470115" label="TouchpadAndWheelScrollLatching:enabled"/> <int value="-435914745" label="ClipboardContentSetting:disabled"/> @@ -65562,6 +65562,7 @@ <int value="1949019439" label="AutofillRestrictUnownedFieldsToFormlessCheckout:disabled"/> <int value="1949156880" label="SyncRequiresPoliciesLoaded:enabled"/> + <int value="1949314084" label="OmniboxWarmRecycledViewPool:enabled"/> <int value="1949908940" label="disable-zip-archiver-unpacker"/> <int value="1949996482" label="CSSColorSchemeUARendering:disabled"/> <int value="1950191981" label="OverlayNewLayout:enabled"/> @@ -65751,6 +65752,7 @@ <int value="2058425230" label="LauncherNudgeSessionReset:enabled"/> <int value="2058439723" label="CalculateNativeWinOcclusion:disabled"/> <int value="2059322877" label="new-avatar-menu"/> + <int value="2062051946" label="AccessCodeCastFreezeUI:disabled"/> <int value="2062752242" label="ApnRevamp:enabled"/> <int value="2063091429" label="OfflinePagesSharing:enabled"/> <int value="2063238104" label="ContextMenuPopupForAllScreenSizes:enabled"/> @@ -104814,10 +104816,6 @@ <int value="4" label="TestExtension"/> </enum> -<enum name="UsedOmnibox"> - <int value="0" label="Used Omnibox"/> -</enum> - <enum name="UserActivationFrameResultEnum"> <obsolete> This was added to assess possible impact of UserActivationV2, by comparing
diff --git a/tools/metrics/histograms/metadata/download/histograms.xml b/tools/metrics/histograms/metadata/download/histograms.xml index e537a59..67ea718 100644 --- a/tools/metrics/histograms/metadata/download/histograms.xml +++ b/tools/metrics/histograms/metadata/download/histograms.xml
@@ -837,11 +837,6 @@ </summary> </histogram> -<histogram name="Download.OpensOutstanding" units="units" expires_after="M77"> - <owner>dtrainor@chromium.org</owner> - <summary>The number of unopened downloads, when one is opened.</summary> -</histogram> - <histogram name="Download.OverwrittenDownloadRemovedFromHistory" units="downloads" expires_after="2022-04-24"> <owner>qinmin@chromium.org</owner> @@ -939,48 +934,6 @@ </summary> </histogram> -<histogram name="Download.Resume.AutoResumeLimitReached" enum="Boolean" - expires_after="2021-01-10"> - <owner>shaktisahu@chromium.org</owner> - <owner>clank-downloads@google.com</owner> - <summary> - Records whenever max auto-resumption limit was reached for a download. - </summary> -</histogram> - -<histogram name="Download.Resume.AutoResumeLimitReached.LastReason" - enum="InterruptReason" expires_after="2021-01-10"> - <owner>shaktisahu@chromium.org</owner> - <owner>clank-downloads@google.com</owner> - <summary> - Records the last interrupt reason for this download when the download - reaches auto-resumption limit. - </summary> -</histogram> - -<histogram name="Download.Resume.LastReason" enum="InterruptReason" - expires_after="2021-01-03"> - <owner>shaktisahu@chromium.org</owner> - <owner>clank-downloads@google.com</owner> - <summary>Records the last interrupt reason for this download.</summary> -</histogram> - -<histogram name="Download.Resume.UserResume" enum="Boolean" - expires_after="2020-11-01"> - <owner>shaktisahu@chromium.org</owner> - <owner>clank-downloads@google.com</owner> - <summary>Records whether a resumption was due to user.</summary> -</histogram> - -<histogram name="Download.ResumptionRestart.Reason" enum="InterruptReason" - expires_after="2021-02-28"> - <owner>qinmin@chromium.org</owner> - <summary> - Records the interrupt reason when download is restarting from the beginning - during resumption. - </summary> -</histogram> - <histogram name="Download.Retry.InterruptReason" enum="InterruptReason" expires_after="2023-09-03"> <owner>thefrog@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/media/histograms.xml b/tools/metrics/histograms/metadata/media/histograms.xml index 489f736..7698865 100644 --- a/tools/metrics/histograms/metadata/media/histograms.xml +++ b/tools/metrics/histograms/metadata/media/histograms.xml
@@ -2124,7 +2124,7 @@ </histogram> <histogram name="Media.EME.CdmFileIO.FileSizeKBOnError" units="KB" - expires_after="2023-05-07"> + expires_after="2024-04-11"> <owner>xhwang@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> @@ -2135,7 +2135,7 @@ </histogram> <histogram name="Media.EME.CdmFileIO.FileSizeKBOnFirstRead" units="KB" - expires_after="2023-09-10"> + expires_after="2024-04-11"> <owner>xhwang@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> @@ -2145,7 +2145,7 @@ </histogram> <histogram name="Media.EME.CdmFileIO.TimeTo.{FileOperation}{IncognitoOrNormal}" - units="ms" expires_after="2023-05-07"> + units="ms" expires_after="2024-04-11"> <owner>jrummell@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> @@ -2157,7 +2157,7 @@ </histogram> <histogram name="Media.EME.CdmFileIO.{FileOperation}{IncognitoOrNormal}" - enum="BooleanSuccess" expires_after="2023-05-07"> + enum="BooleanSuccess" expires_after="2024-04-11"> <owner>jrummell@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> @@ -2169,7 +2169,7 @@ </histogram> <histogram name="Media.EME.CdmFileIO::OpenFile" enum="CdmStorageStatus" - expires_after="2023-09-10"> + expires_after="2024-04-11"> <owner>xhwang@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> @@ -2179,7 +2179,7 @@ </histogram> <histogram name="Media.EME.CdmHostVerificationStatus" - enum="CdmHostVerificationStatus" expires_after="2023-09-10"> + enum="CdmHostVerificationStatus" expires_after="2024-04-11"> <owner>xhwang@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> @@ -2188,7 +2188,7 @@ </histogram> <histogram name="Media.EME.CdmInterfaceVersion" enum="GenericEnum" - expires_after="2023-05-07"> + expires_after="2024-04-11"> <owner>xhwang@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> @@ -2199,7 +2199,7 @@ </histogram> <histogram name="Media.EME.CdmLoadErrorCode" enum="WinGetLastError" - expires_after="2023-08-13"> + expires_after="2024-04-11"> <owner>xhwang@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> @@ -2208,13 +2208,13 @@ </histogram> <histogram name="Media.EME.CdmLoadResult" enum="CdmLoadResult" - expires_after="2023-09-10"> + expires_after="2024-04-11"> <owner>xhwang@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary>The result from an attempt to load a library CDM.</summary> </histogram> -<histogram name="Media.EME.CdmLoadTime" units="ms" expires_after="2023-10-01"> +<histogram name="Media.EME.CdmLoadTime" units="ms" expires_after="2024-04-11"> <owner>xhwang@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary>The time spent to load a library CDM.</summary> @@ -2238,7 +2238,7 @@ </histogram> <histogram name="Media.EME.EncryptedEvent" enum="BooleanEncryptedEvent" - expires_after="2023-05-07"> + expires_after="2024-04-11"> <owner>xhwang@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> @@ -2251,7 +2251,7 @@ </histogram> <histogram name="Media.EME.EncryptedMediaEnabled" enum="BooleanEnabled" - expires_after="2023-09-10"> + expires_after="2024-04-11"> <owner>xhwang@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> @@ -2263,7 +2263,7 @@ </histogram> <histogram name="Media.EME.EncryptionScheme.Initial.Audio" - enum="MediaEncryptionScheme" expires_after="2023-05-07"> + enum="MediaEncryptionScheme" expires_after="2024-04-11"> <owner>jrummell@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> @@ -2273,7 +2273,7 @@ </histogram> <histogram name="Media.EME.EncryptionScheme.Initial.Video" - enum="MediaEncryptionScheme" expires_after="2023-05-07"> + enum="MediaEncryptionScheme" expires_after="2024-04-11"> <owner>jrummell@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> @@ -2283,7 +2283,7 @@ </histogram> <histogram name="Media.EME.IsIncognito" enum="BooleanIncognito" - expires_after="2023-05-07"> + expires_after="2024-04-11"> <owner>xhwang@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> @@ -2294,7 +2294,7 @@ </histogram> <histogram name="Media.EME.MediaCryptoAvailable" enum="BooleanAvailable" - expires_after="2023-05-07"> + expires_after="2024-04-11"> <owner>xhwang@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> @@ -2304,7 +2304,7 @@ </histogram> <histogram name="Media.EME.MediaDrm.GetOriginIdResult" enum="GetOriginIdResult" - expires_after="2023-05-07"> + expires_after="2024-04-11"> <owner>jrummell@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> @@ -2316,7 +2316,7 @@ <histogram name="Media.EME.MediaDrm.PreprovisionedOriginId.NonPerAppProvisioningDevice" - units="units" expires_after="2023-05-07"> + units="units" expires_after="2024-04-11"> <owner>jrummell@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> @@ -2327,7 +2327,7 @@ <histogram name="Media.EME.MediaDrm.PreprovisionedOriginId.PerAppProvisioningDevice" - units="units" expires_after="2023-05-07"> + units="units" expires_after="2024-04-11"> <owner>jrummell@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> @@ -2337,7 +2337,7 @@ </histogram> <histogram name="Media.EME.MediaDrmBridge.KeySystemSupport" - enum="BooleanSupported" expires_after="2023-05-07"> + enum="BooleanSupported" expires_after="2024-04-11"> <owner>xhwang@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> @@ -2347,7 +2347,7 @@ </histogram> <histogram name="Media.EME.MediaFoundationCdm.ActivateCdmFactory" - enum="Hresult" expires_after="2023-05-07"> + enum="Hresult" expires_after="2024-04-11"> <owner>sangbaekpark@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> @@ -2357,7 +2357,7 @@ </histogram> <histogram name="Media.EME.MediaFoundationCdm.LoadErrorCode" - enum="WinGetLastError" expires_after="2023-09-10"> + enum="WinGetLastError" expires_after="2024-04-11"> <owner>sangbaekpark@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> @@ -2366,7 +2366,7 @@ </histogram> <histogram name="Media.EME.MediaFoundationCdm.LoadResult" enum="CdmLoadResult" - expires_after="2023-09-10"> + expires_after="2024-04-11"> <owner>sangbaekpark@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> @@ -2375,7 +2375,7 @@ </histogram> <histogram name="Media.EME.MediaFoundationCdm.LoadTime" units="ms" - expires_after="2023-10-08"> + expires_after="2024-04-11"> <owner>sangbaekpark@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary>The time spent to load a library MediaFoundation CDM.</summary> @@ -2383,7 +2383,7 @@ <histogram name="Media.EME.MediaFoundationCdm.Widevine.HardwareSecure.FirstInitialize" - enum="Hresult" expires_after="2023-05-07"> + enum="Hresult" expires_after="2024-04-11"> <owner>xhwang@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> @@ -2395,7 +2395,7 @@ <histogram name="Media.EME.MediaFoundationCdm.Widevine.HardwareSecure.Initialize" - enum="Hresult" expires_after="2023-04-30"> + enum="Hresult" expires_after="2024-04-11"> <owner>xhwang@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> @@ -2405,7 +2405,7 @@ </histogram> <histogram name="Media.EME.MediaFoundationCdm.Widevine.HardwareSecure.{EmeApi}" - enum="Hresult" expires_after="2023-05-07"> + enum="Hresult" expires_after="2024-04-11"> <owner>xhwang@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> @@ -2416,7 +2416,7 @@ </histogram> <histogram name="Media.EME.MediaFoundationService.Crash2" - enum="BooleanAfterPowerOrDisplayChange" expires_after="2023-05-07"> + enum="BooleanAfterPowerOrDisplayChange" expires_after="2024-04-11"> <owner>xhwang@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> @@ -2428,7 +2428,7 @@ <histogram name="Media.EME.MediaFoundationService.ErrorAfterPowerOrDisplayChange2" - enum="Hresult" expires_after="2023-05-07"> + enum="Hresult" expires_after="2024-04-11"> <owner>xhwang@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> @@ -2439,7 +2439,7 @@ <histogram name="Media.EME.MediaFoundationService.ErrorNotAfterPowerOrDisplayChange2" - enum="Hresult" expires_after="2023-07-30"> + enum="Hresult" expires_after="2024-04-11"> <owner>xhwang@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> @@ -2449,7 +2449,7 @@ </histogram> <histogram name="Media.EME.MediaFoundationService.HardwareContextReset" - enum="BooleanAfterPowerOrDisplayChange" expires_after="2023-05-07"> + enum="BooleanAfterPowerOrDisplayChange" expires_after="2024-04-11"> <owner>xhwang@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> @@ -2460,7 +2460,7 @@ </histogram> <histogram name="Media.EME.MediaFoundationService.IsKeySystemSupported" - units="ms" expires_after="2023-10-08"> + units="ms" expires_after="2024-04-11"> <owner>xhwang@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> @@ -2471,7 +2471,7 @@ <histogram name="Media.EME.MediaFoundationService.Widevine.HardwareSecure.IsTypeSupported" - units="ms" expires_after="2023-08-20"> + units="ms" expires_after="2024-04-11"> <owner>xhwang@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> @@ -2529,7 +2529,7 @@ </histogram> <histogram name="Media.EME.MojoCdm.ConnectionError" - enum="BooleanConnectionError" expires_after="2023-09-10"> + enum="BooleanConnectionError" expires_after="2024-04-11"> <owner>xhwang@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> @@ -2541,7 +2541,7 @@ </histogram> <histogram name="Media.EME.OutputProtection" enum="MediaOutputProtectionStatus" - expires_after="2023-09-10"> + expires_after="2024-04-11"> <owner>xhwang@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> @@ -2561,7 +2561,7 @@ </histogram> <histogram name="Media.EME.RequestMediaKeySystemAccess.{KeySystem}" - enum="RequestMediaKeySystemAccessStatus" expires_after="2023-05-07"> + enum="RequestMediaKeySystemAccessStatus" expires_after="2024-04-11"> <owner>xhwang@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> @@ -2573,7 +2573,7 @@ </histogram> <histogram name="Media.EME.UrlProvisionFetcher.ResponseCode" - enum="CombinedHttpResponseAndNetErrorCode" expires_after="2023-09-10"> + enum="CombinedHttpResponseAndNetErrorCode" expires_after="2024-04-11"> <owner>jrummell@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> @@ -2583,7 +2583,7 @@ </histogram> <histogram name="Media.EME.Widevine.HardwareSecure.CdmInfoStatus" - enum="CdmInfoStatus" expires_after="2023-08-13"> + enum="CdmInfoStatus" expires_after="2024-04-11"> <owner>xhwang@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> @@ -2594,7 +2594,7 @@ <histogram name="Media.EME.Widevine.HardwareSecure.ClearLeadSupport.{VideoCodec}" - enum="BooleanSupported" expires_after="2024-08-05"> + enum="BooleanSupported" expires_after="2024-04-11"> <owner>vpasupathy@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> @@ -2607,7 +2607,7 @@ </histogram> <histogram name="Media.EME.Widevine.HardwareSecure.Pref" enum="BooleanEnabled" - expires_after="2023-10-08"> + expires_after="2024-04-11"> <owner>xhwang@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> @@ -2619,7 +2619,7 @@ </histogram> <histogram name="Media.EME.Widevine.HardwareSecure.Support" - enum="BooleanSupported" expires_after="2023-09-17"> + enum="BooleanSupported" expires_after="2024-04-11"> <owner>xhwang@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> @@ -2631,7 +2631,7 @@ </histogram> <histogram name="Media.EME.Widevine.HardwareSecure.Support.{VideoCodec}" - enum="BooleanSupported" expires_after="2023-05-07"> + enum="BooleanSupported" expires_after="2024-04-11"> <owner>xhwang@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> @@ -2644,7 +2644,7 @@ </histogram> <histogram name="Media.EME.Widevine.SoftwareSecure.SystemCode" - enum="CdmSystemCode" expires_after="2023-09-10"> + enum="CdmSystemCode" expires_after="2024-04-11"> <owner>xhwang@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> @@ -2654,7 +2654,7 @@ </histogram> <histogram name="Media.EME.Widevine.VideoCapability.HasEmptyRobustness" - enum="BooleanEmpty" expires_after="2023-10-01"> + enum="BooleanEmpty" expires_after="2024-04-11"> <owner>xhwang@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> @@ -2665,7 +2665,7 @@ </histogram> <histogram name="Media.EME.{KeySystem}.CreateCdm" enum="BooleanSuccess" - expires_after="2023-05-07"> + expires_after="2024-04-11"> <owner>xhwang@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> @@ -2677,7 +2677,7 @@ </histogram> <histogram name="Media.EME.{KeySystem}.CreateCdmTime" units="ms" - expires_after="2023-05-07"> + expires_after="2024-04-11"> <owner>xhwang@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary>Time took to create the CDM instance for {KeySystem}.</summary> @@ -2685,7 +2685,7 @@ </histogram> <histogram name="Media.EME.{KeySystem}.CreateSession.SessionType" - enum="EmeSessionType" expires_after="2023-05-07"> + enum="EmeSessionType" expires_after="2024-04-11"> <owner>xhwang@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary>EME session type passed into CreateSession.</summary> @@ -2693,7 +2693,7 @@ </histogram> <histogram name="Media.EME.{KeySystem}.GenerateRequest.MojoCdmTimeout" - enum="CallbackTimeoutStatus" expires_after="2023-05-07"> + enum="CallbackTimeoutStatus" expires_after="2024-04-11"> <owner>xhwang@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> @@ -2703,7 +2703,7 @@ </histogram> <histogram name="Media.EME.{KeySystem}.KeyStatusSystemCode" - enum="CdmSystemCode" expires_after="2023-05-07"> + enum="CdmSystemCode" expires_after="2024-04-11"> <owner>xhwang@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary>System code associated with key status for {KeySystem}.</summary> @@ -2711,7 +2711,7 @@ </histogram> <histogram name="Media.EME.{KeySystem}.LibraryCdmAvailable" - enum="BooleanAvailable" expires_after="2023-05-07"> + enum="BooleanAvailable" expires_after="2024-04-11"> <owner>xhwang@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> @@ -2724,7 +2724,7 @@ </histogram> <histogram name="Media.EME.{KeySystem}.TimeTo{ResolveOrReject}.{EmeApi}" - units="ms" expires_after="2023-05-07"> + units="ms" expires_after="2024-04-11"> <owner>xhwang@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary>The time it takes to {ResolveOrReject} a EME promise.</summary> @@ -2734,7 +2734,7 @@ </histogram> <histogram name="Media.EME.{KeySystem}.{EmeApi}" enum="CdmPromiseResult" - expires_after="2023-05-07"> + expires_after="2024-04-11"> <owner>xhwang@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary>Result of EME promises that were handled by Chromium code.</summary> @@ -2743,7 +2743,7 @@ </histogram> <histogram name="Media.EME.{KeySystem}.{EmeApi}.SystemCode" - enum="CdmSystemCode" expires_after="2023-05-07"> + enum="CdmSystemCode" expires_after="2024-04-11"> <owner>xhwang@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary>System code in promise rejection.</summary> @@ -3285,7 +3285,7 @@ </histogram> <histogram name="Media.LoadType" enum="MediaLoadType" - expires_after="2023-05-07"> + expires_after="2024-04-11"> <owner>xhwang@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> @@ -3523,7 +3523,7 @@ </histogram> <histogram name="Media.MediaFoundationRenderer.CreateMediaEngineError" - enum="Hresult" expires_after="2023-04-30"> + enum="Hresult" expires_after="2024-04-11"> <owner>xhwang@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> @@ -3532,7 +3532,7 @@ </histogram> <histogram name="Media.MediaFoundationRenderer.ErrorReason" - enum="MediaFoundationRendererErrorReason" expires_after="2023-05-07"> + enum="MediaFoundationRendererErrorReason" expires_after="2024-04-11"> <owner>xhwang@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> @@ -3542,7 +3542,7 @@ </histogram> <histogram name="Media.MediaFoundationRenderer.FailedToSetDCompMode" - enum="Hresult" expires_after="2023-05-07"> + enum="Hresult" expires_after="2024-04-11"> <owner>xhwang@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> @@ -3553,7 +3553,7 @@ <histogram name="Media.MediaFoundationRenderer.InvalidHwdrmState.HasReportedPlaying" - enum="Boolean" expires_after="2023-08-13"> + enum="Boolean" expires_after="2024-04-11"> <owner>xhwang@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> @@ -3564,7 +3564,7 @@ <histogram name="Media.MediaFoundationRenderer.InvalidHwdrmState.VideoFrameDecoded" - units="frames" expires_after="2023-08-13"> + units="frames" expires_after="2024-04-11"> <owner>xhwang@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> @@ -3574,7 +3574,7 @@ </histogram> <histogram name="Media.MediaFoundationRenderer.PlaybackError" enum="Hresult" - expires_after="2023-09-17"> + expires_after="2024-04-11"> <owner>xhwang@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> @@ -5706,7 +5706,7 @@ </histogram> <histogram name="Media.VideoHeight.Initial.{PlaybackType}" units="pixels" - expires_after="2023-05-07"> + expires_after="2024-04-11"> <owner>xhwang@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/mobile/histograms.xml b/tools/metrics/histograms/metadata/mobile/histograms.xml index f452cd9..7eb903a 100644 --- a/tools/metrics/histograms/metadata/mobile/histograms.xml +++ b/tools/metrics/histograms/metadata/mobile/histograms.xml
@@ -644,16 +644,6 @@ </summary> </histogram> -<histogram name="MobileDownload.Background.TargetDeterminationResult" - enum="MobileDownloadBackgroundTargetDeterminationResult" - expires_after="2020-12-13"> - <owner>qinmin@chromium.org</owner> - <summary> - Android: Records the target determination result for downloads started in - the background, that is, while the browser process is not running. - </summary> -</histogram> - <histogram name="MobileDownload.DownloadLaterPromptStatus" enum="DownloadLaterPromptStatus" expires_after="2023-02-06"> <owner>shaktisahu@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/omnibox/histograms.xml b/tools/metrics/histograms/metadata/omnibox/histograms.xml index 2c76aa6..284fd42 100644 --- a/tools/metrics/histograms/metadata/omnibox/histograms.xml +++ b/tools/metrics/histograms/metadata/omnibox/histograms.xml
@@ -1238,22 +1238,6 @@ variants="OmniboxAutocompleteUpdateSlice"/> </histogram> -<histogram name="Omnibox.NumEvents" enum="UsedOmnibox" - expires_after="2023-09-17"> - <owner>jdonnelly@chromium.org</owner> - <owner>mpearson@chromium.org</owner> - <owner>chrome-omnibox-team@google.com</owner> - <improvement direction="HIGHER_IS_BETTER"/> - <summary> - The number of times users used the omnibox to go somewhere. - - In M-74 and earlier, this was only recorded if the user had no incognito - windows open. In M-75 and later, it records all omnibox interactions - regardless, in order to be consistent with how user actions and histograms - are handled. - </summary> -</histogram> - <histogram name="Omnibox.NumTypedTerms" units="terms" expires_after="2023-08-20"> <owner>jdonnelly@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/others/histograms.xml b/tools/metrics/histograms/metadata/others/histograms.xml index cc6ec047..02515bb 100644 --- a/tools/metrics/histograms/metadata/others/histograms.xml +++ b/tools/metrics/histograms/metadata/others/histograms.xml
@@ -6180,6 +6180,17 @@ </summary> </histogram> +<histogram name="FirstPartySets.NavigationThrottle.ResumeDelta" units="ms" + expires_after="M124"> + <owner>shuuran@google.com</owner> + <owner>kaustubhag@google.com</owner> + <summary> + Measures the length of time between when a navigation was deferred and then + resumed due to timeout or First-Party Sets is ready. Recorded when a + deferred navigation is resumed. + </summary> +</histogram> + <histogram name="FirstPartySets.NavigationThrottle.ResumeOnTimeout" enum="BooleanTimedOut" expires_after="2023-08-20"> <owner>shuuran@google.com</owner>
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json index 98e1ef1..8cd1137d 100644 --- a/tools/perf/core/perfetto_binary_roller/binary_deps.json +++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -5,24 +5,24 @@ "full_remote_path": "perfetto-luci-artifacts/adbbb6c78e3a86c5e87b0338d9e42eb6b4ddbf4d/linux-arm64/trace_processor_shell" }, "win": { - "hash": "daedf5a7cc393fcae54504ad1e553bbaa6df7865", - "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/1c46d9577664f7cd811b4fe9c884f66a99697615/trace_processor_shell.exe" + "hash": "0e2a4c41d5003056f639665381c5cf0f03511e89", + "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/b57a685175d3070783d25958e0851b8d077b6280/trace_processor_shell.exe" }, "linux_arm": { "hash": "1d229abc94dea54ab4bb4327e78e18f942d08bf9", "full_remote_path": "perfetto-luci-artifacts/adbbb6c78e3a86c5e87b0338d9e42eb6b4ddbf4d/linux-arm/trace_processor_shell" }, "mac": { - "hash": "75f30b60b6f93968be7e00e147841d6c2a450fa2", - "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/mac/1c46d9577664f7cd811b4fe9c884f66a99697615/trace_processor_shell" + "hash": "40fdad52d21c168aec843968a05c75aa6b9f1ef2", + "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/mac/b57a685175d3070783d25958e0851b8d077b6280/trace_processor_shell" }, "mac_arm64": { "hash": "7a4026b8718994145a52586fdec6e9447573345a", "full_remote_path": "perfetto-luci-artifacts/adbbb6c78e3a86c5e87b0338d9e42eb6b4ddbf4d/mac-arm64/trace_processor_shell" }, "linux": { - "hash": "da16e9da095315beeb331c2736f4933b48938dbe", - "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/fe416a62fd4b3a04c0efa38dcfe365fd1611ae6d/trace_processor_shell" + "hash": "6cea21590b19ec403a0565b70a99d26c63cc0d89", + "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/d4f6e083e11e78c7370e0ce938be04c5d556cb0f/trace_processor_shell" } }, "power_profile.sql": {
diff --git a/tools/rust/README.md b/tools/rust/README.md index 9f8155db..1997149 100644 --- a/tools/rust/README.md +++ b/tools/rust/README.md
@@ -21,198 +21,64 @@ ## Rust build overview -Each Rust package is built from an official Rust nightly source release and a -corresponding LLVM revision. Hence a new Rust package must be built whenever -either Rust or Clang is updated. +Each Rust package is built from an Rust git, usually from HEAD directly, along +with the current Clang/LLVM revision in use in Chromium. Hence a new Rust +package must be built whenever either Rust or Clang is updated. When building +Rust we also build additional tools such as clippy and rustfmt, and interop +tools including bindgen and crubit. -Chromium's Clang build process leaves behind several artifacts needed for the -Rust build. Each Rust build begins after a Clang build and uses these artifacts, -which include `clang`, LLVM libraries, etc. +The Rust build also includes building LLVM for rustc to use, and Clang for +bindgen and crubit to use. -A special CI job is used to build Clang and Rust from the revisions specified in -the Chromium source tree. These are uploaded to a storage bucket. After being -manually blessed by a developer, they can then be fetched by Chromium checkouts. +The `*_upload_clang` and `*_upload_rust` trybots are used to build Clang and +Rust respectively from the revisions specified in the Chromium source tree. +These are uploaded to a storage bucket when the build succeeds. After being +copied from staging to production by a developer (see +[cs/copy_staging_to_prod_and_goma.sh]( +http://cs/copy_staging_to_prod_and_goma.sh)), they can then be fetched by +`gclient sync`. -Scripts are provided in tree to fetch the packages for the specified revisions. +The `update_rust.py` script is used by `gclient sync` to fetch the Rust +toolchain for the revisions specified in the script. -Whenever a Chromium checkout is updated, `gclient` hooks will update the -toolchain packages to match the revisions listed in tree. +## Rolling Rust +Follow the directions in [//docs/updating_clang.md]( +../../docs/updating_clang.md) to roll Clang and Rust together. To just +roll Rust on its own, use the `--skip-clang` argument when running +`upload_revision.py`. -## Updating Rust +The upload_revision.py script will update the revision of Rust to be +built and used in `update_rust.py` and will start the trybots that +will build the Rust toolchain. -### Set the revision +After the build has succeeded and the new toolchain has been copied to +production, the CQ will run trybots to verify that our code still builds +and tests pass with the new Rust toolchain. -First, pick a new instance of the [CIPD `rust_src` -package](https://chrome-infra-packages.appspot.com/p/chromium/third_party/rust_src/+/). -Click it and copy the version ID (e.g. `version:2@2022-01-01`) to the `//DEPS` entry for -`src/third_party/rust_src/src`. For example (though don't change the other parts -of the entry): +### Possible failure: Missing dependencies -``` - 'src/third_party/rust_src/src': { - 'packages': [ - { - 'package': 'chromium/third_party/rust_src', - 'version': 'version:2@2022-01-01', - }, - ], - # ... - }, -``` +`build_rust.py` will vendor all dependencies before starting the build. To do +this it first initializes git submodules. Then it runs `cargo vendor`. However +some parts of the compiler build are excluded from the top level Cargo.toml +workspace. Thus it passes `--sync dir` for a number of subdirectories, based +on [dist.rs, the nightly tarball packager]( +https://github.com/rust-lang/rust/blob/master/src/bootstrap/dist.rs#L986-L995). -Similarly, update the `RUST_REVISION` named in `//tools/rust/update_rust.py`, -removing dashes from the date (e.g. `version:2@2022-01-01` becomes -`RUST_REVISION = '20220101'`). Reset `RUST_SUB_REVISION = 1`. +If another Cargo.toml is required in the future, and not part of the workspace +it would produce missing dependencies, and the set of directories in +`build_rust.py` would need to be updated. -Run the following to check for changes to Rust's `src/stage0.json`, which -contains revisions of upstream binaries to be fetched and used in the Rust -build: +### Local development -``` -tools/rust/build_rust.py --verify-stage0-hash -``` +To build the Rust toolchain locally, run `//tools/rust/build_rust.py`. It +has additional flags to skip steps if you're making local changes and want +to retry a build. The script will produce its outputs in +`//third_party/rust-toolchain/`, which is the same place that `gclient sync` +places them. -If it exists without printing anything, the stage0 hash is up-to-date and -nothing needs to be done. Otherwise, it will print the actual hash like so: - -``` -... -Actual hash: 6b1c61d494ad447f41c8ae3b9b3239626eecac00e0f0b793b844e0761133dc37 -... -``` - -...in which case you should check the `stage0.json` changes for trustworthiness -(criteria TBD) and then update `STAGE0_JSON_SHA256` in update_rust.py with the -new hash. Re-run the above and confirm it succeeds. - - -### Optional: build locally and run tests - -This step is not strictly necessary since the CI tooling will catch any errors. -But the CI build process is slow and this can save some time. - -To fetch the new Rust sources, and avoid errors during `gclient sync`: -1. Ensure your `.gclient` file has `checkout_rust_toolchain_deps` set to `True`, -but avoid setting `use_rust` to `True`. The latter will try to download the -compiled rustc but as you've just updated the version there is no compiled rustc -to download so it will fail. -1. Additionally, to aid in testing, turn off rust support in GN, with -`enable_rust = false`, since it requires the presence of a Rust toolchain, but -building the toolchain destroys your local toolchain until the build succeeds. - -Running this will do a full build and provide a local toolchain that works for -the host machine, albeit not the same as the CI-provided one: - -``` -tools/rust/build_rust.py --fetch-llvm-libs --use-final-llvm-build-dir -``` - -To do a full build, first build Clang locally (TODO: provide instructions) then -simply run `tools/rust/build_rust.py` with no arguments. - -However, for most cases simply doing - -``` -tools/rust/build_rust.py --fetch-llvm-libs --use-final-llvm-build-dir --run-xpy -- build --stage 1 library/std -``` - -will catch most errors and will be fast. - -### Upload CL - -Run `tools/clang/scripts/upload_revision.py` to roll Clang and Rust to the -latest revision. It will update `//DEPS` and `/tools/rust/update_rust.py` with -new Rust version info, upload a CL to gerrit, and start tryjobs to build the -toolchain. - -See [//docs/updating_clang.md](../../docs/updating_clang.md) for more info -on to roll Clang and Rust. - -To roll Rust only, (make sure you are synced to HEAD and) pass the current Clang -version to `tools/clang/scripts/upload_revision.py`, as: -``` -tools/clang/scripts/upload_revision.py --clang-git-hash HASH --clang-sub-revision SUBREV -``` - -The `HASH` and `SUBREV` can be found from: -``` -# HASH -grep ^CLANG_REVISION tools/clang/scripts/update.py | sed -E 's/.*-g([0-9a-z]+).*/\1/' -# SUBREV -grep ^CLANG_SUB_REVISION tools/clang/scripts/update.py | sed -E 's/.*([0-9a-z]+).*/\1/' -``` - -If you want to use an older version of Rust, use `cipd` to find the version -you want to use. - -To find all instances of the Rust toolchain sources available: -``` -cipd instances chromium/third_party/rust_src -``` - -This will output something like: -``` -Instance ID │ Timestamp │ Uploader │ Refs -───────────────────────────────────────────────────────────────────────────────────────────────────────────────────── -6fLkoaoLWCFzVUlkhDevcLHj18bTXF5DxSCQTtNTJaMC │ Dec 15 06:16 EST 2022 │ chromium-cipd-builder@... │ latest -ohKW73PweFtV25O9vCbRzZoF1nxHGfurbLc0NWV2io8C │ Dec 14 06:13 EST 2022 │ chromium-cipd-builder@... │ -J6zeUMnPfukyu5fo0NFdAH6w9HEDyJzo1D0YhrP15bcC │ Dec 13 06:10 EST 2022 │ chromium-cipd-builder@... │ -pd-8U_6sH8y0dUwfFNUqKcu9GkMYnZmE2e6dOVG7ONUC │ Dec 12 06:12 EST 2022 │ chromium-cipd-builder@... │ -``` - -From here, you may get the version info for an intance with: -``` -cipd describe chromium/third_party/rust_src -version INSTANCE_ID -``` - -With `INSTANCE_ID` as `ohKW73PweFtV25O9vCbRzZoF1nxHGfurbLc0NWV2io8C`, the -describe output looks something like: -``` -Package: chromium/third_party/rust_src -Instance ID: ohKW73PweFtV25O9vCbRzZoF1nxHGfurbLc0NWV2io8C -Tags: - version:2@2022-12-14 -``` - -The Rust toolchain version is what comes after `version:` in the tags. In this -case, it would be `2@2022-12-14`. - -Then, pass this version to `tools/clang/scripts/upload_revision.py` as in: -``` -tools/clang/scripts/upload_revision.py --rust-cipd-version 2@2022-12-14 -``` - -This will generate a patch and upload it to Gerrit with the specified Rust -toolchain version. - -### Verify that Rust compiled - -The `tools/clang/scripts/upload_revision.py` starts builders that will compile -Clang and Rust. At this time, the builders succeed **even if Rust failed**. To -see if Rust did compile, check the build page (e.g. -https://ci.chromium.org/ui/p/chromium/builders/try/linux_upload_clang/2611/overview) -and confirm the "package rust" step succeeded. If it did not, further -investigation is needed. - -### Upload to production - -After the package is built, a developer with permissions must copy the uploaded -(Clang and) Rust packages from staging to production, in order for `gclient -sync` to find them. This must be done before submitting the CL or it will break -`gclient sync` for all Rust users. As of writing, anyone in [Clang -OWNERS](/tools/clang/scripts/OWNERS) or collinbaker@chromium.org can perform -this task. - -### Submit CL - -Once the package has been uploaded to production (see above), it is ready to be -fetched from any Chromium checkout. - -Submit the CL. CQ tryjobs will use the specified toolchain package -version. Any build failures will need to be investigated, as these indicate -breaking changes to Rust. - +Building the `rust_build_tests` GN target is a good way to quickly verify the +toolchain is working. ## Rolling Crubit tools @@ -232,19 +98,10 @@ be made obsolete once Rust-specific tryjobs cover Crubit tests. - -## Building and testing the tools locally +## Building and testing Crubit locally ### Prerequisites -#### LLVM/Clang build - -`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). - #### Bazel `build_crubit.py` depends on Bazel. @@ -267,19 +124,13 @@ ] ``` -#### Supported host platforms - -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`. +Just run `tools/rust/build_crubit.py`. So far `build_crubit.py` has only been +tested on Linux hosts. ### Deploying -`build_rust.py` by default copies the newly build executables/binaries into -`//third_party/rust-toolchain`. - `build_crubit.py` will copy files into the directory specified in the (optional) `--install-to` cmdline parameter - for example: @@ -289,29 +140,8 @@ ### 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. - -## Possible Failures - -### Missing dependencies - -`build_rust.py` will vendor all dependencies before starting the build. To do -this it first initializes git submodules. Then it runs `cargo vendor`. However -some parts of the compiler build are excluded from the top level Cargo.toml -workspace. Thus it passes `--sync dir` for a number of subdirectories, based -on [dist.rs, the nightly tarball packager]( -https://github.com/rust-lang/rust/blob/master/src/bootstrap/dist.rs#L986-L995). - -If another Cargo.toml is required in the future, and not part of the workspace -it would produce missing dependencies, and the set of directories in -`build_rust.py` would need to be updated.
diff --git a/tools/rust/build_rust.py b/tools/rust/build_rust.py index bfef494..6c4df5f 100755 --- a/tools/rust/build_rust.py +++ b/tools/rust/build_rust.py
@@ -534,7 +534,6 @@ sys.executable, os.path.join(CLANG_SCRIPTS_DIR, 'build.py'), '--disable-asserts', - # TODO(danakj): '--no-clang', '--no-tools', '--with-ml-inliner-model=', ]
diff --git a/ui/accessibility/ax_position.h b/ui/accessibility/ax_position.h index af0a50ab7..dd78fdd 100644 --- a/ui/accessibility/ax_position.h +++ b/ui/accessibility/ax_position.h
@@ -3745,6 +3745,11 @@ return 0; return absl::nullopt; } + // Valid positions are required for comparison. Use `AsValidPosition` + // or `SnapToMaxTextOffsetIfBeyond` before calling `CompareTo` or making + // comparisons. + DCHECK(IsValid()); + DCHECK(other.IsValid()); if (GetAnchor() == other.GetAnchor()) return SlowCompareTo(other); // No optimization is necessary.
diff --git a/ui/accessibility/platform/ax_platform_node_textprovider_win.cc b/ui/accessibility/platform/ax_platform_node_textprovider_win.cc index eb169b8..831ea2a7 100644 --- a/ui/accessibility/platform/ax_platform_node_textprovider_win.cc +++ b/ui/accessibility/platform/ax_platform_node_textprovider_win.cc
@@ -89,9 +89,11 @@ DCHECK(!start->IsNullPosition()); DCHECK(!end->IsNullPosition()); - // Reverse start and end if the selection goes backwards - if (*start > *end) + start->SnapToMaxTextOffsetIfBeyond(); + end->SnapToMaxTextOffsetIfBeyond(); + if (*start > *end) { std::swap(start, end); + } Microsoft::WRL::ComPtr<ITextRangeProvider> text_range_provider = AXPlatformNodeTextRangeProviderWin::CreateTextRangeProvider(
diff --git a/ui/accessibility/platform/ax_platform_node_textprovider_win_unittest.cc b/ui/accessibility/platform/ax_platform_node_textprovider_win_unittest.cc index 2112a48..8d9b073 100644 --- a/ui/accessibility/platform/ax_platform_node_textprovider_win_unittest.cc +++ b/ui/accessibility/platform/ax_platform_node_textprovider_win_unittest.cc
@@ -673,6 +673,73 @@ text_edit_provider->GetSelection(selections.Receive())); } +TEST_F(AXPlatformNodeTextProviderTest, + TestRemoveTextInvalidatingPositionForComparison) { + TestAXTreeUpdate initial_state(std::string(R"HTML( + ++1 kRootWebArea + ++++2 kStaticText name="aaa" + ++++++3 kInlineTextBox name="aaa" + )HTML")); + + Init(initial_state); + + ComPtr<IRawElementProviderSimple> root_node = + GetRootIRawElementProviderSimple(); + + ComPtr<ITextProvider> root_text_provider; + EXPECT_HRESULT_SUCCEEDED( + root_node->GetPatternProvider(UIA_TextPatternId, &root_text_provider)); + + ComPtr<AXPlatformNodeTextProviderWin> root_platform_node; + root_text_provider->QueryInterface(IID_PPV_ARGS(&root_platform_node)); + + base::win::ScopedSafearray selections; + AXPlatformNodeWin* owner = GetOwner(root_platform_node.Get()); + AXTreeData& selected_tree_data = + const_cast<AXTreeData&>(owner->GetDelegate()->GetTreeData()); + selected_tree_data.sel_focus_object_id = 2; + selected_tree_data.sel_anchor_object_id = 2; + selected_tree_data.sel_anchor_offset = 0; + selected_tree_data.sel_focus_offset = 3; + + root_text_provider->GetSelection(selections.Receive()); + ASSERT_NE(nullptr, selections.Get()); + + LONG index = 0; + ComPtr<ITextRangeProvider> text_range_provider; + EXPECT_HRESULT_SUCCEEDED(SafeArrayGetElement( + selections.Get(), &index, static_cast<void**>(&text_range_provider))); + SetOwner(owner, text_range_provider.Get()); + + base::win::ScopedBstr text_content; + EXPECT_HRESULT_SUCCEEDED( + text_range_provider->GetText(-1, text_content.Receive())); + EXPECT_EQ(0, wcscmp(text_content.Get(), L"aaa")); + + selections.Reset(); + text_range_provider.Reset(); + text_content.Reset(); + + AXTreeUpdate update; + update.nodes.resize(2); + update.nodes[0] = initial_state.nodes[1]; + update.nodes[0].SetName("aa"); + update.nodes[1] = initial_state.nodes[2]; + update.nodes[1].SetName("aa"); + ASSERT_TRUE(GetTree()->Unserialize(update)); + + root_text_provider->GetSelection(selections.Receive()); + ASSERT_NE(nullptr, selections.Get()); + + EXPECT_HRESULT_SUCCEEDED(SafeArrayGetElement( + selections.Get(), &index, static_cast<void**>(&text_range_provider))); + SetOwner(owner, text_range_provider.Get()); + + EXPECT_HRESULT_SUCCEEDED( + text_range_provider->GetText(-1, text_content.Receive())); + EXPECT_EQ(0, wcscmp(text_content.Get(), L"aa")); +} + TEST_F(AXPlatformNodeTextProviderTest, ITextProviderGetActiveComposition) { TestAXTreeUpdate update(std::string(R"HTML( ++1 kRootWebArea name="Document"
diff --git a/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.cc b/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.cc index df6bfb6..06774c4 100644 --- a/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.cc +++ b/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.cc
@@ -915,12 +915,14 @@ if (this_endpoint == TextPatternRangeEndpoint_Start) { SetStart(other_provider_endpoint->Clone()); - if (*start() > *end()) + if (*start() > *end()) { SetEnd(start()->Clone()); + } } else { SetEnd(other_provider_endpoint->Clone()); - if (*start() > *end()) + if (*start() > *end()) { SetStart(end()->Clone()); + } } return S_OK; } @@ -1758,6 +1760,28 @@ ax_tree_manager->ax_tree()->RemoveObserver(this); } +void AXPlatformNodeTextRangeProviderWin::TextRangeEndpoints:: + OnStringAttributeChanged(AXTree* tree, + AXNode* node, + ax::mojom::StringAttribute attr, + const std::string& old_value, + const std::string& new_value) { + if (attr != ax::mojom::StringAttribute::kName || + new_value.length() >= old_value.length()) { + return; + } + if (!start_->IsNullPosition() && + start_->tree_id() == node->tree()->GetAXTreeID() && + start_->anchor_id() == node->id()) { + start_->SnapToMaxTextOffsetIfBeyond(); + } + if (!end_->IsNullPosition() && + end_->tree_id() == node->tree()->GetAXTreeID() && + end_->anchor_id() == node->id()) { + end_->SnapToMaxTextOffsetIfBeyond(); + } +} + // Ensures that our endpoints are located on non-deleted nodes (step 1, case A // and B). See comment in header file for more details. void AXPlatformNodeTextRangeProviderWin::TextRangeEndpoints:: @@ -1849,6 +1873,8 @@ // normalizing above. If we don't set the opposite endpoint to something that // we know will be safe (i.e. not in a deleted subtree) we'll crash later on // when trying to create a valid position. + other_endpoint->SnapToMaxTextOffsetIfBeyond(); + new_endpoint->SnapToMaxTextOffsetIfBeyond(); if (is_start_endpoint) { if (*other_endpoint < *new_endpoint) SetEnd(new_endpoint->Clone());
diff --git a/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.h b/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.h index d1e0e216..aedc2fc 100644 --- a/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.h +++ b/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.h
@@ -265,6 +265,11 @@ void AddObserver(const AXTreeID tree_id); void RemoveObserver(const AXTreeID tree_id); + void OnStringAttributeChanged(AXTree* tree, + AXNode* node, + ax::mojom::StringAttribute attr, + const std::string& old_value, + const std::string& new_value) override; void OnSubtreeWillBeDeleted(AXTree* tree, AXNode* node) override; void OnNodeDeleted(AXTree* tree, AXNodeID node_id) override; void OnTreeManagerWillBeRemoved(AXTreeID previous_tree_id) override;
diff --git a/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc b/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc index d888d02..a5eef51 100644 --- a/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc +++ b/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc
@@ -6189,7 +6189,10 @@ ExpectPositionsEqual(original_end, GetEnd(text_range)); EXPECT_EQ(*start_after_move, *normalized_start); - EXPECT_EQ(*end_after_move, *normalized_end); + // There are now two characters only instead of three, so positions should be + // the same minus in the text offset. + EXPECT_EQ(end_after_move->anchor_id(), normalized_end->anchor_id()); + EXPECT_EQ(end_after_move->text_offset(), normalized_end->text_offset() + 1); } TEST_F(AXPlatformNodeTextRangeProviderTest, @@ -6258,7 +6261,10 @@ ExpectPositionsEqual(original_end, GetEnd(text_range)); EXPECT_EQ(*start_after_move, *normalized_start); - EXPECT_EQ(*end_after_move, *normalized_end); + // There are now two characters only instead of three, so positions should be + // the same minus in the text offset. + EXPECT_EQ(end_after_move->anchor_id(), normalized_end->anchor_id()); + EXPECT_EQ(end_after_move->text_offset(), normalized_end->text_offset() + 1); } TEST_F(AXPlatformNodeTextRangeProviderTest,
diff --git a/ui/base/ime/surrounding_text_tracker.cc b/ui/base/ime/surrounding_text_tracker.cc index 75e051f67..96ed663 100644 --- a/ui/base/ime/surrounding_text_tracker.cc +++ b/ui/base/ime/surrounding_text_tracker.cc
@@ -8,8 +8,74 @@ #include "base/check.h" #include "base/logging.h" +#include "base/notreached.h" namespace ui { +namespace { + +// Replaces the substring of the given str with the offset with replacement. +// If the range is outside of the str, str will not be updated (i.e. final +// result may not contain replacement) but at least offset should be adjusted. +void ReplaceString16WithOffset(std::u16string& str, + size_t& offset, + size_t pos, + size_t n, + const std::u16string& replacement) { + if (offset + str.length() < pos) { + // replacement starts after the known str. Do nothing. + return; + } + if (pos + n < offset) { + // replacement is in the range of [0:offset). Just adjust the offset. + offset += replacement.length() - n; + return; + } + + // Here, we have overlap (including just concatenating) of the original + // str and the replacement. + if (pos < offset) { + // Replacement starts before the current offset. + // Merge the pattern, and adjust the offset. + str.replace(0, n - (offset - pos), replacement); + offset = pos; + return; + } + + // Here, the overlap starts the same as or after the offset. + // In this case, offset is not changed. + size_t begin = pos - offset; // Begin index within str. + str.replace(begin, std::min(n, str.length() - begin), replacement); +} + +// Erases [pos:pos+n) from the given str with the offset. +void EraseString16WithOffset(std::u16string& str, + size_t& offset, + size_t pos, + size_t n) { + if (offset + str.length() <= pos) { + // The erasing range is after the str's range. Do nothing. + return; + } + + if (pos + n <= offset) { + // The erasing range is included in [0:offset]. Just adjust the offset. + offset -= n; + return; + } + + // Here we have to actually erase some range of str. + if (pos < offset) { + // The erasing range starts before the offset. + str.erase(0, n - (offset - pos)); + offset = pos; + return; + } + + size_t begin = pos - offset; + str.erase(begin, std::min(n, str.length() - begin)); +} + +} // namespace SurroundingTextTracker::Entry::Entry(State state, base::RepeatingClosure command) @@ -24,32 +90,74 @@ SurroundingTextTracker::Entry::~Entry() = default; SurroundingTextTracker::SurroundingTextTracker() { - ResetInternal(u"", gfx::Range(0)); + ResetInternal(u"", 0u, gfx::Range(0)); } SurroundingTextTracker::~SurroundingTextTracker() = default; void SurroundingTextTracker::Reset() { - ResetInternal(u"", gfx::Range(0)); + ResetInternal(u"", 0u, gfx::Range(0)); } SurroundingTextTracker::UpdateResult SurroundingTextTracker::Update( const base::StringPiece16 surrounding_text, + size_t utf16_offset, const gfx::Range& selection) { for (auto it = expected_updates_.begin(); it != expected_updates_.end(); ++it) { + if (it->state.selection != selection) { + continue; + } + + // TODO(crbug.com/1402906): Limit the trailing text to support cases + // where trailing text is truncated. + size_t compare_begin = std::max(utf16_offset, it->state.utf16_offset); + base::StringPiece16 target = + surrounding_text.substr(compare_begin - utf16_offset); + base::StringPiece16 history = + base::StringPiece16(it->state.surrounding_text) + .substr(compare_begin - utf16_offset); + + if (target != history) { + continue; + } + + // Found the target state, but it may be different from the one we + // estimate. Because the Update may be called multiple times for the same + // event. Check if the recorded state is exact same here to skip unneeded + // recalculation. if (it->state.surrounding_text == surrounding_text && + it->state.utf16_offset == utf16_offset && it->state.selection == selection) { - // Found the target state. Remove the older histories. - // Keep the last entry, because sometimes it is notified multiple times - // by client apps. expected_updates_.erase(expected_updates_.begin(), it); return UpdateResult::kUpdated; } + + // Otherwise, recalculate the predicts. + predicted_state_ = State{ + std::u16string(surrounding_text), utf16_offset, selection, + predicted_state_.composition, // Carried from the original state. + }; + + base::RepeatingClosure current_command = std::move(it->command); + std::vector<base::RepeatingClosure> remaining_commands; + for (++it; it != expected_updates_.end(); ++it) { + remaining_commands.push_back(std::move(it->command)); + } + expected_updates_.clear(); + expected_updates_.emplace_back(predicted_state_, + std::move(current_command)); + + // Replay all remaining commands to re-calculate predicted states from the + // given one. + for (auto& command : remaining_commands) { + command.Run(); + } + return UpdateResult::kUpdated; } VLOG(1) << "Unknown surrounding text update is found"; - ResetInternal(surrounding_text, selection); + ResetInternal(surrounding_text, utf16_offset, selection); return UpdateResult::kReset; } @@ -70,8 +178,16 @@ ? predicted_state_.selection : predicted_state_.composition; size_t composition_begin = old_range.GetMin(); - predicted_state_.surrounding_text.replace( - composition_begin, old_range.length(), composition.text); + if (old_range.GetMax() < predicted_state_.utf16_offset || + old_range.GetMin() > predicted_state_.utf16_offset + + predicted_state_.surrounding_text.length()) { + predicted_state_.surrounding_text = composition.text; + predicted_state_.utf16_offset = composition_begin; + } else { + ReplaceString16WithOffset(predicted_state_.surrounding_text, + predicted_state_.utf16_offset, composition_begin, + old_range.length(), composition.text); + } predicted_state_.selection = gfx::Range(composition_begin + composition.selection.start(), composition_begin + composition.selection.end()); @@ -109,9 +225,10 @@ void SurroundingTextTracker::OnClearCompositionText() { if (!predicted_state_.composition.is_empty()) { - predicted_state_.surrounding_text.erase( - predicted_state_.composition.GetMin(), - predicted_state_.composition.length()); + EraseString16WithOffset(predicted_state_.surrounding_text, + predicted_state_.utf16_offset, + predicted_state_.composition.GetMin(), + predicted_state_.composition.length()); // Set selection to the position where composition existed. predicted_state_.selection = gfx::Range(predicted_state_.composition.GetMin()); @@ -140,9 +257,10 @@ } else { // Otherwise, remove the composition. If the composition appears before // the rewritten range, the offset needs to be updated. - predicted_state_.surrounding_text.erase( - predicted_state_.composition.GetMin(), - predicted_state_.composition.length()); + EraseString16WithOffset(predicted_state_.surrounding_text, + predicted_state_.utf16_offset, + predicted_state_.composition.GetMin(), + predicted_state_.composition.length()); if (rewritten_range.GetMin() > predicted_state_.composition.GetMin()) { rewritten_range = gfx::Range( rewritten_range.start() - predicted_state_.composition.length(), @@ -151,8 +269,18 @@ } } - predicted_state_.surrounding_text.replace( - rewritten_range.GetMin(), rewritten_range.length(), std::u16string(text)); + if (rewritten_range.GetMin() > + predicted_state_.utf16_offset + + predicted_state_.surrounding_text.length() || + rewritten_range.GetMax() < predicted_state_.utf16_offset) { + predicted_state_.surrounding_text = std::u16string(text); + predicted_state_.utf16_offset = rewritten_range.GetMin(); + } else { + ReplaceString16WithOffset(predicted_state_.surrounding_text, + predicted_state_.utf16_offset, + rewritten_range.GetMin(), + rewritten_range.length(), std::u16string(text)); + } predicted_state_.selection = cursor_behavior == TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText @@ -172,8 +300,7 @@ gfx::Range delete_range( predicted_state_.selection.GetMin() - std::min(before, predicted_state_.selection.GetMin()), - std::min(predicted_state_.selection.GetMax() + after, - predicted_state_.surrounding_text.length())); + predicted_state_.selection.GetMax() + after); if (!predicted_state_.composition.is_empty()) { // Cancel the current composition. if (predicted_state_.composition.Intersects(delete_range)) { @@ -187,9 +314,10 @@ } else { // Otherwise, remove the composition here. If the composition appears // before the delete_range, the offset needs to be updated. - predicted_state_.surrounding_text.erase( - predicted_state_.composition.GetMin(), - predicted_state_.composition.length()); + EraseString16WithOffset(predicted_state_.surrounding_text, + predicted_state_.utf16_offset, + predicted_state_.composition.GetMin(), + predicted_state_.composition.length()); if (delete_range.GetMin() > predicted_state_.composition.GetMin()) { delete_range = gfx::Range( delete_range.start() - predicted_state_.composition.length(), @@ -198,8 +326,9 @@ } } - predicted_state_.surrounding_text.erase(delete_range.GetMin(), - delete_range.length()); + EraseString16WithOffset(predicted_state_.surrounding_text, + predicted_state_.utf16_offset, + delete_range.GetMin(), delete_range.length()); predicted_state_.selection = gfx::Range(delete_range.GetMin()); predicted_state_.composition = gfx::Range(); } @@ -211,9 +340,10 @@ } void SurroundingTextTracker::ResetInternal(base::StringPiece16 surrounding_text, + size_t utf16_offset, const gfx::Range& selection) { - predicted_state_ = - State{std::u16string(surrounding_text), selection, gfx::Range()}; + predicted_state_ = State{std::u16string(surrounding_text), utf16_offset, + selection, gfx::Range()}; expected_updates_.clear(); expected_updates_.emplace_back(predicted_state_, base::RepeatingClosure()); }
diff --git a/ui/base/ime/surrounding_text_tracker.h b/ui/base/ime/surrounding_text_tracker.h index f78345a..0cad008 100644 --- a/ui/base/ime/surrounding_text_tracker.h +++ b/ui/base/ime/surrounding_text_tracker.h
@@ -30,9 +30,15 @@ struct State { // Whole surrounding text, specifically this may include composition text. std::u16string surrounding_text; + + // Offset of the surrounding_text within the text input client. + // This does not affect to either selection nor composition. + size_t utf16_offset; + // Selection range. If it is empty, it means the cursor. Must not be // InvalidRange. Must be fit in |surrounding_text| range. gfx::Range selection; + // Composition range if it has. Maybe empty if there's no composition text. // Must not be InvalidRange. Must be fit in |surrounding_text| range. gfx::Range composition; @@ -63,6 +69,7 @@ // arguments, then returns kHistoryIsReset. // Note intentiontally ignored composition text. UpdateResult Update(const base::StringPiece16 surrounding_text, + size_t utf16_offset, const gfx::Range& selection); // The following methods are used to guess new surrounding text state. @@ -94,6 +101,7 @@ }; void ResetInternal(base::StringPiece16 surrounding_text, + size_t utf16_offset, const gfx::Range& selection); // The latest known state.
diff --git a/ui/base/ime/surrounding_text_tracker_unittest.cc b/ui/base/ime/surrounding_text_tracker_unittest.cc index 9fc0a9c..a4db32f4 100644 --- a/ui/base/ime/surrounding_text_tracker_unittest.cc +++ b/ui/base/ime/surrounding_text_tracker_unittest.cc
@@ -19,6 +19,7 @@ tracker.OnSetCompositionText(composition); EXPECT_EQ(u"abc", tracker.predicted_state().surrounding_text); + EXPECT_EQ(0u, tracker.predicted_state().utf16_offset); EXPECT_EQ(gfx::Range(3), tracker.predicted_state().selection); EXPECT_EQ(gfx::Range(0, 3), tracker.predicted_state().composition); @@ -27,6 +28,7 @@ tracker.OnSetCompositionText(composition); EXPECT_EQ(u"xyzw", tracker.predicted_state().surrounding_text); + EXPECT_EQ(0u, tracker.predicted_state().utf16_offset); EXPECT_EQ(gfx::Range(4), tracker.predicted_state().selection); EXPECT_EQ(gfx::Range(0, 4), tracker.predicted_state().composition); } @@ -34,7 +36,7 @@ TEST(SurroundingTextTracker, SetCompositionTextWithExistingText) { SurroundingTextTracker tracker; ASSERT_EQ(SurroundingTextTracker::UpdateResult::kReset, - tracker.Update(u"abcdefg", + tracker.Update(u"abcdefg", 0u, gfx::Range(3))); // Set cursor between c and d. ui::CompositionText composition; @@ -44,6 +46,7 @@ tracker.OnSetCompositionText(composition); EXPECT_EQ(u"abcxyzdefg", tracker.predicted_state().surrounding_text); + EXPECT_EQ(0u, tracker.predicted_state().utf16_offset); EXPECT_EQ(gfx::Range(6), tracker.predicted_state().selection); EXPECT_EQ(gfx::Range(3, 6), tracker.predicted_state().composition); @@ -53,25 +56,157 @@ tracker.OnSetCompositionText(composition); EXPECT_EQ(u"abcpqrstdefg", tracker.predicted_state().surrounding_text); + EXPECT_EQ(0u, tracker.predicted_state().utf16_offset); EXPECT_EQ(gfx::Range(3), tracker.predicted_state().selection); EXPECT_EQ(gfx::Range(3, 8), tracker.predicted_state().composition); + + // If there's selection, that will be replaced by composition. + tracker.Reset(); + ASSERT_EQ(SurroundingTextTracker::UpdateResult::kReset, + tracker.Update(u"abcdefg", 0u, gfx::Range(2, 5))); // Select "cde". + + composition.text = u"xyz"; + composition.selection = gfx::Range(3); // at the end. + + tracker.OnSetCompositionText(composition); + + EXPECT_EQ(u"abxyzfg", tracker.predicted_state().surrounding_text); + EXPECT_EQ(0u, tracker.predicted_state().utf16_offset); + EXPECT_EQ(gfx::Range(5), tracker.predicted_state().selection); + EXPECT_EQ(gfx::Range(2, 5), tracker.predicted_state().composition); + + // Simple check with offset. + tracker.Reset(); + ASSERT_EQ(SurroundingTextTracker::UpdateResult::kReset, + tracker.Update(u"abcdefg", 5u, + gfx::Range(8))); // Set cursor between c and d. + + composition.text = u"xyz"; + composition.selection = gfx::Range(3); // at the end. + + tracker.OnSetCompositionText(composition); + + EXPECT_EQ(u"abcxyzdefg", tracker.predicted_state().surrounding_text); + EXPECT_EQ(5u, tracker.predicted_state().utf16_offset); + EXPECT_EQ(gfx::Range(11), tracker.predicted_state().selection); + EXPECT_EQ(gfx::Range(8, 11), tracker.predicted_state().composition); + + // Selection is before offset. + tracker.Reset(); + ASSERT_EQ(SurroundingTextTracker::UpdateResult::kReset, + tracker.Update(u"abcdefg", 5u, + gfx::Range(3))); // Set cursor before offset. + + composition.text = u"xyz"; + composition.selection = gfx::Range(3); // at the end + + tracker.OnSetCompositionText(composition); + + EXPECT_EQ(u"xyz", tracker.predicted_state().surrounding_text); + EXPECT_EQ(3u, tracker.predicted_state().utf16_offset); + EXPECT_EQ(gfx::Range(6), tracker.predicted_state().selection); + EXPECT_EQ(gfx::Range(3, 6), tracker.predicted_state().composition); + + // Selection ends at the beginning of surrounding text. + tracker.Reset(); + ASSERT_EQ(SurroundingTextTracker::UpdateResult::kReset, + tracker.Update(u"abcdefg", 5u, gfx::Range(3, 5))); + + tracker.OnSetCompositionText(composition); + + EXPECT_EQ(u"xyzabcdefg", tracker.predicted_state().surrounding_text); + EXPECT_EQ(3u, tracker.predicted_state().utf16_offset); + EXPECT_EQ(gfx::Range(6), tracker.predicted_state().selection); + EXPECT_EQ(gfx::Range(3, 6), tracker.predicted_state().composition); + + // Selection overlaps with the surrounding text. + tracker.Reset(); + ASSERT_EQ(SurroundingTextTracker::UpdateResult::kReset, + tracker.Update(u"abcdefg", 5u, gfx::Range(4, 6))); + + tracker.OnSetCompositionText(composition); + + EXPECT_EQ(u"xyzbcdefg", tracker.predicted_state().surrounding_text); + EXPECT_EQ(4u, tracker.predicted_state().utf16_offset); + EXPECT_EQ(gfx::Range(7), tracker.predicted_state().selection); + EXPECT_EQ(gfx::Range(4, 7), tracker.predicted_state().composition); + + // Selection covers whole surrounding text. + tracker.Reset(); + ASSERT_EQ(SurroundingTextTracker::UpdateResult::kReset, + tracker.Update(u"abcdefg", 5u, gfx::Range(4, 13))); + + tracker.OnSetCompositionText(composition); + + EXPECT_EQ(u"xyz", tracker.predicted_state().surrounding_text); + EXPECT_EQ(4u, tracker.predicted_state().utf16_offset); + EXPECT_EQ(gfx::Range(7), tracker.predicted_state().selection); + EXPECT_EQ(gfx::Range(4, 7), tracker.predicted_state().composition); + + // Selection begins within the surrounding text, but overflows it. + tracker.Reset(); + ASSERT_EQ(SurroundingTextTracker::UpdateResult::kReset, + tracker.Update(u"abcdefg", 5u, gfx::Range(11, 13))); + + tracker.OnSetCompositionText(composition); + + EXPECT_EQ(u"abcdefxyz", tracker.predicted_state().surrounding_text); + EXPECT_EQ(5u, tracker.predicted_state().utf16_offset); + EXPECT_EQ(gfx::Range(14), tracker.predicted_state().selection); + EXPECT_EQ(gfx::Range(11, 14), tracker.predicted_state().composition); + + // Selection begins at the end of the surrounding text. + tracker.Reset(); + ASSERT_EQ(SurroundingTextTracker::UpdateResult::kReset, + tracker.Update(u"abcdefg", 5u, gfx::Range(12, 13))); + + tracker.OnSetCompositionText(composition); + + EXPECT_EQ(u"abcdefgxyz", tracker.predicted_state().surrounding_text); + EXPECT_EQ(5u, tracker.predicted_state().utf16_offset); + EXPECT_EQ(gfx::Range(15), tracker.predicted_state().selection); + EXPECT_EQ(gfx::Range(12, 15), tracker.predicted_state().composition); + + // Selection begins after the known surrounding text. + tracker.Reset(); + ASSERT_EQ(SurroundingTextTracker::UpdateResult::kReset, + tracker.Update(u"abcdefg", 5u, gfx::Range(13))); + + tracker.OnSetCompositionText(composition); + + EXPECT_EQ(u"xyz", tracker.predicted_state().surrounding_text); + EXPECT_EQ(13u, tracker.predicted_state().utf16_offset); + EXPECT_EQ(gfx::Range(16), tracker.predicted_state().selection); + EXPECT_EQ(gfx::Range(13, 16), tracker.predicted_state().composition); } TEST(SurroundingTextTracker, SetCompositionFromExistingText) { SurroundingTextTracker tracker; ASSERT_EQ(SurroundingTextTracker::UpdateResult::kReset, - tracker.Update(u"abcdefg", + tracker.Update(u"abcdefg", 0u, gfx::Range(3))); // Set cursor between c and d. tracker.OnSetCompositionFromExistingText(gfx::Range(3, 5)); EXPECT_EQ(u"abcdefg", tracker.predicted_state().surrounding_text); + EXPECT_EQ(0u, tracker.predicted_state().utf16_offset); EXPECT_EQ(gfx::Range(3), tracker.predicted_state().selection); EXPECT_EQ(gfx::Range(3, 5), tracker.predicted_state().composition); + + tracker.Reset(); + ASSERT_EQ(SurroundingTextTracker::UpdateResult::kReset, + tracker.Update(u"abcdefg", 5u, + gfx::Range(8))); // Set cursor between c and d. + + tracker.OnSetCompositionFromExistingText(gfx::Range(8, 10)); + EXPECT_EQ(u"abcdefg", tracker.predicted_state().surrounding_text); + EXPECT_EQ(5u, tracker.predicted_state().utf16_offset); + EXPECT_EQ(gfx::Range(8), tracker.predicted_state().selection); + EXPECT_EQ(gfx::Range(8, 10), tracker.predicted_state().composition); } TEST(SurroundingTextTracker, ConfirmCompositionText) { SurroundingTextTracker tracker; ASSERT_EQ(SurroundingTextTracker::UpdateResult::kReset, - tracker.Update(u"abcdefg", + tracker.Update(u"abcdefg", 0u, gfx::Range(3))); // Set cursor between c and d. ui::CompositionText composition; @@ -81,26 +216,48 @@ tracker.OnSetCompositionText(composition); EXPECT_EQ(u"abcxyzdefg", tracker.predicted_state().surrounding_text); + EXPECT_EQ(0u, tracker.predicted_state().utf16_offset); EXPECT_EQ(gfx::Range(4), tracker.predicted_state().selection); EXPECT_EQ(gfx::Range(3, 6), tracker.predicted_state().composition); tracker.OnConfirmCompositionText(/*keep_selection=*/false); EXPECT_EQ(u"abcxyzdefg", tracker.predicted_state().surrounding_text); + EXPECT_EQ(0u, tracker.predicted_state().utf16_offset); EXPECT_EQ(gfx::Range(6), tracker.predicted_state().selection); EXPECT_TRUE(tracker.predicted_state().composition.is_empty()); // Nothing happens if no composition exists. tracker.OnConfirmCompositionText(/*keep_selection=*/false); EXPECT_EQ(u"abcxyzdefg", tracker.predicted_state().surrounding_text); + EXPECT_EQ(0u, tracker.predicted_state().utf16_offset); EXPECT_EQ(gfx::Range(6), tracker.predicted_state().selection); EXPECT_TRUE(tracker.predicted_state().composition.is_empty()); + + // Check with offset. + tracker.Reset(); + ASSERT_EQ(SurroundingTextTracker::UpdateResult::kReset, + tracker.Update(u"abcdefg", 5u, + gfx::Range(8))); // Set cursor between c and d. + tracker.OnSetCompositionText(composition); + + EXPECT_EQ(u"abcxyzdefg", tracker.predicted_state().surrounding_text); + EXPECT_EQ(5u, tracker.predicted_state().utf16_offset); + EXPECT_EQ(gfx::Range(9), tracker.predicted_state().selection); + EXPECT_EQ(gfx::Range(8, 11), tracker.predicted_state().composition); + + tracker.OnConfirmCompositionText(/*keep_selection=*/false); + + EXPECT_EQ(u"abcxyzdefg", tracker.predicted_state().surrounding_text); + EXPECT_EQ(5u, tracker.predicted_state().utf16_offset); + EXPECT_EQ(gfx::Range(11), tracker.predicted_state().selection); + EXPECT_TRUE(tracker.predicted_state().composition.is_empty()); } TEST(SurroundingTextTracker, ConfirmCompositionTextWithKeepSelection) { SurroundingTextTracker tracker; ASSERT_EQ(SurroundingTextTracker::UpdateResult::kReset, - tracker.Update(u"abcdefg", + tracker.Update(u"abcdefg", 0u, gfx::Range(3))); // Set cursor between c and d. ui::CompositionText composition; @@ -110,18 +267,21 @@ tracker.OnSetCompositionText(composition); EXPECT_EQ(u"abcxyzdefg", tracker.predicted_state().surrounding_text); + EXPECT_EQ(0u, tracker.predicted_state().utf16_offset); EXPECT_EQ(gfx::Range(4), tracker.predicted_state().selection); EXPECT_EQ(gfx::Range(3, 6), tracker.predicted_state().composition); tracker.OnConfirmCompositionText(/*keep_selection=*/true); EXPECT_EQ(u"abcxyzdefg", tracker.predicted_state().surrounding_text); + EXPECT_EQ(0u, tracker.predicted_state().utf16_offset); EXPECT_EQ(gfx::Range(4), tracker.predicted_state().selection); EXPECT_TRUE(tracker.predicted_state().composition.is_empty()); // Nothing happens if no composition exists. tracker.OnConfirmCompositionText(/*keep_selection=*/true); EXPECT_EQ(u"abcxyzdefg", tracker.predicted_state().surrounding_text); + EXPECT_EQ(0u, tracker.predicted_state().utf16_offset); EXPECT_EQ(gfx::Range(4), tracker.predicted_state().selection); EXPECT_TRUE(tracker.predicted_state().composition.is_empty()); } @@ -129,7 +289,7 @@ TEST(SurroundingTextTracker, ClearCompositionText) { SurroundingTextTracker tracker; ASSERT_EQ(SurroundingTextTracker::UpdateResult::kReset, - tracker.Update(u"abcdefg", + tracker.Update(u"abcdefg", 0u, gfx::Range(3))); // Set cursor between c and d. ui::CompositionText composition; @@ -139,18 +299,21 @@ tracker.OnSetCompositionText(composition); EXPECT_EQ(u"abcxyzdefg", tracker.predicted_state().surrounding_text); + EXPECT_EQ(0u, tracker.predicted_state().utf16_offset); EXPECT_EQ(gfx::Range(4), tracker.predicted_state().selection); EXPECT_EQ(gfx::Range(3, 6), tracker.predicted_state().composition); tracker.OnClearCompositionText(); EXPECT_EQ(u"abcdefg", tracker.predicted_state().surrounding_text); + EXPECT_EQ(0u, tracker.predicted_state().utf16_offset); EXPECT_EQ(gfx::Range(3), tracker.predicted_state().selection); EXPECT_TRUE(tracker.predicted_state().composition.is_empty()); // Set "cd" as composition text. tracker.OnSetCompositionFromExistingText(gfx::Range(2, 4)); EXPECT_EQ(u"abcdefg", tracker.predicted_state().surrounding_text); + EXPECT_EQ(0u, tracker.predicted_state().utf16_offset); EXPECT_EQ(gfx::Range(3), tracker.predicted_state().selection); EXPECT_EQ(gfx::Range(2, 4), tracker.predicted_state().composition); @@ -158,67 +321,254 @@ tracker.OnClearCompositionText(); EXPECT_EQ(u"abefg", tracker.predicted_state().surrounding_text); + EXPECT_EQ(0u, tracker.predicted_state().utf16_offset); EXPECT_EQ(gfx::Range(2), tracker.predicted_state().selection); EXPECT_TRUE(tracker.predicted_state().composition.is_empty()); // Nothing should happen if there's no composition. tracker.OnClearCompositionText(); EXPECT_EQ(u"abefg", tracker.predicted_state().surrounding_text); + EXPECT_EQ(0u, tracker.predicted_state().utf16_offset); EXPECT_EQ(gfx::Range(2), tracker.predicted_state().selection); EXPECT_TRUE(tracker.predicted_state().composition.is_empty()); + + // With offset. + // Set composition before the surrounding text. + tracker.Reset(); + ASSERT_EQ(SurroundingTextTracker::UpdateResult::kReset, + tracker.Update(u"abcdefg", 5u, + gfx::Range(8))); // Set cursor between c and d. + tracker.OnSetCompositionFromExistingText(gfx::Range(2, 4)); + tracker.OnClearCompositionText(); + + EXPECT_EQ(u"abcdefg", tracker.predicted_state().surrounding_text); + EXPECT_EQ(3u, tracker.predicted_state().utf16_offset); + EXPECT_EQ(gfx::Range(2), tracker.predicted_state().selection); + EXPECT_TRUE(tracker.predicted_state().composition.is_empty()); + + // Composition overlaps with the surrounding text. + tracker.Reset(); + ASSERT_EQ(SurroundingTextTracker::UpdateResult::kReset, + tracker.Update(u"abcdefg", 5u, + gfx::Range(8))); // Set cursor between c and d. + tracker.OnSetCompositionFromExistingText(gfx::Range(4, 6)); + tracker.OnClearCompositionText(); + + EXPECT_EQ(u"bcdefg", tracker.predicted_state().surrounding_text); + EXPECT_EQ(4u, tracker.predicted_state().utf16_offset); + EXPECT_EQ(gfx::Range(4), tracker.predicted_state().selection); + EXPECT_TRUE(tracker.predicted_state().composition.is_empty()); + + // Composition covers the whole surrounding text. + tracker.Reset(); + ASSERT_EQ(SurroundingTextTracker::UpdateResult::kReset, + tracker.Update(u"abcdefg", 5u, + gfx::Range(8))); // Set cursor between c and d. + tracker.OnSetCompositionFromExistingText(gfx::Range(4, 13)); + tracker.OnClearCompositionText(); + + EXPECT_EQ(u"", tracker.predicted_state().surrounding_text); + EXPECT_EQ(4u, tracker.predicted_state().utf16_offset); + EXPECT_EQ(gfx::Range(4), tracker.predicted_state().selection); + EXPECT_TRUE(tracker.predicted_state().composition.is_empty()); + + // Composition overlaps the trailing part of surrounding text. + tracker.Reset(); + ASSERT_EQ(SurroundingTextTracker::UpdateResult::kReset, + tracker.Update(u"abcdefg", 5u, + gfx::Range(8))); // Set cursor between c and d. + tracker.OnSetCompositionFromExistingText(gfx::Range(11, 13)); + tracker.OnClearCompositionText(); + + EXPECT_EQ(u"abcdef", tracker.predicted_state().surrounding_text); + EXPECT_EQ(5u, tracker.predicted_state().utf16_offset); + EXPECT_EQ(gfx::Range(11), tracker.predicted_state().selection); + EXPECT_TRUE(tracker.predicted_state().composition.is_empty()); + + // Composition is set after the surrounding text. + tracker.Reset(); + ASSERT_EQ(SurroundingTextTracker::UpdateResult::kReset, + tracker.Update(u"abcdefg", 5u, + gfx::Range(8))); // Set cursor between c and d. + tracker.OnSetCompositionFromExistingText(gfx::Range(13, 15)); + tracker.OnClearCompositionText(); + + EXPECT_EQ(u"abcdefg", tracker.predicted_state().surrounding_text); + EXPECT_EQ(5u, tracker.predicted_state().utf16_offset); + EXPECT_EQ(gfx::Range(13), tracker.predicted_state().selection); + EXPECT_TRUE(tracker.predicted_state().composition.is_empty()); } TEST(SurroundingTextTracker, InsertText) { SurroundingTextTracker tracker; ASSERT_EQ(SurroundingTextTracker::UpdateResult::kReset, - tracker.Update(u"abcdefg", + tracker.Update(u"abcdefg", 0u, gfx::Range(3))); // Set cursor between c and d. tracker.OnInsertText( u"xyz", TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText); EXPECT_EQ(u"abcxyzdefg", tracker.predicted_state().surrounding_text); + EXPECT_EQ(0u, tracker.predicted_state().utf16_offset); EXPECT_EQ(gfx::Range(6), tracker.predicted_state().selection); EXPECT_TRUE(tracker.predicted_state().composition.is_empty()); EXPECT_EQ(SurroundingTextTracker::UpdateResult::kUpdated, - tracker.Update(u"abcxyzdefg", gfx::Range(6))); + tracker.Update(u"abcxyzdefg", 0u, gfx::Range(6))); + tracker.Reset(); ASSERT_EQ(SurroundingTextTracker::UpdateResult::kReset, - tracker.Update(u"abcdefg", + tracker.Update(u"abcdefg", 0u, gfx::Range(3))); // Set cursor between c and d. tracker.OnInsertText( u"xyz", TextInputClient::InsertTextCursorBehavior::kMoveCursorBeforeText); EXPECT_EQ(u"abcxyzdefg", tracker.predicted_state().surrounding_text); + EXPECT_EQ(0u, tracker.predicted_state().utf16_offset); EXPECT_EQ(gfx::Range(3), tracker.predicted_state().selection); EXPECT_TRUE(tracker.predicted_state().composition.is_empty()); EXPECT_EQ(SurroundingTextTracker::UpdateResult::kUpdated, - tracker.Update(u"abcxyzdefg", gfx::Range(3))); + tracker.Update(u"abcxyzdefg", 0u, gfx::Range(3))); - ASSERT_EQ( - SurroundingTextTracker::UpdateResult::kReset, - tracker.Update(u"abcdefg", gfx::Range(3, 4))); // Set selection on "d". + tracker.Reset(); + ASSERT_EQ(SurroundingTextTracker::UpdateResult::kReset, + tracker.Update(u"abcdefg", 0u, + gfx::Range(3, 4))); // Set selection on "d". tracker.OnInsertText( u"xyz", TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText); EXPECT_EQ(u"abcxyzefg", tracker.predicted_state().surrounding_text); + EXPECT_EQ(0u, tracker.predicted_state().utf16_offset); EXPECT_EQ(gfx::Range(6), tracker.predicted_state().selection); EXPECT_TRUE(tracker.predicted_state().composition.is_empty()); EXPECT_EQ(SurroundingTextTracker::UpdateResult::kUpdated, - tracker.Update(u"abcxyzefg", gfx::Range(6))); + tracker.Update(u"abcxyzefg", 0u, gfx::Range(6))); - ASSERT_EQ( - SurroundingTextTracker::UpdateResult::kReset, - tracker.Update(u"abcdefg", gfx::Range(3, 4))); // Set selection on "d". + ASSERT_EQ(SurroundingTextTracker::UpdateResult::kReset, + tracker.Update(u"abcdefg", 0u, + gfx::Range(3, 4))); // Set selection on "d". tracker.OnInsertText( u"xyz", TextInputClient::InsertTextCursorBehavior::kMoveCursorBeforeText); // 'd' should be replaced. EXPECT_EQ(u"abcxyzefg", tracker.predicted_state().surrounding_text); + EXPECT_EQ(0u, tracker.predicted_state().utf16_offset); EXPECT_EQ(gfx::Range(3), tracker.predicted_state().selection); EXPECT_TRUE(tracker.predicted_state().composition.is_empty()); EXPECT_EQ(SurroundingTextTracker::UpdateResult::kUpdated, - tracker.Update(u"abcxyzefg", gfx::Range(3))); + tracker.Update(u"abcxyzefg", 0u, gfx::Range(3))); + + // With offset. + tracker.Reset(); + ASSERT_EQ( + SurroundingTextTracker::UpdateResult::kReset, + tracker.Update(u"abcdefg", 5u, gfx::Range(8))); // Set cursor after "c" + + tracker.OnInsertText( + u"xyz", TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText); + EXPECT_EQ(u"abcxyzdefg", tracker.predicted_state().surrounding_text); + EXPECT_EQ(5u, tracker.predicted_state().utf16_offset); + EXPECT_EQ(gfx::Range(11), tracker.predicted_state().selection); + EXPECT_TRUE(tracker.predicted_state().composition.is_empty()); + EXPECT_EQ(SurroundingTextTracker::UpdateResult::kUpdated, + tracker.Update(u"abcxyzdefg", 5u, gfx::Range(11))); + + // Selection is before offset. + tracker.Reset(); + ASSERT_EQ(SurroundingTextTracker::UpdateResult::kReset, + tracker.Update(u"abcdefg", 5u, gfx::Range(3, 4))); + + tracker.OnInsertText( + u"xyz", TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText); + EXPECT_EQ(u"xyz", tracker.predicted_state().surrounding_text); + EXPECT_EQ(3u, tracker.predicted_state().utf16_offset); + EXPECT_EQ(gfx::Range(6), tracker.predicted_state().selection); + EXPECT_TRUE(tracker.predicted_state().composition.is_empty()); + EXPECT_EQ(SurroundingTextTracker::UpdateResult::kUpdated, + tracker.Update(u"xyz", 3u, gfx::Range(6))); + + // Selection ends at the beginning of the surrounding text. + tracker.Reset(); + ASSERT_EQ(SurroundingTextTracker::UpdateResult::kReset, + tracker.Update(u"abcdefg", 5u, gfx::Range(3, 5))); + + tracker.OnInsertText( + u"xyz", TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText); + EXPECT_EQ(u"xyzabcdefg", tracker.predicted_state().surrounding_text); + EXPECT_EQ(3u, tracker.predicted_state().utf16_offset); + EXPECT_EQ(gfx::Range(6), tracker.predicted_state().selection); + EXPECT_TRUE(tracker.predicted_state().composition.is_empty()); + EXPECT_EQ(SurroundingTextTracker::UpdateResult::kUpdated, + tracker.Update(u"xyzabcdefg", 3u, gfx::Range(6))); + + // Selection overlaps the leading parts of surrounding text. + tracker.Reset(); + ASSERT_EQ(SurroundingTextTracker::UpdateResult::kReset, + tracker.Update(u"abcdefg", 5u, gfx::Range(4, 6))); + + tracker.OnInsertText( + u"xyz", TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText); + EXPECT_EQ(u"xyzbcdefg", tracker.predicted_state().surrounding_text); + EXPECT_EQ(4u, tracker.predicted_state().utf16_offset); + EXPECT_EQ(gfx::Range(7), tracker.predicted_state().selection); + EXPECT_TRUE(tracker.predicted_state().composition.is_empty()); + EXPECT_EQ(SurroundingTextTracker::UpdateResult::kUpdated, + tracker.Update(u"xyzbcdefg", 4u, gfx::Range(7))); + + // Selection covers the whole surrounding text. + tracker.Reset(); + ASSERT_EQ(SurroundingTextTracker::UpdateResult::kReset, + tracker.Update(u"abcdefg", 5u, gfx::Range(4, 13))); + + tracker.OnInsertText( + u"xyz", TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText); + EXPECT_EQ(u"xyz", tracker.predicted_state().surrounding_text); + EXPECT_EQ(4u, tracker.predicted_state().utf16_offset); + EXPECT_EQ(gfx::Range(7), tracker.predicted_state().selection); + EXPECT_TRUE(tracker.predicted_state().composition.is_empty()); + EXPECT_EQ(SurroundingTextTracker::UpdateResult::kUpdated, + tracker.Update(u"xyz", 4u, gfx::Range(7))); + + // Selection overlaps the trailing part of surrounding text. + tracker.Reset(); + ASSERT_EQ(SurroundingTextTracker::UpdateResult::kReset, + tracker.Update(u"abcdefg", 5u, gfx::Range(11, 13))); + + tracker.OnInsertText( + u"xyz", TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText); + EXPECT_EQ(u"abcdefxyz", tracker.predicted_state().surrounding_text); + EXPECT_EQ(5u, tracker.predicted_state().utf16_offset); + EXPECT_EQ(gfx::Range(14), tracker.predicted_state().selection); + EXPECT_TRUE(tracker.predicted_state().composition.is_empty()); + EXPECT_EQ(SurroundingTextTracker::UpdateResult::kUpdated, + tracker.Update(u"abcdefxyz", 5u, gfx::Range(14))); + + // Selection starts wat the end of the surrounding text. + tracker.Reset(); + ASSERT_EQ(SurroundingTextTracker::UpdateResult::kReset, + tracker.Update(u"abcdefg", 5u, gfx::Range(12, 13))); + + tracker.OnInsertText( + u"xyz", TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText); + EXPECT_EQ(u"abcdefgxyz", tracker.predicted_state().surrounding_text); + EXPECT_EQ(5u, tracker.predicted_state().utf16_offset); + EXPECT_EQ(gfx::Range(15), tracker.predicted_state().selection); + EXPECT_TRUE(tracker.predicted_state().composition.is_empty()); + EXPECT_EQ(SurroundingTextTracker::UpdateResult::kUpdated, + tracker.Update(u"abcdefgxyz", 5u, gfx::Range(15))); + + // Selection is after the surrounding text. + tracker.Reset(); + ASSERT_EQ(SurroundingTextTracker::UpdateResult::kReset, + tracker.Update(u"abcdefg", 5u, gfx::Range(13, 14))); + + tracker.OnInsertText( + u"xyz", TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText); + EXPECT_EQ(u"xyz", tracker.predicted_state().surrounding_text); + EXPECT_EQ(13u, tracker.predicted_state().utf16_offset); + EXPECT_EQ(gfx::Range(16), tracker.predicted_state().selection); + EXPECT_TRUE(tracker.predicted_state().composition.is_empty()); + EXPECT_EQ(SurroundingTextTracker::UpdateResult::kUpdated, + tracker.Update(u"xyz", 13u, gfx::Range(16))); } TEST(SurroundingTextTracker, InsertTextWithComposition) { @@ -267,7 +617,7 @@ SurroundingTextTracker tracker; ASSERT_EQ(SurroundingTextTracker::UpdateResult::kReset, - tracker.Update(u"abcdefg", test_case.selection)); + tracker.Update(u"abcdefg", 0u, test_case.selection)); // Set composition on "cde". tracker.OnSetCompositionFromExistingText(gfx::Range(2, 5)); @@ -286,63 +636,77 @@ TEST(SurroundingTextTracker, ExtendSelectionAndDelete) { constexpr struct { + size_t utf16_offset; gfx::Range selection; gfx::Range composition; size_t before; size_t after; const char16_t* expected_surrounding_text; + size_t expected_utf16_offset; gfx::Range expected_selection; } kTestData[] = { // null deletion. - {gfx::Range(3), gfx::Range(), 0, 0, u"abcdefg", gfx::Range(3)}, + {0u, gfx::Range(3), gfx::Range(), 0, 0, u"abcdefg", 0u, gfx::Range(3)}, // Remove 1 char before the cursor. - {gfx::Range(3), gfx::Range(), 1, 0, u"abdefg", gfx::Range(2)}, + {0u, gfx::Range(3), gfx::Range(), 1, 0, u"abdefg", 0u, gfx::Range(2)}, // Remove 1 char after the cursor. - {gfx::Range(3), gfx::Range(), 0, 1, u"abcefg", gfx::Range(3)}, + {0u, gfx::Range(3), gfx::Range(), 0, 1, u"abcefg", 0u, gfx::Range(3)}, // Remove 1 char for each before and after the cursor. - {gfx::Range(3), gfx::Range(), 1, 1, u"abefg", gfx::Range(2)}, + {0u, gfx::Range(3), gfx::Range(), 1, 1, u"abefg", 0u, gfx::Range(2)}, // Selection deletion. - {gfx::Range(3, 4), gfx::Range(), 0, 0, u"abcefg", gfx::Range(3)}, + {0u, gfx::Range(3, 4), gfx::Range(), 0, 0, u"abcefg", 0u, gfx::Range(3)}, // Selection deletion with 1 char before. - {gfx::Range(3, 4), gfx::Range(), 1, 0, u"abefg", gfx::Range(2)}, + {0u, gfx::Range(3, 4), gfx::Range(), 1, 0, u"abefg", 0u, gfx::Range(2)}, // Selection deletion with 1 char after. - {gfx::Range(3, 4), gfx::Range(), 0, 1, u"abcfg", gfx::Range(3)}, + {0u, gfx::Range(3, 4), gfx::Range(), 0, 1, u"abcfg", 0u, gfx::Range(3)}, // Selection deletion with 1 char for each before and after. - {gfx::Range(3, 4), gfx::Range(), 1, 1, u"abfg", gfx::Range(2)}, + {0u, gfx::Range(3, 4), gfx::Range(), 1, 1, u"abfg", 0u, gfx::Range(2)}, // With composition. - {gfx::Range(2), gfx::Range(3, 4), 0, 0, u"abcefg", gfx::Range(2)}, + {0u, gfx::Range(2), gfx::Range(3, 4), 0, 0, u"abcefg", 0u, gfx::Range(2)}, // With composition crossing the beginning boundary. - {gfx::Range(1), gfx::Range(2, 5), 0, 2, u"afg", gfx::Range(1)}, + {0u, gfx::Range(1), gfx::Range(2, 5), 0, 2, u"afg", 0u, gfx::Range(1)}, // With composition containing the selection. - {gfx::Range(3, 4), gfx::Range(1, 6), 1, 1, u"ag", gfx::Range(1)}, + {0u, gfx::Range(3, 4), gfx::Range(1, 6), 1, 1, u"ag", 0u, gfx::Range(1)}, // With composition crossing the end boundary. - {gfx::Range(6), gfx::Range(2, 5), 2, 0, u"abg", gfx::Range(2)}, + {0u, gfx::Range(6), gfx::Range(2, 5), 2, 0, u"abg", 0u, gfx::Range(2)}, // With composition covered by selection. - {gfx::Range(3, 4), gfx::Range(2, 5), 2, 2, u"ag", gfx::Range(1)}, + {0u, gfx::Range(3, 4), gfx::Range(2, 5), 2, 2, u"ag", 0u, gfx::Range(1)}, + + // With offset. + {5u, gfx::Range(8), gfx::Range(), 1, 2, u"abfg", 5u, gfx::Range(7)}, + {5u, gfx::Range(3), gfx::Range(), 1, 0, u"abcdefg", 4u, gfx::Range(2)}, + {5u, gfx::Range(3), gfx::Range(), 0, 1, u"abcdefg", 4u, gfx::Range(3)}, + {5u, gfx::Range(4), gfx::Range(), 0, 2, u"bcdefg", 4u, gfx::Range(4)}, + {5u, gfx::Range(13), gfx::Range(), 1, 0, u"abcdefg", 5u, gfx::Range(12)}, + {5u, gfx::Range(13), gfx::Range(), 0, 1, u"abcdefg", 5u, gfx::Range(13)}, + {5u, gfx::Range(13), gfx::Range(), 2, 0, u"abcdef", 5u, gfx::Range(11)}, }; for (const auto& test_case : kTestData) { SurroundingTextTracker tracker; ASSERT_EQ(SurroundingTextTracker::UpdateResult::kReset, - tracker.Update(u"abcdefg", test_case.selection)); + tracker.Update(u"abcdefg", test_case.utf16_offset, + test_case.selection)); if (!test_case.composition.is_empty()) tracker.OnSetCompositionFromExistingText(test_case.composition); tracker.OnExtendSelectionAndDelete(test_case.before, test_case.after); EXPECT_EQ(test_case.expected_surrounding_text, tracker.predicted_state().surrounding_text); + EXPECT_EQ(test_case.expected_utf16_offset, + tracker.predicted_state().utf16_offset); EXPECT_EQ(test_case.expected_selection, tracker.predicted_state().selection); EXPECT_TRUE(tracker.predicted_state().composition.is_empty());
diff --git a/ui/chromeos/styles/cros_sys_colors.json5 b/ui/chromeos/styles/cros_sys_colors.json5 index a187630..2af8836 100644 --- a/ui/chromeos/styles/cros_sys_colors.json5 +++ b/ui/chromeos/styles/cros_sys_colors.json5
@@ -105,6 +105,7 @@ 'on-surface-variant': { light: '$cros.ref.neutralvariant30', dark: '$cros.ref.neutralvariant80', + generate_per_mode: true, }, outline: { light: '$cros.ref.neutralvariant50',
diff --git a/ui/events/BUILD.gn b/ui/events/BUILD.gn index 90d4467..25c0f44 100644 --- a/ui/events/BUILD.gn +++ b/ui/events/BUILD.gn
@@ -98,7 +98,6 @@ sources = [ "base_event_utils.cc", "base_event_utils.h", - "event_latency_metadata.h", "event_switches.cc", "event_switches.h", "events_base_export.h", @@ -497,7 +496,6 @@ "//ui/display", "//ui/gfx", "//ui/gfx/geometry", - "//ui/latency", ] defines = [ "GESTURE_DETECTION_IMPLEMENTATION" ]
diff --git a/ui/events/blink/blink_event_util.cc b/ui/events/blink/blink_event_util.cc index e7f0d58..9ad01f1 100644 --- a/ui/events/blink/blink_event_util.cc +++ b/ui/events/blink/blink_event_util.cc
@@ -335,8 +335,6 @@ gesture.primary_unique_touch_event_id = details.primary_unique_touch_event_id(); gesture.unique_touch_event_id = unique_touch_event_id; - gesture.GetModifiableEventLatencyMetadata() = - details.GetEventLatencyMetadata(); switch (details.type()) { case ET_GESTURE_SHOW_PRESS:
diff --git a/ui/events/event_latency_metadata.h b/ui/events/event_latency_metadata.h deleted file mode 100644 index b61ccf8..0000000 --- a/ui/events/event_latency_metadata.h +++ /dev/null
@@ -1,30 +0,0 @@ -// Copyright 2023 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef UI_EVENTS_EVENT_LATENCY_METADATA_H_ -#define UI_EVENTS_EVENT_LATENCY_METADATA_H_ - -#include "base/time/time.h" - -namespace ui { - -// The struct contains metadata about EventLatency events. -// There should only be POD classes in this struct to keep the metadata to a -// minimum. -struct EventLatencyMetadata { - // Time when event arrived in the BrowserMain thread. - base::TimeTicks arrived_in_browser_main_timestamp; - - // This field is used only by scroll events to understand when the related - // blocking touch move was dispatched to Renderer. If the related touch move - // wasn't blocking, this field is not set. - base::TimeTicks scrolls_blocking_touch_dispatched_to_renderer; - - // Time when event was disppatched to the Renderer from the Browser. - base::TimeTicks dispatched_to_renderer; -}; - -} // namespace ui - -#endif // UI_EVENTS_EVENT_LATENCY_METADATA_H_ \ No newline at end of file
diff --git a/ui/events/gesture_detection/filtered_gesture_provider.cc b/ui/events/gesture_detection/filtered_gesture_provider.cc index d497ee0..b832c1db 100644 --- a/ui/events/gesture_detection/filtered_gesture_provider.cc +++ b/ui/events/gesture_detection/filtered_gesture_provider.cc
@@ -62,11 +62,9 @@ void FilteredGestureProvider::OnTouchEventAck( uint32_t unique_event_id, bool event_consumed, - bool is_source_touch_event_set_blocking, - const absl::optional<EventLatencyMetadata>& event_latency_metadata) { + bool is_source_touch_event_set_blocking) { gesture_filter_.OnTouchEventAck(unique_event_id, event_consumed, - is_source_touch_event_set_blocking, - event_latency_metadata); + is_source_touch_event_set_blocking); } void FilteredGestureProvider::ResetGestureHandlingState() {
diff --git a/ui/events/gesture_detection/filtered_gesture_provider.h b/ui/events/gesture_detection/filtered_gesture_provider.h index f02ff45a..cbe9984 100644 --- a/ui/events/gesture_detection/filtered_gesture_provider.h +++ b/ui/events/gesture_detection/filtered_gesture_provider.h
@@ -48,15 +48,9 @@ // To be called upon asynchronous and synchronous ack of an event that was // forwarded after a successful call to |OnTouchEvent()|. - // |event_latency_metadata| is provided only if the touch event or - // corresponding touch event was blocked before sending to the Renderer. This - // definition of blocking is not related to the value of - // |is_source_touch_event_set_blocking|. void OnTouchEventAck(uint32_t unique_event_id, bool event_consumed, - bool is_source_touch_event_set_blocking, - const absl::optional<EventLatencyMetadata>& - event_latency_metadata = absl::nullopt); + bool is_source_touch_event_set_blocking); void ResetGestureHandlingState();
diff --git a/ui/events/gesture_detection/gesture_event_data_packet.cc b/ui/events/gesture_detection/gesture_event_data_packet.cc index bc6f6fe..dfd08725 100644 --- a/ui/events/gesture_detection/gesture_event_data_packet.cc +++ b/ui/events/gesture_detection/gesture_event_data_packet.cc
@@ -122,15 +122,4 @@ } } -void GestureEventDataPacket::AddEventLatencyMetadataToGestures( - const EventLatencyMetadata& event_latency_metadata, - const base::RepeatingCallback<bool(const ui::GestureEventData&)>& filter) { - for (auto& gesture : gestures_) { - if (filter.Run(gesture)) { - gesture.details.GetModifiableEventLatencyMetadata() = - event_latency_metadata; - } - } -} - } // namespace ui
diff --git a/ui/events/gesture_detection/gesture_event_data_packet.h b/ui/events/gesture_detection/gesture_event_data_packet.h index 8719711..285c837 100644 --- a/ui/events/gesture_detection/gesture_event_data_packet.h +++ b/ui/events/gesture_detection/gesture_event_data_packet.h
@@ -7,10 +7,8 @@ #include <stddef.h> #include <stdint.h> -#include <functional> #include "base/containers/stack_container.h" -#include "base/functional/callback.h" #include "base/time/time.h" #include "ui/events/gesture_detection/gesture_detection_export.h" #include "ui/events/gesture_detection/gesture_event_data.h" @@ -68,10 +66,6 @@ AckState ack_state() { return ack_state_; } uint32_t unique_touch_event_id() const { return unique_touch_event_id_; } - void AddEventLatencyMetadataToGestures( - const EventLatencyMetadata& event_latency_metadata, - const base::RepeatingCallback<bool(const ui::GestureEventData&)>& filter); - private: GestureEventDataPacket(base::TimeTicks timestamp, GestureSource source,
diff --git a/ui/events/gesture_detection/gesture_event_data_packet_unittest.cc b/ui/events/gesture_detection/gesture_event_data_packet_unittest.cc index c65b011..b4995671 100644 --- a/ui/events/gesture_detection/gesture_event_data_packet_unittest.cc +++ b/ui/events/gesture_detection/gesture_event_data_packet_unittest.cc
@@ -134,33 +134,4 @@ EXPECT_EQ(gfx::PointF(gesture.x, gesture.y), packet.touch_location()); } -TEST_F(GestureEventDataPacketTest, AddEventLatencyMetadataToGestures) { - GestureEventDataPacket packet = GestureEventDataPacket::FromTouch( - MockMotionEvent(MotionEvent::Action::DOWN)); - packet.Push(CreateGesture(ET_GESTURE_TAP)); - packet.Push(CreateGesture(ET_GESTURE_SCROLL_UPDATE)); - packet.Push(CreateGesture(ET_GESTURE_PINCH_UPDATE)); - - EventLatencyMetadata event_latency_metadata; - event_latency_metadata.scrolls_blocking_touch_dispatched_to_renderer = - base::TimeTicks::Now(); - packet.AddEventLatencyMetadataToGestures( - event_latency_metadata, - base::BindRepeating([](const ui::GestureEventData& data) { - return data.type() == ET_GESTURE_SCROLL_UPDATE; - })); - - EXPECT_TRUE(packet.gesture(0) - .details.GetEventLatencyMetadata() - .scrolls_blocking_touch_dispatched_to_renderer.is_null()); - EXPECT_EQ( - packet.gesture(1) - .details.GetEventLatencyMetadata() - .scrolls_blocking_touch_dispatched_to_renderer, - event_latency_metadata.scrolls_blocking_touch_dispatched_to_renderer); - EXPECT_TRUE(packet.gesture(2) - .details.GetEventLatencyMetadata() - .scrolls_blocking_touch_dispatched_to_renderer.is_null()); -} - } // namespace ui
diff --git a/ui/events/gesture_detection/touch_disposition_gesture_filter.cc b/ui/events/gesture_detection/touch_disposition_gesture_filter.cc index 4cb988e..219d06d3 100644 --- a/ui/events/gesture_detection/touch_disposition_gesture_filter.cc +++ b/ui/events/gesture_detection/touch_disposition_gesture_filter.cc
@@ -9,7 +9,6 @@ #include "base/auto_reset.h" #include "base/check_op.h" #include "base/notreached.h" -#include "base/trace_event/typed_macros.h" #include "ui/events/gesture_event_details.h" namespace ui { @@ -135,11 +134,6 @@ gesture_source == GestureEventDataPacket::TOUCH_START; } -bool DoAddInputTimestampsToGesture(const GestureEventData& gesture_data) { - return gesture_data.type() == EventType::ET_GESTURE_SCROLL_UPDATE || - gesture_data.type() == EventType::ET_GESTURE_SCROLL_BEGIN; -} - } // namespace // TouchDispositionGestureFilter @@ -207,8 +201,7 @@ void TouchDispositionGestureFilter::OnTouchEventAck( uint32_t unique_touch_event_id, bool event_consumed, - bool is_source_touch_event_set_blocking, - const absl::optional<EventLatencyMetadata>& event_latency_metadata) { + bool is_source_touch_event_set_blocking) { // Spurious asynchronous acks should not trigger a crash. if (IsEmpty() || (Head().empty() && sequences_.size() == 1)) return; @@ -223,17 +216,16 @@ Tail().back().gesture_source() != GestureEventDataPacket::TOUCH_TIMEOUT) { Tail().back().Ack(event_consumed, is_source_touch_event_set_blocking); if (sequences_.size() == 1 && Tail().size() == 1) - SendAckedEvents(event_latency_metadata); + SendAckedEvents(); } else { DCHECK(!Head().empty()); DCHECK_EQ(Head().front().unique_touch_event_id(), unique_touch_event_id); Head().front().Ack(event_consumed, is_source_touch_event_set_blocking); - SendAckedEvents(event_latency_metadata); + SendAckedEvents(); } } -void TouchDispositionGestureFilter::SendAckedEvents( - const absl::optional<EventLatencyMetadata>& event_latency_metadata) { +void TouchDispositionGestureFilter::SendAckedEvents() { // Dispatch all packets corresponding to ack'ed touches, as well as // any pending timeout-based packets. bool touch_packet_for_current_ack_handled = false; @@ -264,20 +256,8 @@ // Aura, we could trigger a touch-cancel). As popping the sequence destroys // the packet, we copy the packet before popping it. touch_packet_for_current_ack_handled = true; - GestureEventDataPacket packet = sequence.front(); + const GestureEventDataPacket packet = sequence.front(); sequence.pop(); - - if (source == GestureEventDataPacket::TOUCH_MOVE && - event_latency_metadata.has_value()) { - EventLatencyMetadata gesture_event_latency_metadata; - gesture_event_latency_metadata - .scrolls_blocking_touch_dispatched_to_renderer = - event_latency_metadata->dispatched_to_renderer; - packet.AddEventLatencyMetadataToGestures( - std::move(gesture_event_latency_metadata), - base::BindRepeating(DoAddInputTimestampsToGesture)); - } - FilterAndSendPacket(packet); } DCHECK(touch_packet_for_current_ack_handled);
diff --git a/ui/events/gesture_detection/touch_disposition_gesture_filter.h b/ui/events/gesture_detection/touch_disposition_gesture_filter.h index 10f2bd0..53bbd88 100644 --- a/ui/events/gesture_detection/touch_disposition_gesture_filter.h +++ b/ui/events/gesture_detection/touch_disposition_gesture_filter.h
@@ -9,12 +9,10 @@ #include "base/containers/queue.h" #include "base/memory/raw_ptr.h" -#include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/events/gesture_detection/bitset_32.h" #include "ui/events/gesture_detection/gesture_detection_export.h" #include "ui/events/gesture_detection/gesture_event_data_packet.h" #include "ui/events/types/event_type.h" -#include "ui/latency/latency_info.h" namespace ui { @@ -55,18 +53,9 @@ PacketResult OnGesturePacket(const GestureEventDataPacket& packet); // OnTouchEventAck must be called upon receipt of every touch event ack. - // |event_latency_metadata| is provided only if the touch event or - // corresponding touch event was blocked before sending to the Renderer. This - // definition of blocking is not related to the value of - // |is_source_touch_event_set_blocking| since - // |is_source_touch_event_set_blocking| refers to the behavior of blocking - // future inputs, not whether the current event was dispatched blocking to the - // renderer. void OnTouchEventAck(uint32_t unique_touch_event_id, bool event_consumed, - bool is_source_touch_event_set_blocking, - const absl::optional<EventLatencyMetadata>& - event_latency_metadata = absl::nullopt); + bool is_source_touch_event_set_blocking); // Whether there are any active gesture sequences still queued in the filter. bool IsEmpty() const; @@ -112,8 +101,7 @@ void CancelFlingIfNecessary(const GestureEventDataPacket& packet); void EndScrollIfNecessary(const GestureEventDataPacket& packet); void PopGestureSequence(); - void SendAckedEvents( - const absl::optional<EventLatencyMetadata>& event_latency_metadata); + void SendAckedEvents(); GestureSequence& Head(); GestureSequence& Tail();
diff --git a/ui/events/gesture_event_details.h b/ui/events/gesture_event_details.h index bdf8406..ce44240 100644 --- a/ui/events/gesture_event_details.h +++ b/ui/events/gesture_event_details.h
@@ -9,7 +9,6 @@ #include "base/check_op.h" #include "ui/events/event_constants.h" -#include "ui/events/event_latency_metadata.h" #include "ui/events/events_base_export.h" #include "ui/events/types/event_type.h" #include "ui/events/types/scroll_types.h" @@ -186,13 +185,6 @@ data_.scale = scale; } - const EventLatencyMetadata& GetEventLatencyMetadata() const { - return input_timestamps_; - } - EventLatencyMetadata& GetModifiableEventLatencyMetadata() { - return input_timestamps_; - } - // Supports comparison over internal structures for testing. bool operator==(const GestureEventDetails& other) const { return type_ == other.type_ && @@ -267,8 +259,6 @@ // Bounding box is an axis-aligned rectangle that contains all the // enclosing rectangles of the touch-points in the gesture. gfx::RectF bounding_box_; - - EventLatencyMetadata input_timestamps_; }; } // namespace ui
diff --git a/ui/events/mojom/BUILD.gn b/ui/events/mojom/BUILD.gn index 47a11bf..a1f910e6 100644 --- a/ui/events/mojom/BUILD.gn +++ b/ui/events/mojom/BUILD.gn
@@ -80,24 +80,3 @@ blink_cpp_typemaps = shared_cpp_typemaps webui_module_path = "chrome://resources/mojo/ui/events/mojom" } - -mojom("event_latency_metadata_mojom") { - generate_java = true - sources = [ "event_latency_metadata.mojom" ] - public_deps = [ "//mojo/public/mojom/base" ] - - cpp_typemaps = [ - { - types = [ - { - mojom = "ui.mojom.EventLatencyMetadata" - cpp = "::ui::EventLatencyMetadata" - }, - ] - - traits_headers = [ "event_latency_metadata_mojom_traits.h" ] - traits_sources = [ "event_latency_metadata_mojom_traits.cc" ] - traits_deps = [ "//ui/events:events_base" ] - }, - ] -}
diff --git a/ui/events/mojom/event_latency_metadata.mojom b/ui/events/mojom/event_latency_metadata.mojom deleted file mode 100644 index 615bdad..0000000 --- a/ui/events/mojom/event_latency_metadata.mojom +++ /dev/null
@@ -1,23 +0,0 @@ -// Copyright 2023 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -module ui.mojom; - -import "mojo/public/mojom/base/time.mojom"; - -// The struct contains metadata about EventLatency events. -// There should only be POD classes in this struct to keep the metadata to a -// minimum. -struct EventLatencyMetadata { - // Time when event arrived in the BrowserMain thread. - mojo_base.mojom.TimeTicks arrived_in_browser_main_timestamp; - - // This field is used only by scroll events to understand when the related - // blocking touch move was dispatched to Renderer. If the related touch move - // wasn't blocking, this field is not set. - mojo_base.mojom.TimeTicks scrolls_blocking_touch_dispatched_to_renderer; - - // Time when event was disppatched to the Renderer from the Browser. - mojo_base.mojom.TimeTicks dispatched_to_renderer; -};
diff --git a/ui/events/mojom/event_latency_metadata_mojom_traits.cc b/ui/events/mojom/event_latency_metadata_mojom_traits.cc deleted file mode 100644 index 9d1fa06..0000000 --- a/ui/events/mojom/event_latency_metadata_mojom_traits.cc +++ /dev/null
@@ -1,27 +0,0 @@ -// Copyright 2023 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ui/events/mojom/event_latency_metadata_mojom_traits.h" - -namespace mojo { - -// static -bool StructTraits< - ui::mojom::EventLatencyMetadataDataView, - ui::EventLatencyMetadata>::Read(ui::mojom::EventLatencyMetadataDataView in, - ui::EventLatencyMetadata* out) { - DCHECK(out != nullptr); - - if (!in.ReadArrivedInBrowserMainTimestamp( - &out->arrived_in_browser_main_timestamp) || - !in.ReadScrollsBlockingTouchDispatchedToRenderer( - &out->scrolls_blocking_touch_dispatched_to_renderer) || - !in.ReadDispatchedToRenderer(&out->dispatched_to_renderer)) { - return false; - } - - return true; -} - -} // namespace mojo
diff --git a/ui/events/mojom/event_latency_metadata_mojom_traits.h b/ui/events/mojom/event_latency_metadata_mojom_traits.h deleted file mode 100644 index 04bcb4f..0000000 --- a/ui/events/mojom/event_latency_metadata_mojom_traits.h +++ /dev/null
@@ -1,38 +0,0 @@ -// Copyright 2023 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef UI_EVENTS_MOJOM_EVENT_LATENCY_METADATA_MOJOM_TRAITS_H_ -#define UI_EVENTS_MOJOM_EVENT_LATENCY_METADATA_MOJOM_TRAITS_H_ - -#include "mojo/public/cpp/base/time_mojom_traits.h" -#include "mojo/public/cpp/bindings/struct_traits.h" -#include "ui/events/event_latency_metadata.h" -#include "ui/events/mojom/event_latency_metadata.mojom-shared.h" - -namespace mojo { - -template <> -struct StructTraits<ui::mojom::EventLatencyMetadataDataView, - ui::EventLatencyMetadata> { - static base::TimeTicks arrived_in_browser_main_timestamp( - const ui::EventLatencyMetadata& event_latency_metadata) { - return event_latency_metadata.arrived_in_browser_main_timestamp; - } - - static base::TimeTicks scrolls_blocking_touch_dispatched_to_renderer( - const ui::EventLatencyMetadata& event_latency_metadata) { - return event_latency_metadata.scrolls_blocking_touch_dispatched_to_renderer; - } - - static base::TimeTicks dispatched_to_renderer( - const ui::EventLatencyMetadata& event_latency_metadata) { - return event_latency_metadata.dispatched_to_renderer; - } - static bool Read(ui::mojom::EventLatencyMetadataDataView in, - ui::EventLatencyMetadata* out); -}; - -} // namespace mojo - -#endif // UI_EVENTS_MOJOM_EVENT_LATENCY_METADATA_MOJOM_TRAITS_H_ \ No newline at end of file
diff --git a/ui/latency/latency_info.cc b/ui/latency/latency_info.cc index ef364fc..dd76d2a 100644 --- a/ui/latency/latency_info.cc +++ b/ui/latency/latency_info.cc
@@ -148,10 +148,11 @@ AddLatencyNumberWithTimestampImpl(component, base::TimeTicks::Now(), nullptr); } -void LatencyInfo::AddLatencyNumberWithTraceName(LatencyComponentType component, - const char* trace_name_str, - base::TimeTicks now) { - AddLatencyNumberWithTimestampImpl(component, now, trace_name_str); +void LatencyInfo::AddLatencyNumberWithTraceName( + LatencyComponentType component, + const char* trace_name_str) { + AddLatencyNumberWithTimestampImpl(component, base::TimeTicks::Now(), + trace_name_str); } void LatencyInfo::AddLatencyNumberWithTimestamp(LatencyComponentType component,
diff --git a/ui/latency/latency_info.h b/ui/latency/latency_info.h index 3456e68..64dfa11 100644 --- a/ui/latency/latency_info.h +++ b/ui/latency/latency_info.h
@@ -130,8 +130,7 @@ // the trace event's name. // This function should only be called when adding a BEGIN component. void AddLatencyNumberWithTraceName(LatencyComponentType component, - const char* trace_name_str, - base::TimeTicks now); + const char* trace_name_str); // Modifies the current sequence number and adds a certain number of events // for a specific component.
diff --git a/ui/ozone/platform/flatland/flatland_screen.cc b/ui/ozone/platform/flatland/flatland_screen.cc index c716523..278ad392 100644 --- a/ui/ozone/platform/flatland/flatland_screen.cc +++ b/ui/ozone/platform/flatland/flatland_screen.cc
@@ -11,11 +11,16 @@ namespace ui { +namespace { +constexpr gfx::Size kDefaultDisplaySize = gfx::Size(1280, 720); +} // namespace + // TODO(crbug.com/1242052): Integrate with platform APIs for screen enumeration // and management, when available. FlatlandScreen::FlatlandScreen() - : displays_({display::Display::GetDefaultDisplay()}) {} + : displays_({display::Display(display::kDefaultDisplayId, + gfx::Rect(kDefaultDisplaySize))}) {} FlatlandScreen::~FlatlandScreen() = default;
diff --git a/ui/ozone/platform/wayland/host/wayland_input_method_context.cc b/ui/ozone/platform/wayland/host/wayland_input_method_context.cc index a245d2e6..6039e6fb 100644 --- a/ui/ozone/platform/wayland/host/wayland_input_method_context.cc +++ b/ui/ozone/platform/wayland/host/wayland_input_method_context.cc
@@ -254,7 +254,7 @@ const gfx::Range& text_range, const gfx::Range& selection_range) { // TODO(crbug.com/1402906): Text range is not currently handled correctly. - surrounding_text_tracker_.Update(text, selection_range); + surrounding_text_tracker_.Update(text, 0u, selection_range); if (!text_input_) return; @@ -463,7 +463,8 @@ void WaylandInputMethodContext::OnCursorPosition(int32_t index, int32_t anchor) { - const auto& [surrounding_text, selection, unused_composition_text] = + const auto& [surrounding_text, utf16_offset, selection, + unused_composition_text] = surrounding_text_tracker_.predicted_state(); if (surrounding_text.empty()) { @@ -520,7 +521,7 @@ void WaylandInputMethodContext::OnDeleteSurroundingText(int32_t index, uint32_t length) { - const auto& [surrounding_text, selection, unsused_composition] = + const auto& [surrounding_text, utf16_offset, selection, unsused_composition] = surrounding_text_tracker_.predicted_state(); DCHECK(selection.IsValid()); @@ -608,7 +609,8 @@ int32_t index, uint32_t length, const std::vector<SpanStyle>& spans) { - const auto& [surrounding_text, selection, unused_composition_text] = + const auto& [surrounding_text, utf16_offset, selection, + unused_composition_text] = surrounding_text_tracker_.predicted_state(); std::vector<size_t> selection_utf8_offsets = {selection.start(),
diff --git a/ui/views/BUILD.gn b/ui/views/BUILD.gn index 5aae27d..444ceb3 100644 --- a/ui/views/BUILD.gn +++ b/ui/views/BUILD.gn
@@ -1095,6 +1095,12 @@ "win/test_support/fake_ipen_device.h", "win/test_support/fake_ipen_device_statics.cc", "win/test_support/fake_ipen_device_statics.h", + "win/test_support/fake_ipen_pointer_point_statics.cc", + "win/test_support/fake_ipen_pointer_point_statics.h", + "win/test_support/fake_ipointer_point.cc", + "win/test_support/fake_ipointer_point.h", + "win/test_support/fake_ipointer_point_properties.cc", + "win/test_support/fake_ipointer_point_properties.h", ] } if (is_mac) {
diff --git a/ui/views/win/pen_event_processor.cc b/ui/views/win/pen_event_processor.cc index 7813863..5fe5d01 100644 --- a/ui/views/win/pen_event_processor.cc +++ b/ui/views/win/pen_event_processor.cc
@@ -65,6 +65,7 @@ rotation_angle += 180; int tilt_x = pointer_pen_info.tiltX; int tilt_y = pointer_pen_info.tiltY; + ui::PointerDetails pointer_details( input_type, mapped_pointer_id, /* radius_x */ 0.0f, /* radius_y */ 0.0f, pressure, rotation_angle, tilt_x, tilt_y, /* tangential_pressure */ 0.0f);
diff --git a/ui/views/win/pen_id_handler.cc b/ui/views/win/pen_id_handler.cc index 82451439..05c925e3 100644 --- a/ui/views/win/pen_id_handler.cc +++ b/ui/views/win/pen_id_handler.cc
@@ -24,11 +24,24 @@ } // namespace +using ABI::Windows::Devices::Input::IPenDevice; +using ABI::Windows::UI::Input::IPointerPoint; +using ABI::Windows::UI::Input::IPointerPointProperties; +using Microsoft::WRL::ComPtr; + +#define HID_USAGE_PAGE_DIGITIZER ((UINT)0x0d) +#define HID_USAGE_ID_TSN ((UINT)0x5b) +#define HID_USAGE_ID_TVID ((UINT)0x91) + PenIdHandler::GetPenDeviceStatics get_pen_device_statics = nullptr; +PenIdHandler::GetPointerPointStatics get_pointer_point_statics = nullptr; PenIdHandler::ScopedPenIdStaticsForTesting::ScopedPenIdStaticsForTesting( - PenIdHandler::GetPenDeviceStatics statics) - : resetter_(&get_pen_device_statics, statics) {} + PenIdHandler::GetPenDeviceStatics pen_device_statics, + PenIdHandler::GetPointerPointStatics pointer_point_statics) + : pen_device_resetter_(&get_pen_device_statics, pen_device_statics), + pointer_point_resetter_(&get_pointer_point_statics, + pointer_point_statics) {} PenIdHandler::ScopedPenIdStaticsForTesting::~ScopedPenIdStaticsForTesting() = default; @@ -41,6 +54,14 @@ if (FAILED(hr)) { pen_device_statics_ = nullptr; } + + hr = base::win::RoGetActivationFactory( + base::win::HStringReference(RuntimeClass_Windows_UI_Input_PointerPoint) + .Get(), + IID_PPV_ARGS(&pointer_point_statics_)); + if (FAILED(hr)) { + pointer_point_statics_ = nullptr; + } } PenIdHandler::~PenIdHandler() = default; @@ -51,15 +72,23 @@ } absl::optional<std::string> guid = TryGetGuid(pointer_id); - if (!guid.has_value()) { - return absl::nullopt; + if (guid.has_value()) { + auto entry = guid_to_id_map_.insert({guid.value(), current_id_}); + if (entry.second) { + current_id_++; + } + return entry.first->second; } - auto entry = guid_to_id_map_.insert({guid.value(), current_id_}); - if (entry.second) { - current_id_++; + PenIdHandler::TransducerId transducer_id = TryGetTransducerId(pointer_id); + if (transducer_id.tsn != TransducerId::kInvalidTSN) { + if (!transducer_id_to_id_map_.contains(transducer_id)) { + transducer_id_to_id_map_[transducer_id] = current_id_++; + } + return transducer_id_to_id_map_[transducer_id]; } - return entry.first->second; + + return absl::nullopt; } absl::optional<std::string> PenIdHandler::TryGetGuid(UINT32 pointer_id) const { @@ -88,4 +117,62 @@ return base::WideToUTF8(base::win::WStringFromGUID(pen_device_guid)); } +PenIdHandler::TransducerId PenIdHandler::TryGetTransducerId( + UINT32 pointer_id) const { + TransducerId transducer_id; + + // Override pointer point statics if in a test. + const Microsoft::WRL::ComPtr<ABI::Windows::UI::Input::IPointerPointStatics> + pointer_point_statics = + get_pointer_point_statics ? (*get_pointer_point_statics)() + : pointer_point_statics_; + + if (!pointer_point_statics) { + return transducer_id; + } + + ComPtr<IPointerPoint> pointer_point; + HRESULT hr = + pointer_point_statics->GetCurrentPoint(pointer_id, &pointer_point); + if (hr != S_OK) { + return transducer_id; + } + + ComPtr<IPointerPointProperties> pointer_point_properties; + hr = pointer_point->get_Properties(&pointer_point_properties); + if (hr != S_OK) { + return transducer_id; + } + + // Retrieve Transducer Serial Number and check if it's valid. + boolean has_tsn = false; + hr = pointer_point_properties->HasUsage(HID_USAGE_PAGE_DIGITIZER, + HID_USAGE_ID_TSN, &has_tsn); + + if (hr != S_OK || !has_tsn) { + return transducer_id; + } + + hr = pointer_point_properties->GetUsageValue( + HID_USAGE_PAGE_DIGITIZER, HID_USAGE_ID_TSN, &transducer_id.tsn); + + if (hr != S_OK || transducer_id.tsn == TransducerId::kInvalidTSN) { + return transducer_id; + } + + // Retrieve Transducer Vendor Id and check if it's valid. + boolean has_tvid = false; + hr = pointer_point_properties->HasUsage(HID_USAGE_PAGE_DIGITIZER, + HID_USAGE_ID_TVID, &has_tvid); + + if (hr != S_OK || !has_tvid) { + return transducer_id; + } + + hr = pointer_point_properties->GetUsageValue( + HID_USAGE_PAGE_DIGITIZER, HID_USAGE_ID_TVID, &transducer_id.tvid); + + return transducer_id; +} + } // namespace views
diff --git a/ui/views/win/pen_id_handler.h b/ui/views/win/pen_id_handler.h index e68e899..a0a5ce9 100644 --- a/ui/views/win/pen_id_handler.h +++ b/ui/views/win/pen_id_handler.h
@@ -31,14 +31,18 @@ public: using GetPenDeviceStatics = Microsoft::WRL::ComPtr< ABI::Windows::Devices::Input::IPenDeviceStatics> (*)(); + using GetPointerPointStatics = Microsoft::WRL::ComPtr< + ABI::Windows::UI::Input::IPointerPointStatics> (*)(); class VIEWS_EXPORT [[maybe_unused, nodiscard]] ScopedPenIdStaticsForTesting { public: explicit ScopedPenIdStaticsForTesting( - GetPenDeviceStatics pen_device_statics); + GetPenDeviceStatics pen_device_statics, + GetPointerPointStatics pointer_point_statics); ~ScopedPenIdStaticsForTesting(); private: - base::AutoReset<GetPenDeviceStatics> resetter_; + base::AutoReset<GetPenDeviceStatics> pen_device_resetter_; + base::AutoReset<GetPointerPointStatics> pointer_point_resetter_; }; PenIdHandler(); @@ -51,16 +55,45 @@ FRIEND_TEST_ALL_PREFIXES(PenIdHandlerTest, GetGuidMapping); FRIEND_TEST_ALL_PREFIXES(PenIdHandlerTest, PenDeviceStaticsFailedToSet); FRIEND_TEST_ALL_PREFIXES(PenIdHandlerTest, TryGetGuidHandlesBadStatics); + FRIEND_TEST_ALL_PREFIXES(PenIdHandlerTest, PenDeviceStaticsFailedToSet); + FRIEND_TEST_ALL_PREFIXES(PenIdHandlerTest, TryGetTransducerIdHandlesErrors); + + struct TransducerId { + int32_t tsn = 0; + int32_t tvid = 0; + static constexpr int32_t kInvalidTSN = 0; + bool operator<(const TransducerId& other) const { + if (this->tsn != other.tsn) { + return this->tsn < other.tsn; + } + return this->tvid < other.tvid; + } + bool operator==(const TransducerId& other) const { + if (this->tsn == other.tsn && this->tvid == other.tvid) { + return true; + } + return false; + } + }; // Virtual for unit testing. // Checks if a PenDevice can be retrieved for the `pointer_id` and returns its // GUID if it exists. virtual absl::optional<std::string> TryGetGuid(UINT32 pointer_id) const; + // This is a fallback scenario when TryGetGUID doesn't retrieve a PenDevice. + // Happens when the device doesn't have both TSN/TVID (e.g. + // SurfaceHub 1 + SurfaceHub Pen -> only has TSN, no TVID). + virtual TransducerId TryGetTransducerId(UINT32 pointer_id) const; base::flat_map<std::string, int32_t> guid_to_id_map_; + // Mapping from "Transducer Serial Number (TSN)" to `unique_id`. More + // information on TSN: https://www.usb.org/sites/default/files/hut1_22.pdf + base::flat_map<TransducerId, int32_t> transducer_id_to_id_map_; int32_t current_id_ = 0; Microsoft::WRL::ComPtr<ABI::Windows::Devices::Input::IPenDeviceStatics> pen_device_statics_; + Microsoft::WRL::ComPtr<ABI::Windows::UI::Input::IPointerPointStatics> + pointer_point_statics_; }; } // namespace views
diff --git a/ui/views/win/pen_id_handler_unittest.cc b/ui/views/win/pen_id_handler_unittest.cc index 09c73b8..df34364 100644 --- a/ui/views/win/pen_id_handler_unittest.cc +++ b/ui/views/win/pen_id_handler_unittest.cc
@@ -9,24 +9,32 @@ #include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/views/win/test_support/fake_ipen_device.h" #include "ui/views/win/test_support/fake_ipen_device_statics.h" +#include "ui/views/win/test_support/fake_ipen_pointer_point_statics.h" +#include "ui/views/win/test_support/fake_ipointer_point.h" +#include "ui/views/win/test_support/fake_ipointer_point_properties.h" namespace views { -namespace { +using ABI::Windows::Devices::Input::IPenDeviceStatics; +using ABI::Windows::UI::Input::IPointerPointStatics; + +constexpr int kPenId0 = 0; +constexpr int kPenId1 = 1; +constexpr int kPenId2 = 2; constexpr int kPointerId1 = 1111; constexpr int kPointerId2 = 2222; constexpr int kPointerId3 = 3333; constexpr int kPointerId4 = 4444; - -} // namespace +constexpr int kPointerId5 = 5555; class FakePenIdHandler : public PenIdHandler { public: FakePenIdHandler( - Microsoft::WRL::ComPtr<ABI::Windows::Devices::Input::IPenDeviceStatics> - pen_device_statics = nullptr) { + Microsoft::WRL::ComPtr<IPenDeviceStatics> pen_device_statics, + Microsoft::WRL::ComPtr<IPointerPointStatics> pointer_point_statics) { pen_device_statics_ = pen_device_statics; + pointer_point_statics_ = pointer_point_statics; } }; @@ -49,15 +57,15 @@ void PenIdHandlerTest::TearDown() { FakeIPenDeviceStatics::GetInstance()->SimulateAllPenDevicesRemoved(); + FakeIPenPointerPointStatics::GetInstance()->ClearPointerPointsMap(); } - // Tests TryGetPenUniqueId for devices that have a guid. The unique guid should -// be correctly mapped to a unique pen id, which is the value that is returned +// be correctly maped to a unique pen id, which is the value that is returned // by TryGetPenUniqueId. TEST_F(PenIdHandlerTest, GetGuidMapping) { Microsoft::WRL::ComPtr<FakeIPenDeviceStatics> pen_device_statics = FakeIPenDeviceStatics::GetInstance(); - FakePenIdHandler pen_id_handler(pen_device_statics); + FakePenIdHandler pen_id_handler(pen_device_statics, nullptr); // Make sure Get GUID works correctly. const auto fake_pen_device_1 = Microsoft::WRL::Make<FakeIPenDevice>(); @@ -86,12 +94,75 @@ EXPECT_EQ(id, pen_id_handler.TryGetPenUniqueId(kPointerId4)); } +// Tests TryGetPenUniqueId for devices that don't have a guid, but do have +// a transducer id. Makes sure the correct TransducerId is returned given a +// pointer id. +TEST_F(PenIdHandlerTest, GetTransducerIdMapping) { + Microsoft::WRL::ComPtr<FakeIPenPointerPointStatics> pointer_point_statics = + FakeIPenPointerPointStatics::GetInstance(); + FakePenIdHandler pen_id_handler(nullptr, pointer_point_statics); + + // Make sure Get GUID works correctly. + + const auto p1 = Microsoft::WRL::Make<FakeIPointerPoint>( + /*getProperties throw error*/ false, + /*has usage error*/ false, + /*get usage error*/ false, + /*tsn*/ 100, + /*tvid*/ 1); + const auto p2 = Microsoft::WRL::Make<FakeIPointerPoint>( + /*getProperties throw error*/ false, + /*has usage error*/ false, + /*get usage error*/ false, + /*tsn*/ 200, + /*tvid*/ 1); + const auto p3 = Microsoft::WRL::Make<FakeIPointerPoint>( + /*getProperties throw error*/ false, + /*has usage error*/ false, + /*get usage error*/ false, + /*tsn*/ 100, + /*tvid*/ 2); + const auto p4 = Microsoft::WRL::Make<FakeIPointerPoint>( + /*getProperties throw error*/ false, + /*has usage error*/ false, + /*get usage error*/ false, + /*tsn*/ 100, + /*tvid*/ 1); + + pointer_point_statics->AddPointerPoint(kPointerId1, p1); + pointer_point_statics->AddPointerPoint(kPointerId2, p2); + pointer_point_statics->AddPointerPoint(kPointerId3, p3); + pointer_point_statics->AddPointerPoint(kPointerId4, p4); + + absl::optional<int32_t> id = pen_id_handler.TryGetPenUniqueId(kPointerId1); + EXPECT_EQ(id, kPenId0); + + // Different serial number to previous should return a new unique id. + id = pen_id_handler.TryGetPenUniqueId(kPointerId2); + EXPECT_EQ(id, kPenId1); + + // Same serial number but different vendor id should result in a different + // returned unique id. + id = pen_id_handler.TryGetPenUniqueId(kPointerId3); + EXPECT_EQ(id, kPenId2); + + // Persisted id should be returned if transducer id is recognized. + id = pen_id_handler.TryGetPenUniqueId(kPointerId4); + EXPECT_EQ(id, kPenId0); + + // Unrecognized id should return a null optional. + id = pen_id_handler.TryGetPenUniqueId(kPointerId5); + EXPECT_EQ(id, absl::nullopt); +} + // Simulate statics not being set. This should result in TryGetGuid returning // absl::nullopt and TryGetTransducerId returning an invalid Transducer ID. // Ultimately TryGetPenUniqueId should return null. TEST_F(PenIdHandlerTest, PenDeviceStaticsFailedToSet) { - FakePenIdHandler pen_id_handler; + FakePenIdHandler pen_id_handler(nullptr, nullptr); EXPECT_EQ(pen_id_handler.TryGetGuid(kPointerId1), absl::nullopt); + EXPECT_EQ(pen_id_handler.TryGetTransducerId(kPointerId1), + PenIdHandler::TransducerId()); EXPECT_EQ(pen_id_handler.TryGetPenUniqueId(kPointerId1), absl::nullopt); } @@ -99,7 +170,7 @@ // Make sure `TryGetGUID` fails when there is no ID. Microsoft::WRL::ComPtr<FakeIPenDeviceStatics> pen_device_statics = FakeIPenDeviceStatics::GetInstance(); - FakePenIdHandler pen_id_handler(pen_device_statics); + FakePenIdHandler pen_id_handler(pen_device_statics, nullptr); EXPECT_EQ(pen_id_handler.TryGetGuid(kPointerId1), absl::nullopt); // When there is a GUID, it should be plumbed. @@ -108,4 +179,49 @@ EXPECT_EQ(pen_id_handler.TryGetGuid(kPointerId1), fake_pen_device->GetGuid()); } +TEST_F(PenIdHandlerTest, TryGetTransducerIdHandlesErrors) { + Microsoft::WRL::ComPtr<FakeIPenPointerPointStatics> pointer_point_statics = + FakeIPenPointerPointStatics::GetInstance(); + FakePenIdHandler pen_id_handler(nullptr, pointer_point_statics); + + // No current point found. + EXPECT_EQ(pen_id_handler.TryGetTransducerId(kPointerId1), + PenIdHandler::TransducerId()); + + // Current point found but point->GetProperties throws error. + const auto p = Microsoft::WRL::Make<FakeIPointerPoint>( + /*getProperties throw error*/ true); + pointer_point_statics->AddPointerPoint(kPointerId1, p); + EXPECT_EQ(pen_id_handler.TryGetTransducerId(kPointerId1), + PenIdHandler::TransducerId()); + + // has usage throws error. + const auto p1 = Microsoft::WRL::Make<FakeIPointerPoint>( + /*getProperties throw error*/ false, + /*has usage error*/ true); + pointer_point_statics->AddPointerPoint(kPointerId2, p1); + EXPECT_EQ(pen_id_handler.TryGetTransducerId(kPointerId2), + PenIdHandler::TransducerId()); + + // get usage throws error. + const auto p2 = Microsoft::WRL::Make<FakeIPointerPoint>( + /*getProperties throw error*/ false, + /*has usage error*/ false, + /*get usage error*/ true); + pointer_point_statics->AddPointerPoint(kPointerId3, p2); + EXPECT_EQ(pen_id_handler.TryGetTransducerId(kPointerId3), + PenIdHandler::TransducerId()); + + // Entire pipeline works correctly. + const auto p3 = Microsoft::WRL::Make<FakeIPointerPoint>( + /*getProperties throw error*/ false, + /*has usage error*/ false, + /*get usage error*/ false, + /*tsn*/ 100, + /*tvid*/ 200); + pointer_point_statics->AddPointerPoint(kPointerId4, p3); + EXPECT_EQ(pen_id_handler.TryGetTransducerId(kPointerId4), + (PenIdHandler::TransducerId{/*tsn*/ 100, /*tvid*/ 200})); +} + } // namespace views
diff --git a/ui/views/win/test_support/fake_ipen_pointer_point_statics.cc b/ui/views/win/test_support/fake_ipen_pointer_point_statics.cc new file mode 100644 index 0000000..a63ba9e --- /dev/null +++ b/ui/views/win/test_support/fake_ipen_pointer_point_statics.cc
@@ -0,0 +1,75 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/views/win/test_support/fake_ipen_pointer_point_statics.h" + +#include "base/no_destructor.h" +#include "base/notreached.h" + +namespace views { + +FakeIPenPointerPointStatics::FakeIPenPointerPointStatics() = default; +FakeIPenPointerPointStatics::~FakeIPenPointerPointStatics() = default; + +// static +FakeIPenPointerPointStatics* FakeIPenPointerPointStatics::GetInstance() { + // This instantiation contributes to singleton lazy initialization. + static base::NoDestructor<FakeIPenPointerPointStatics> instance; + return instance.get(); +} + +// static +Microsoft::WRL::ComPtr<IPointerPointStatics> +FakeIPenPointerPointStatics::FakeIPenPointerPointStaticsComPtr() { + FakeIPenPointerPointStatics* instance = GetInstance(); + return static_cast<Microsoft::WRL::ComPtr<IPointerPointStatics>>(instance); +} + +HRESULT FakeIPenPointerPointStatics::GetCurrentPoint( + UINT32 pointer_id, + ABI::Windows::UI::Input::IPointerPoint** result) { + auto pointer_point = pointer_point_map_.find(pointer_id); + if (pointer_point == pointer_point_map_.end()) { + return HRESULT_FROM_WIN32(ERROR_NOT_FOUND); + } + + // This call always return S_OK. + return pointer_point->second.CopyTo(result); +} + +void FakeIPenPointerPointStatics::AddPointerPoint( + UINT32 pointer_id, + Microsoft::WRL::ComPtr<ABI::Windows::UI::Input::IPointerPoint> + pointer_point) { + pointer_point_map_[pointer_id] = pointer_point; +} + +void FakeIPenPointerPointStatics::ClearPointerPointsMap() { + pointer_point_map_.clear(); +} + +HRESULT FakeIPenPointerPointStatics::GetIntermediatePoints( + UINT32 pointer_id, + ABI::Windows::Foundation::Collections::IVector< + ABI::Windows::UI::Input::PointerPoint*>** points) { + NOTIMPLEMENTED(); + return HRESULT_FROM_WIN32(ERROR_NOT_FOUND); +} +HRESULT FakeIPenPointerPointStatics::GetCurrentPointTransformed( + UINT32 pointer_id, + ABI::Windows::UI::Input::IPointerPointTransform* t, + ABI::Windows::UI::Input::IPointerPoint** p) { + NOTIMPLEMENTED(); + return HRESULT_FROM_WIN32(ERROR_NOT_FOUND); +} +HRESULT FakeIPenPointerPointStatics::GetIntermediatePointsTransformed( + UINT32 pointer_id, + ABI::Windows::UI::Input::IPointerPointTransform* t, + ABI::Windows::Foundation::Collections::IVector< + ABI::Windows::UI::Input::PointerPoint*>** points) { + NOTIMPLEMENTED(); + return HRESULT_FROM_WIN32(ERROR_NOT_FOUND); +} + +} // namespace views
diff --git a/ui/views/win/test_support/fake_ipen_pointer_point_statics.h b/ui/views/win/test_support/fake_ipen_pointer_point_statics.h new file mode 100644 index 0000000..c0a3c5637 --- /dev/null +++ b/ui/views/win/test_support/fake_ipen_pointer_point_statics.h
@@ -0,0 +1,78 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_VIEWS_WIN_TEST_SUPPORT_FAKE_IPEN_POINTER_POINT_STATICS_H_ +#define UI_VIEWS_WIN_TEST_SUPPORT_FAKE_IPEN_POINTER_POINT_STATICS_H_ + +#include <windows.devices.input.h> +#include <windows.foundation.collections.h> +#include <windows.ui.input.h> +#include <wrl.h> + +#include <unordered_map> + +#include "base/logging.h" +#include "base/strings/utf_string_conversions.h" +#include "base/win/core_winrt_util.h" +#include "base/win/hstring_reference.h" +#include "base/win/win_util.h" + +namespace views { + +using ABI::Windows::UI::Input::IPointerPoint; +using ABI::Windows::UI::Input::IPointerPointStatics; +using ABI::Windows::UI::Input::IPointerPointTransform; +using ABI::Windows::UI::Input::PointerPoint; + +// ABI::Windows::UI::Input::IPointerPointStatics fake implementation. +class FakeIPenPointerPointStatics final + : public Microsoft::WRL::RuntimeClass< + Microsoft::WRL::RuntimeClassFlags< + Microsoft::WRL::WinRt | Microsoft::WRL::InhibitRoOriginateError>, + IPointerPointStatics> { + public: + FakeIPenPointerPointStatics(); + + FakeIPenPointerPointStatics(const FakeIPenPointerPointStatics&) = delete; + FakeIPenPointerPointStatics& operator=(const FakeIPenPointerPointStatics&) = + delete; + + ~FakeIPenPointerPointStatics() final; + + static FakeIPenPointerPointStatics* GetInstance(); + static Microsoft::WRL::ComPtr<IPointerPointStatics> + FakeIPenPointerPointStaticsComPtr(); + + HRESULT WINAPI GetCurrentPoint(UINT32 pointer_id, + IPointerPoint** pointer_point) override; + + HRESULT STDMETHODCALLTYPE GetIntermediatePoints( + UINT32 pointer_id, + ABI::Windows::Foundation::Collections::IVector<PointerPoint*>** points) + override; + HRESULT STDMETHODCALLTYPE + GetCurrentPointTransformed(UINT32 pointer_id, + IPointerPointTransform* t, + IPointerPoint**) override; + HRESULT STDMETHODCALLTYPE GetIntermediatePointsTransformed( + UINT32 pointer_id, + IPointerPointTransform* t, + ABI::Windows::Foundation::Collections::IVector<PointerPoint*>** points) + override; + + // Test methods + void AddPointerPoint(UINT32 pointer_id, + Microsoft::WRL::ComPtr<IPointerPoint> pointer_point); + void ClearPointerPointsMap(); + + private: + std::unordered_map< + /*pointer_id=*/UINT32, + Microsoft::WRL::ComPtr<IPointerPoint>> + pointer_point_map_; +}; + +} // namespace views + +#endif // UI_VIEWS_WIN_TEST_SUPPORT_FAKE_IPEN_POINTER_POINT_STATICS_H_
diff --git a/ui/views/win/test_support/fake_ipointer_point.cc b/ui/views/win/test_support/fake_ipointer_point.cc new file mode 100644 index 0000000..160c2941 --- /dev/null +++ b/ui/views/win/test_support/fake_ipointer_point.cc
@@ -0,0 +1,83 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/views/win/test_support/fake_ipointer_point.h" + +#include <combaseapi.h> +#include <wchar.h> + +#include <string> + +#include "base/check_op.h" +#include "base/cxx17_backports.h" +#include "base/notreached.h" +#include "base/strings/string_piece_forward.h" +#include "base/strings/utf_string_conversions.h" +#include "base/win/win_util.h" +#include "ui/views/win/test_support/fake_ipointer_point_properties.h" + +using Microsoft::WRL::ComPtr; + +namespace views { + +FakeIPointerPoint::FakeIPointerPoint() + : properties_(Microsoft::WRL::Make<FakeIPointerPointProperties>()) {} + +FakeIPointerPoint::FakeIPointerPoint(bool throw_error_in_get_properties, + bool has_usage_throws_error, + bool get_usage_throws_error, + int tsn, + int tvid) + : throw_error_in_get_properties_(throw_error_in_get_properties), + properties_(Microsoft::WRL::Make<FakeIPointerPointProperties>( + has_usage_throws_error, + get_usage_throws_error, + tsn, + tvid)) {} + +FakeIPointerPoint::~FakeIPointerPoint() = default; + +HRESULT FakeIPointerPoint::get_Properties( + ABI::Windows::UI::Input::IPointerPointProperties** value) { + if (throw_error_in_get_properties_) { + return HRESULT_FROM_WIN32(ERROR_NOT_FOUND); + } + + properties_.CopyTo(value); + return S_OK; +} + +HRESULT WINAPI FakeIPointerPoint::get_PointerDevice( + ABI::Windows::Devices::Input::IPointerDevice** value) { + NOTIMPLEMENTED(); + return HRESULT_FROM_WIN32(ERROR_NOT_FOUND); +} +HRESULT WINAPI +FakeIPointerPoint::get_Position(ABI::Windows::Foundation::Point* value) { + NOTIMPLEMENTED(); + return HRESULT_FROM_WIN32(ERROR_NOT_FOUND); +} +HRESULT WINAPI +FakeIPointerPoint::get_RawPosition(ABI::Windows::Foundation::Point* value) { + NOTIMPLEMENTED(); + return HRESULT_FROM_WIN32(ERROR_NOT_FOUND); +} +HRESULT WINAPI FakeIPointerPoint::get_PointerId(UINT32* value) { + NOTIMPLEMENTED(); + return HRESULT_FROM_WIN32(ERROR_NOT_FOUND); +} +HRESULT WINAPI FakeIPointerPoint::get_FrameId(UINT32* value) { + NOTIMPLEMENTED(); + return HRESULT_FROM_WIN32(ERROR_NOT_FOUND); +} +HRESULT WINAPI FakeIPointerPoint::get_Timestamp(UINT64* value) { + NOTIMPLEMENTED(); + return HRESULT_FROM_WIN32(ERROR_NOT_FOUND); +} +HRESULT WINAPI FakeIPointerPoint::get_IsInContact(boolean* value) { + NOTIMPLEMENTED(); + return HRESULT_FROM_WIN32(ERROR_NOT_FOUND); +} + +} // namespace views
diff --git a/ui/views/win/test_support/fake_ipointer_point.h b/ui/views/win/test_support/fake_ipointer_point.h new file mode 100644 index 0000000..36f0be8 --- /dev/null +++ b/ui/views/win/test_support/fake_ipointer_point.h
@@ -0,0 +1,53 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_VIEWS_WIN_TEST_SUPPORT_FAKE_IPOINTER_POINT_H_ +#define UI_VIEWS_WIN_TEST_SUPPORT_FAKE_IPOINTER_POINT_H_ + +#include <windows.devices.input.h> +#include <windows.ui.input.h> +#include <wrl.h> + +#include "ui/views/win/test_support/fake_ipointer_point_properties.h" + +namespace views { + +// ABI::Windows::UI::Input::IPointerPoint fake implementation. +class FakeIPointerPoint final + : public Microsoft::WRL::RuntimeClass< + Microsoft::WRL::RuntimeClassFlags< + Microsoft::WRL::WinRt | Microsoft::WRL::InhibitRoOriginateError>, + ABI::Windows::UI::Input::IPointerPoint> { + public: + FakeIPointerPoint(); + FakeIPointerPoint(bool throw_error_in_get_properties, + bool has_usage_throws_error = false, + bool get_usage_throws_error = false, + int tsn = 0, + int tvid = 0); + explicit FakeIPointerPoint(FakeIPointerPointProperties* p); + FakeIPointerPoint& operator=(const FakeIPointerPoint&) = delete; + + ~FakeIPointerPoint() override; + + HRESULT WINAPI get_Properties( + ABI::Windows::UI::Input::IPointerPointProperties** + pointer_point_properties) override; + HRESULT WINAPI + get_PointerDevice(ABI::Windows::Devices::Input::IPointerDevice**) override; + HRESULT WINAPI get_Position(ABI::Windows::Foundation::Point*) override; + HRESULT WINAPI get_RawPosition(ABI::Windows::Foundation::Point*) override; + HRESULT WINAPI get_PointerId(UINT32*) override; + HRESULT WINAPI get_FrameId(UINT32*) override; + HRESULT WINAPI get_Timestamp(UINT64*) override; + HRESULT WINAPI get_IsInContact(boolean*) override; + + private: + bool throw_error_in_get_properties_ = false; + Microsoft::WRL::ComPtr<FakeIPointerPointProperties> properties_; +}; + +} // namespace views + +#endif // UI_VIEWS_WIN_TEST_SUPPORT_FAKE_IPOINTER_POINT_H_
diff --git a/ui/views/win/test_support/fake_ipointer_point_properties.cc b/ui/views/win/test_support/fake_ipointer_point_properties.cc new file mode 100644 index 0000000..de494095 --- /dev/null +++ b/ui/views/win/test_support/fake_ipointer_point_properties.cc
@@ -0,0 +1,155 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/views/win/test_support/fake_ipointer_point_properties.h" + +#include <combaseapi.h> +#include <wchar.h> + +#include <string> + +#include "base/check_op.h" +#include "base/cxx17_backports.h" +#include "base/notreached.h" +#include "base/strings/string_piece_forward.h" +#include "base/strings/utf_string_conversions.h" +#include "base/win/win_util.h" + +using Microsoft::WRL::ComPtr; + +namespace views { + +#define HID_USAGE_ID_TSN ((UINT)0x5b) +#define HID_USAGE_ID_TVID ((UINT)0x91) + +FakeIPointerPointProperties::FakeIPointerPointProperties() = default; +FakeIPointerPointProperties::FakeIPointerPointProperties( + bool has_usage_throws_error, + bool get_usage_throws_error, + int tsn, + int tvid) + : has_usage_throws_error_(has_usage_throws_error), + get_usage_throws_error_(get_usage_throws_error), + tsn_(tsn), + tvid_(tvid) {} + +FakeIPointerPointProperties::~FakeIPointerPointProperties() = default; + +HRESULT FakeIPointerPointProperties::get_IsInverted(boolean*) { + NOTIMPLEMENTED(); + return S_OK; +} +HRESULT FakeIPointerPointProperties::get_Pressure(float*) { + NOTIMPLEMENTED(); + return S_OK; +} +HRESULT FakeIPointerPointProperties::get_IsEraser(boolean*) { + NOTIMPLEMENTED(); + return S_OK; +} +HRESULT FakeIPointerPointProperties::get_Orientation(float*) { + NOTIMPLEMENTED(); + return S_OK; +} +HRESULT FakeIPointerPointProperties::get_XTilt(float*) { + NOTIMPLEMENTED(); + return S_OK; +} +HRESULT FakeIPointerPointProperties::get_YTilt(float*) { + NOTIMPLEMENTED(); + return S_OK; +} +HRESULT FakeIPointerPointProperties::get_Twist(float*) { + NOTIMPLEMENTED(); + return S_OK; +} +HRESULT FakeIPointerPointProperties::get_ContactRect( + ABI::Windows::Foundation::Rect*) { + NOTIMPLEMENTED(); + return S_OK; +} +HRESULT FakeIPointerPointProperties::get_ContactRectRaw( + ABI::Windows::Foundation::Rect*) { + NOTIMPLEMENTED(); + return S_OK; +} +HRESULT FakeIPointerPointProperties::get_TouchConfidence(boolean*) { + NOTIMPLEMENTED(); + return S_OK; +} +HRESULT FakeIPointerPointProperties::get_IsLeftButtonPressed(boolean*) { + NOTIMPLEMENTED(); + return S_OK; +} +HRESULT FakeIPointerPointProperties::get_IsRightButtonPressed(boolean*) { + NOTIMPLEMENTED(); + return S_OK; +} +HRESULT FakeIPointerPointProperties::get_IsMiddleButtonPressed(boolean*) { + NOTIMPLEMENTED(); + return S_OK; +} +HRESULT FakeIPointerPointProperties::get_MouseWheelDelta(INT32*) { + NOTIMPLEMENTED(); + return S_OK; +} +HRESULT FakeIPointerPointProperties::get_IsHorizontalMouseWheel(boolean*) { + NOTIMPLEMENTED(); + return S_OK; +} +HRESULT FakeIPointerPointProperties::get_IsPrimary(boolean*) { + NOTIMPLEMENTED(); + return S_OK; +} +HRESULT FakeIPointerPointProperties::get_IsInRange(boolean*) { + NOTIMPLEMENTED(); + return S_OK; +} +HRESULT FakeIPointerPointProperties::get_IsCanceled(boolean*) { + NOTIMPLEMENTED(); + return S_OK; +} +HRESULT FakeIPointerPointProperties::get_IsBarrelButtonPressed(boolean*) { + NOTIMPLEMENTED(); + return S_OK; +} +HRESULT FakeIPointerPointProperties::get_IsXButton1Pressed(boolean*) { + NOTIMPLEMENTED(); + return S_OK; +} +HRESULT FakeIPointerPointProperties::get_IsXButton2Pressed(boolean*) { + NOTIMPLEMENTED(); + return S_OK; +} +HRESULT FakeIPointerPointProperties::get_PointerUpdateKind( + ABI::Windows::UI::Input::PointerUpdateKind*) { + NOTIMPLEMENTED(); + return S_OK; +} +HRESULT FakeIPointerPointProperties::HasUsage(UINT32, UINT32, boolean* value) { + if (has_usage_throws_error_) { + return HRESULT_FROM_WIN32(ERROR_NOT_FOUND); + } + + *value = true; + return S_OK; +} +HRESULT FakeIPointerPointProperties::GetUsageValue(UINT32 a, + UINT32 id_type, + INT32* value) { + if (get_usage_throws_error_) { + return HRESULT_FROM_WIN32(ERROR_NOT_FOUND); + } + + if (id_type == HID_USAGE_ID_TSN) { + *value = tsn(); + } else if (id_type == HID_USAGE_ID_TVID) { + *value = tvid(); + } else { + NOTREACHED(); + } + return S_OK; +} + +} // namespace views
diff --git a/ui/views/win/test_support/fake_ipointer_point_properties.h b/ui/views/win/test_support/fake_ipointer_point_properties.h new file mode 100644 index 0000000..38d59c09 --- /dev/null +++ b/ui/views/win/test_support/fake_ipointer_point_properties.h
@@ -0,0 +1,71 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_VIEWS_WIN_TEST_SUPPORT_FAKE_IPOINTER_POINT_PROPERTIES_H_ +#define UI_VIEWS_WIN_TEST_SUPPORT_FAKE_IPOINTER_POINT_PROPERTIES_H_ + +#include <windows.devices.input.h> +#include <windows.ui.input.h> +#include <wrl.h> + +namespace views { + +// ABI::Windows::UI::Input::IPointerPointProperties fake implementation. +class FakeIPointerPointProperties final + : public Microsoft::WRL::RuntimeClass< + Microsoft::WRL::RuntimeClassFlags< + Microsoft::WRL::WinRt | Microsoft::WRL::InhibitRoOriginateError>, + ABI::Windows::UI::Input::IPointerPointProperties> { + public: + FakeIPointerPointProperties(); + FakeIPointerPointProperties(bool has_usage_throws_error, + bool get_usage_throws_error, + int tsn, + int tvid); + FakeIPointerPointProperties& operator=(const FakeIPointerPointProperties&) = + delete; + + ~FakeIPointerPointProperties() override; + + HRESULT STDMETHODCALLTYPE get_IsInverted(boolean*) override; + HRESULT STDMETHODCALLTYPE get_Pressure(float*) override; + HRESULT STDMETHODCALLTYPE get_IsEraser(boolean*) override; + HRESULT STDMETHODCALLTYPE get_Orientation(float*) override; + HRESULT STDMETHODCALLTYPE get_XTilt(float*) override; + HRESULT STDMETHODCALLTYPE get_YTilt(float*) override; + HRESULT STDMETHODCALLTYPE get_Twist(float*) override; + HRESULT STDMETHODCALLTYPE + get_ContactRect(ABI::Windows::Foundation::Rect*) override; + HRESULT STDMETHODCALLTYPE + get_ContactRectRaw(ABI::Windows::Foundation::Rect*) override; + HRESULT STDMETHODCALLTYPE get_TouchConfidence(boolean*) override; + HRESULT STDMETHODCALLTYPE get_IsLeftButtonPressed(boolean*) override; + HRESULT STDMETHODCALLTYPE get_IsRightButtonPressed(boolean*) override; + HRESULT STDMETHODCALLTYPE get_IsMiddleButtonPressed(boolean*) override; + HRESULT STDMETHODCALLTYPE get_MouseWheelDelta(INT32*) override; + HRESULT STDMETHODCALLTYPE get_IsHorizontalMouseWheel(boolean*) override; + HRESULT STDMETHODCALLTYPE get_IsPrimary(boolean*) override; + HRESULT STDMETHODCALLTYPE get_IsInRange(boolean*) override; + HRESULT STDMETHODCALLTYPE get_IsCanceled(boolean*) override; + HRESULT STDMETHODCALLTYPE get_IsBarrelButtonPressed(boolean*) override; + HRESULT STDMETHODCALLTYPE get_IsXButton1Pressed(boolean*) override; + HRESULT STDMETHODCALLTYPE get_IsXButton2Pressed(boolean*) override; + HRESULT STDMETHODCALLTYPE + get_PointerUpdateKind(ABI::Windows::UI::Input::PointerUpdateKind*) override; + HRESULT STDMETHODCALLTYPE HasUsage(UINT32, UINT32, boolean*) override; + HRESULT STDMETHODCALLTYPE GetUsageValue(UINT32, UINT32, INT32*) override; + + int tsn() { return tsn_; } + int tvid() { return tvid_; } + + private: + bool has_usage_throws_error_ = false; + bool get_usage_throws_error_ = false; + int tsn_; + int tvid_; +}; + +} // namespace views + +#endif // UI_VIEWS_WIN_TEST_SUPPORT_FAKE_IPOINTER_POINT_PROPERTIES_H_
diff --git a/ui/webui/resources/tools/build_webui.gni b/ui/webui/resources/tools/build_webui.gni index edf9b29..8d4ba38 100644 --- a/ui/webui/resources/tools/build_webui.gni +++ b/ui/webui/resources/tools/build_webui.gni
@@ -376,6 +376,10 @@ excludes = invoker.optimize_webui_excludes } + if (defined(invoker.optimize_webui_external_paths)) { + external_paths = invoker.optimize_webui_external_paths + } + deps = [ ":build_ts" ] } }