diff --git a/DEPS b/DEPS index 4469de0..c89fecb 100644 --- a/DEPS +++ b/DEPS
@@ -300,7 +300,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. - 'src_internal_revision': 'f964ce98d3a6b672509d3e584959338d0c8c9827', + 'src_internal_revision': 'caa0380f0b26c677fedd3a3829236c0d8414c8ae', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and whatever else without interference from each other. @@ -308,11 +308,11 @@ # 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': '208e64a3826d88df2c2c21a0ccbd501e4c39408c', + 'v8_revision': '5df25f061a57285d5ba77884b65b1b4ba0835759', # 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': 'f1e1987261215891dd310f886544c32e1d5dbbcf', + 'angle_revision': '1572f609c18e12eef702983c58b563f58acad1c3', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. @@ -391,7 +391,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling devtools-frontend # and whatever else without interference from each other. - 'devtools_frontend_revision': 'e653e7f03c2faa8eebf2cfdd4c5c82e1730612c2', + 'devtools_frontend_revision': 'cf6706a3cb404a78a7bdec9900bb106ef7faf731', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libprotobuf-mutator # and whatever else without interference from each other. @@ -431,7 +431,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'dawn_revision': '261e510cd3298f69b23c65a0d2288d4ba03647bf', + 'dawn_revision': 'bfe346b8723e37a23de1f4b199bfaeff156ae70a', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -1249,7 +1249,7 @@ Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'), 'src/third_party/devtools-frontend-internal': { - 'url': Var('chrome_git') + '/devtools/devtools-internal.git' + '@' + 'd81bfc61bbfd36996528309d51baa321448ea964', + 'url': Var('chrome_git') + '/devtools/devtools-internal.git' + '@' + '4dd947a96a4953f3fc2c2da2ca0b4181676e48c8', 'condition': 'checkout_src_internal', }, @@ -1705,7 +1705,7 @@ Var('chromium_git') + '/external/github.com/cisco/openh264' + '@' + '09a4f3ec842a8932341b195c5b01e141c8a16eb7', 'src/third_party/openscreen/src': - Var('chromium_git') + '/openscreen' + '@' + '15348b85c11a6ca20a6c93ac5bad4018e2ebb1ca', + Var('chromium_git') + '/openscreen' + '@' + '03ab64e47e14f7b4c8ac50e651b2ef1cbb1f9b92', 'src/third_party/openxr/src': { 'url': Var('chromium_git') + '/external/github.com/KhronosGroup/OpenXR-SDK' + '@' + '58a00cf85c39ad5ec4dc43a769624e420c06179a', @@ -1716,7 +1716,7 @@ Var('pdfium_git') + '/pdfium.git' + '@' + Var('pdfium_revision'), 'src/third_party/perfetto': - Var('android_git') + '/platform/external/perfetto.git' + '@' + 'a124832ae9ce7a717e68dc569ee99dc151046258', + Var('android_git') + '/platform/external/perfetto.git' + '@' + '67cf047d357b44d870ac51a74a578ce462bac047', 'src/third_party/perl': { 'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3', @@ -2015,7 +2015,7 @@ 'packages': [ { 'package': 'chromeos_internal/apps/eche_app/app', - 'version': 'k7xonW_WNZwSrxN7tuRU321LUBL--Y0vy6PIthiYv88C', + 'version': 'AGaYoE5HgGxUdavPZXZ_WmzKlTj-huAqcrS67fSFdYwC', }, ], 'condition': 'checkout_chromeos and checkout_src_internal',
diff --git a/ash/accessibility/accessibility_controller_impl.cc b/ash/accessibility/accessibility_controller_impl.cc index 7865cf7..6d83d3f 100644 --- a/ash/accessibility/accessibility_controller_impl.cc +++ b/ash/accessibility/accessibility_controller_impl.cc
@@ -66,7 +66,6 @@ #include "components/vector_icons/vector_icons.h" #include "media/base/media_switches.h" #include "ui/accessibility/accessibility_features.h" -#include "ui/accessibility/accessibility_switches.h" #include "ui/accessibility/aura/aura_window_properties.h" #include "ui/aura/window.h" #include "ui/base/cursor/cursor_size.h"
diff --git a/ash/capture_mode/camera_video_frame_renderer.cc b/ash/capture_mode/camera_video_frame_renderer.cc index 7c094934..8f8a63aea 100644 --- a/ash/capture_mode/camera_video_frame_renderer.cc +++ b/ash/capture_mode/camera_video_frame_renderer.cc
@@ -43,8 +43,7 @@ GetContextFactory(), std::move(camera_video_source), capture_format), - context_provider_(GetContextFactory()->SharedMainThreadContextProvider()), - raster_context_provider_( + context_provider_( GetContextFactory()->SharedMainThreadRasterContextProvider()), should_flip_frames_horizontally_(should_flip_frames_horizontally) { host_window_.set_owned_by_parent(false); @@ -69,10 +68,10 @@ layer_tree_frame_sink_->BindToClient(this); const int max_texture_size = - raster_context_provider_->ContextCapabilities().max_texture_size; + context_provider_->ContextCapabilities().max_texture_size; video_resource_updater_ = std::make_unique<media::VideoResourceUpdater>( - context_provider_.get(), raster_context_provider_.get(), - layer_tree_frame_sink_.get(), &client_resource_provider_, + context_provider_.get(), layer_tree_frame_sink_.get(), + &client_resource_provider_, /*use_stream_video_draw_quad=*/false, /*use_gpu_memory_buffer_resources=*/false, /*use_r16_texture=*/false, max_texture_size); @@ -288,7 +287,7 @@ std::vector<viz::TransferableResource> resource_list; client_resource_provider_.PrepareSendToParent(resource_ids, &resource_list, - raster_context_provider_.get()); + context_provider_.get()); compositor_frame.resource_list = std::move(resource_list); return compositor_frame;
diff --git a/ash/capture_mode/camera_video_frame_renderer.h b/ash/capture_mode/camera_video_frame_renderer.h index 47a2de5b..a4a4743 100644 --- a/ash/capture_mode/camera_video_frame_renderer.h +++ b/ash/capture_mode/camera_video_frame_renderer.h
@@ -26,7 +26,6 @@ } // namespace media namespace viz { -class ContextProvider; class RasterContextProvider; } // namespace viz @@ -114,8 +113,7 @@ gfx::Size last_compositor_frame_size_pixels_; float last_compositor_frame_dsf_ = 1.0f; - scoped_refptr<viz::ContextProvider> context_provider_; - scoped_refptr<viz::RasterContextProvider> raster_context_provider_; + scoped_refptr<viz::RasterContextProvider> context_provider_; // The layer tree frame sink created from `host_window_`, which is used to // submit compositor frames for the camera video frames.
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc index 53c77b42..8a104a04 100644 --- a/ash/constants/ash_features.cc +++ b/ash/constants/ash_features.cc
@@ -245,6 +245,11 @@ "CrosBatterySaver", base::FEATURE_DISABLED_BY_DEFAULT); +// Make Battery Saver on all the time, even when charged or charging. +BASE_FEATURE(kBatterySaverAlwaysOn, + "CrosBatterySaverAlwaysOn", + base::FEATURE_DISABLED_BY_DEFAULT); + // Enables or disables the usage of fixed Bluetooth A2DP packet size to improve // audio performance in noisy environment. BASE_FEATURE(kBluetoothFixA2dpPacketSize, @@ -417,7 +422,7 @@ // Enables or disables Crostini IME support. BASE_FEATURE(kCrostiniImeSupport, "CrostiniImeSupport", - base::FEATURE_DISABLED_BY_DEFAULT); + base::FEATURE_ENABLED_BY_DEFAULT); // Enables or disables Crostini Qt application IME support. BASE_FEATURE(kCrostiniQtImeSupport, @@ -2672,6 +2677,10 @@ return base::FeatureList::IsEnabled(kBatterySaver); } +bool IsBatterySaverAlwaysOn() { + return base::FeatureList::IsEnabled(kBatterySaverAlwaysOn); +} + bool IsBluetoothQualityReportEnabled() { return base::FeatureList::IsEnabled(kBluetoothQualityReport); }
diff --git a/ash/constants/ash_features.h b/ash/constants/ash_features.h index 74cec21..35bf3cb 100644 --- a/ash/constants/ash_features.h +++ b/ash/constants/ash_features.h
@@ -74,6 +74,7 @@ BASE_DECLARE_FEATURE(kAutozoomNudgeSessionReset); COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kAvatarsCloudMigration); COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kBatterySaver); +COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kBatterySaverAlwaysOn); COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kBluetoothFixA2dpPacketSize); COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kBluetoothQualityReport); @@ -744,6 +745,7 @@ COMPONENT_EXPORT(ASH_CONSTANTS) bool IsAudioHFPNbsWarningEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsBackgroundBlurEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsBatterySaverAvailable(); +COMPONENT_EXPORT(ASH_CONSTANTS) bool IsBatterySaverAlwaysOn(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsBluetoothQualityReportEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsCalendarJellyEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsCaptivePortalErrorPageEnabled();
diff --git a/ash/events/event_rewriter_controller_impl.cc b/ash/events/event_rewriter_controller_impl.cc index c9188c9..a8f8db2 100644 --- a/ash/events/event_rewriter_controller_impl.cc +++ b/ash/events/event_rewriter_controller_impl.cc
@@ -15,7 +15,6 @@ #include "ash/public/cpp/accessibility_event_rewriter_delegate.h" #include "ash/shell.h" #include "base/command_line.h" -#include "ui/accessibility/accessibility_switches.h" #include "ui/aura/env.h" #include "ui/aura/window_tree_host.h" #include "ui/events/event_sink.h"
diff --git a/ash/shelf/login_shelf_view_unittest.cc b/ash/shelf/login_shelf_view_unittest.cc index b31e804..f774c5f4 100644 --- a/ash/shelf/login_shelf_view_unittest.cc +++ b/ash/shelf/login_shelf_view_unittest.cc
@@ -1035,15 +1035,6 @@ const char kShelfShutdownConfirmationActionHistogramName[] = "Ash.Shelf.ShutdownConfirmationBubble.Action"; -const char kCancelActionDurationHistogramName[] = - "Ash.Shelf.ShutdownConfirmationBubble.ActionDuration.Cancel"; - -const char kConfirmActionDurationHistogramName[] = - "Ash.Shelf.ShutdownConfirmationBubble.ActionDuration.Confirm"; - -const char kDismissActionDurationHistogramName[] = - "Ash.Shelf.ShutdownConfirmationBubble.ActionDuration.Dismiss"; - } // namespace class LoginShelfViewWithShutdownConfirmationTest : public LoginShelfViewTest { @@ -1136,9 +1127,6 @@ ShelfShutdownConfirmationBubble::BubbleAction::kOpened, 1); histograms().ExpectTotalCount(kShelfShutdownConfirmationActionHistogramName, 1); - histograms().ExpectTotalCount(kCancelActionDurationHistogramName, 0); - histograms().ExpectTotalCount(kDismissActionDurationHistogramName, 0); - histograms().ExpectTotalCount(kConfirmActionDurationHistogramName, 0); } // Checks that shutdown confirmation bubble appears after pressing the @@ -1161,9 +1149,6 @@ ShelfShutdownConfirmationBubble::BubbleAction::kOpened, 1); histograms().ExpectTotalCount(kShelfShutdownConfirmationActionHistogramName, 1); - histograms().ExpectTotalCount(kCancelActionDurationHistogramName, 0); - histograms().ExpectTotalCount(kDismissActionDurationHistogramName, 0); - histograms().ExpectTotalCount(kConfirmActionDurationHistogramName, 0); } // Checks that shutdown confirmation bubble disappears after pressing the @@ -1194,9 +1179,6 @@ ShelfShutdownConfirmationBubble::BubbleAction::kCancelled, 1); histograms().ExpectTotalCount(kShelfShutdownConfirmationActionHistogramName, 2); - histograms().ExpectTotalCount(kCancelActionDurationHistogramName, 1); - histograms().ExpectTotalCount(kDismissActionDurationHistogramName, 0); - histograms().ExpectTotalCount(kConfirmActionDurationHistogramName, 0); // Shutdown confirmation could be shown again. Click(LoginShelfView::kShutdown); @@ -1207,9 +1189,6 @@ ShelfShutdownConfirmationBubble::BubbleAction::kOpened, 2); histograms().ExpectTotalCount(kShelfShutdownConfirmationActionHistogramName, 3); - histograms().ExpectTotalCount(kCancelActionDurationHistogramName, 1); - histograms().ExpectTotalCount(kDismissActionDurationHistogramName, 0); - histograms().ExpectTotalCount(kConfirmActionDurationHistogramName, 0); } // Checks that shutdown confirmation bubble disappears after pressing the @@ -1241,9 +1220,6 @@ ShelfShutdownConfirmationBubble::BubbleAction::kConfirmed, 1); histograms().ExpectTotalCount(kShelfShutdownConfirmationActionHistogramName, 2); - histograms().ExpectTotalCount(kCancelActionDurationHistogramName, 0); - histograms().ExpectTotalCount(kDismissActionDurationHistogramName, 0); - histograms().ExpectTotalCount(kConfirmActionDurationHistogramName, 1); } // Checks that shutdown confirmation bubble disappears after inactive. @@ -1273,9 +1249,6 @@ ShelfShutdownConfirmationBubble::BubbleAction::kDismissed, 1); histograms().ExpectTotalCount(kShelfShutdownConfirmationActionHistogramName, 2); - histograms().ExpectTotalCount(kCancelActionDurationHistogramName, 0); - histograms().ExpectTotalCount(kDismissActionDurationHistogramName, 1); - histograms().ExpectTotalCount(kConfirmActionDurationHistogramName, 0); } // Checks that shutdown confirmation was first cancelled, then confirmed @@ -1305,9 +1278,6 @@ ShelfShutdownConfirmationBubble::BubbleAction::kCancelled, 1); histograms().ExpectTotalCount(kShelfShutdownConfirmationActionHistogramName, 2); - histograms().ExpectTotalCount(kCancelActionDurationHistogramName, 1); - histograms().ExpectTotalCount(kDismissActionDurationHistogramName, 0); - histograms().ExpectTotalCount(kConfirmActionDurationHistogramName, 0); // Shutdown confirmation could be shown again. Click(LoginShelfView::kShutdown); @@ -1318,9 +1288,6 @@ ShelfShutdownConfirmationBubble::BubbleAction::kOpened, 2); histograms().ExpectTotalCount(kShelfShutdownConfirmationActionHistogramName, 3); - histograms().ExpectTotalCount(kCancelActionDurationHistogramName, 1); - histograms().ExpectTotalCount(kDismissActionDurationHistogramName, 0); - histograms().ExpectTotalCount(kConfirmActionDurationHistogramName, 0); // Shutdown confirmation is confirmed and disappeared. ConfirmShutdown(); @@ -1331,9 +1298,6 @@ ShelfShutdownConfirmationBubble::BubbleAction::kConfirmed, 1); histograms().ExpectTotalCount(kShelfShutdownConfirmationActionHistogramName, 4); - histograms().ExpectTotalCount(kCancelActionDurationHistogramName, 1); - histograms().ExpectTotalCount(kDismissActionDurationHistogramName, 0); - histograms().ExpectTotalCount(kConfirmActionDurationHistogramName, 1); } // When display is on Shutdown button clicks should not be blocked.
diff --git a/ash/shelf/shelf_shutdown_confirmation_bubble.cc b/ash/shelf/shelf_shutdown_confirmation_bubble.cc index f8530e17..30a358e 100644 --- a/ash/shelf/shelf_shutdown_confirmation_bubble.cc +++ b/ash/shelf/shelf_shutdown_confirmation_bubble.cc
@@ -15,9 +15,6 @@ #include "base/functional/callback_forward.h" #include "base/functional/callback_helpers.h" #include "base/metrics/histogram_functions.h" -#include "base/notreached.h" -#include "base/strings/strcat.h" -#include "base/time/time.h" #include "chromeos/constants/chromeos_features.h" #include "components/strings/grit/components_strings.h" #include "components/vector_icons/vector_icons.h" @@ -54,29 +51,6 @@ constexpr char kActionHistogramName[] = "Ash.Shelf.ShutdownConfirmationBubble.Action"; -// Histogram for tracking the time delta between bubble opened and actions taken -// on the shelf shutdown confirmation bubble. -constexpr char kActionDurationHistogramPrefix[] = - "Ash.Shelf.ShutdownConfirmationBubble.ActionDuration."; - -// Suffix for shutdown confirmation action. Should match suffixes of the -// Ash.Shelf.ShutdownConfirmationBubble.ActionDuration.* metrics in -// metadata/ash/histograms.xml -std::string BubbleActionSuffix( - ShelfShutdownConfirmationBubble::BubbleAction action) { - switch (action) { - case ShelfShutdownConfirmationBubble::BubbleAction::kCancelled: - return "Cancel"; - case ShelfShutdownConfirmationBubble::BubbleAction::kConfirmed: - return "Confirm"; - case ShelfShutdownConfirmationBubble::BubbleAction::kDismissed: - return "Dismiss"; - case ShelfShutdownConfirmationBubble::BubbleAction::kOpened: - NOTREACHED(); - return ""; - } -} - } // namespace ShelfShutdownConfirmationBubble::ShelfShutdownConfirmationBubble( @@ -84,8 +58,7 @@ ShelfAlignment alignment, base::OnceClosure on_confirm_callback, base::OnceClosure on_cancel_callback) - : ShelfBubble(anchor, alignment), - bubble_opened_timestamp_(base::TimeTicks::Now()) { + : ShelfBubble(anchor, alignment) { DCHECK(on_confirm_callback); DCHECK(on_cancel_callback); confirm_callback_ = std::move(on_confirm_callback); @@ -258,12 +231,6 @@ void ShelfShutdownConfirmationBubble::ReportBubbleAction( ShelfShutdownConfirmationBubble::BubbleAction action) { base::UmaHistogramEnumeration(kActionHistogramName, action); - - const std::string action_suffix = BubbleActionSuffix(action); - auto elapsed_time = base::TimeTicks::Now() - bubble_opened_timestamp_; - base::UmaHistogramMediumTimes( - base::StrCat({kActionDurationHistogramPrefix, action_suffix}), - elapsed_time); } } // namespace ash
diff --git a/ash/shelf/shelf_shutdown_confirmation_bubble.h b/ash/shelf/shelf_shutdown_confirmation_bubble.h index 6387c297..9477e08e 100644 --- a/ash/shelf/shelf_shutdown_confirmation_bubble.h +++ b/ash/shelf/shelf_shutdown_confirmation_bubble.h
@@ -10,7 +10,6 @@ #include "ash/shelf/shelf_bubble.h" #include "base/functional/callback_forward.h" #include "base/memory/raw_ptr.h" -#include "base/time/time.h" #include "ui/gfx/geometry/size.h" #include "ui/views/controls/button/label_button.h" #include "ui/views/controls/image_view.h" @@ -84,9 +83,6 @@ // A simple state machine to keep track of the dialog result. DialogResult dialog_result_{DialogResult::kNone}; - - // Track time delta between bubble opened to an action taken - base::TimeTicks bubble_opened_timestamp_; }; } // namespace ash
diff --git a/ash/shell.cc b/ash/shell.cc index 3d130c6..6434cbdc 100644 --- a/ash/shell.cc +++ b/ash/shell.cc
@@ -860,7 +860,7 @@ // As clients of `capture_mode_controller_`, `projector_controller_` and // `game_dashboard_controller_` need to be destroyed before - // `capture_mode_controller_` + // `capture_mode_controller_`. projector_controller_.reset(); game_dashboard_controller_.reset(); @@ -1310,10 +1310,6 @@ env_filter_ = std::make_unique<::wm::CompoundEventFilter>(); AddPreTargetHandler(env_filter_.get()); - if (features::IsSnapGroupEnabled()) { - snap_group_controller_ = std::make_unique<SnapGroupController>(); - } - // FocusController takes ownership of AshFocusRules. focus_rules_ = new AshFocusRules(); focus_controller_ = std::make_unique<::wm::FocusController>(focus_rules_); @@ -1321,6 +1317,12 @@ overview_controller_ = std::make_unique<OverviewController>(); + // `SnapGroupController` has dependencies on `OverviweController` and + // `TabletModeController`. + if (features::IsSnapGroupEnabled()) { + snap_group_controller_ = std::make_unique<SnapGroupController>(); + } + screen_position_controller_ = std::make_unique<ScreenPositionController>(); frame_throttling_controller_ = std::make_unique<FrameThrottlingController>(
diff --git a/ash/system/power/battery_saver_controller.cc b/ash/system/power/battery_saver_controller.cc index 990e4bd..226436b 100644 --- a/ash/system/power/battery_saver_controller.cc +++ b/ash/system/power/battery_saver_controller.cc
@@ -4,6 +4,7 @@ #include "ash/system/power/battery_saver_controller.h" +#include "ash/constants/ash_features.h" #include "ash/constants/ash_pref_names.h" #include "base/logging.h" #include "chromeos/dbus/power/power_manager_client.h" @@ -15,7 +16,8 @@ const double BatterySaverController::kActivationChargePercent = 20.0; BatterySaverController::BatterySaverController(PrefService* local_state) - : local_state_(local_state) { + : local_state_(local_state), + always_on_(features::IsBatterySaverAlwaysOn()) { power_status_observation_.Observe(PowerStatus::Get()); pref_change_registrar_.Init(local_state); @@ -36,6 +38,11 @@ } void BatterySaverController::OnPowerStatusChanged() { + if (always_on_) { + SetBatterySaverState(true); + return; + } + auto* power_status = PowerStatus::Get(); double battery_percent = power_status->GetBatteryPercent(); bool active = power_status->IsBatterySaverActive(); @@ -52,6 +59,11 @@ } void BatterySaverController::OnSettingsPrefChanged() { + if (always_on_) { + SetBatterySaverState(true); + return; + } + // OS Settings has changed the pref, tell Power Manager. SetBatterySaverState(local_state_->GetBoolean(prefs::kPowerBatterySaver)); }
diff --git a/ash/system/power/battery_saver_controller.h b/ash/system/power/battery_saver_controller.h index 393fcbe3..a498c9fe 100644 --- a/ash/system/power/battery_saver_controller.h +++ b/ash/system/power/battery_saver_controller.h
@@ -52,6 +52,8 @@ PrefChangeRegistrar pref_change_registrar_; + bool always_on_; + base::WeakPtrFactory<BatterySaverController> weak_ptr_factory_{this}; };
diff --git a/ash/system/privacy_hub/geolocation_privacy_switch_controller.cc b/ash/system/privacy_hub/geolocation_privacy_switch_controller.cc index 99b3f51..9501adfc 100644 --- a/ash/system/privacy_hub/geolocation_privacy_switch_controller.cc +++ b/ash/system/privacy_hub/geolocation_privacy_switch_controller.cc
@@ -48,15 +48,15 @@ // TODO(zauri): Set 0-state } -void GeolocationPrivacySwitchController::OnAppStartsUsingGeolocation( - const std::u16string& app_name) { +void GeolocationPrivacySwitchController::TrackGeolocationAttempted( + const std::string& app_name) { ++usage_per_app_[app_name]; ++usage_cnt_; UpdateNotification(); } -void GeolocationPrivacySwitchController::OnAppStopsUsingGeolocation( - const std::u16string& app_name) { +void GeolocationPrivacySwitchController::TrackGeolocationRelinquished( + const std::string& app_name) { --usage_per_app_[app_name]; --usage_cnt_; if (usage_per_app_[app_name] < 0 || usage_cnt_ < 0) { @@ -74,13 +74,12 @@ std::vector<std::u16string> apps; for (const auto& [name, cnt] : usage_per_app_) { if (cnt > 0) { - apps.push_back(name); + apps.push_back(base::UTF8ToUTF16(name)); if (apps.size() == max_count) { break; } } } - return apps; }
diff --git a/ash/system/privacy_hub/geolocation_privacy_switch_controller.h b/ash/system/privacy_hub/geolocation_privacy_switch_controller.h index e5c3cf9..3cd3d740 100644 --- a/ash/system/privacy_hub/geolocation_privacy_switch_controller.h +++ b/ash/system/privacy_hub/geolocation_privacy_switch_controller.h
@@ -38,8 +38,8 @@ // using the following methods. They are used to decide whether a notification // that an app wants to use geolocation should be used. System usages like // time-zones should not use this mechanism as they are permanently active. - void OnAppStartsUsingGeolocation(const std::u16string& app_name); - void OnAppStopsUsingGeolocation(const std::u16string& app_name); + void TrackGeolocationAttempted(const std::string& app_name); + void TrackGeolocationRelinquished(const std::string& app_name); // Returns the names of the apps that want to actively use geolocation (if // there is more than `max_count` of such apps, first max_count names are @@ -55,7 +55,7 @@ std::unique_ptr<PrefChangeRegistrar> pref_change_registrar_; int usage_cnt_{}; - std::map<std::u16string, int> usage_per_app_; + std::map<std::string, int> usage_per_app_; }; } // namespace ash
diff --git a/ash/system/privacy_hub/geolocation_privacy_switch_controller_unittest.cc b/ash/system/privacy_hub/geolocation_privacy_switch_controller_unittest.cc index b150b14..f64a8657 100644 --- a/ash/system/privacy_hub/geolocation_privacy_switch_controller_unittest.cc +++ b/ash/system/privacy_hub/geolocation_privacy_switch_controller_unittest.cc
@@ -77,47 +77,48 @@ }; TEST_F(PrivacyHubGeolocationControllerTest, GetActiveAppsTest) { - const std::vector<std::u16string> app_names{u"App1", u"App2", u"App3"}; + const std::vector<std::string> app_names{"App1", "App2", "App3"}; + const std::vector<std::u16string> app_names_u16{u"App1", u"App2", u"App3"}; EXPECT_EQ(controller_->GetActiveApps(3), (std::vector<std::u16string>{})); - controller_->OnAppStartsUsingGeolocation(app_names[0]); + controller_->TrackGeolocationAttempted(app_names[0]); EXPECT_EQ(controller_->GetActiveApps(3), - (std::vector<std::u16string>{app_names[0]})); - controller_->OnAppStartsUsingGeolocation(app_names[1]); + (std::vector<std::u16string>{app_names_u16[0]})); + controller_->TrackGeolocationAttempted(app_names[1]); EXPECT_EQ(controller_->GetActiveApps(3), - (std::vector<std::u16string>{app_names[0], app_names[1]})); - controller_->OnAppStartsUsingGeolocation(app_names[1]); + (std::vector<std::u16string>{app_names_u16[0], app_names_u16[1]})); + controller_->TrackGeolocationAttempted(app_names[1]); EXPECT_EQ(controller_->GetActiveApps(3), - (std::vector<std::u16string>{app_names[0], app_names[1]})); - controller_->OnAppStartsUsingGeolocation(app_names[2]); - EXPECT_EQ(controller_->GetActiveApps(3), app_names); - controller_->OnAppStopsUsingGeolocation(app_names[2]); + (std::vector<std::u16string>{app_names_u16[0], app_names_u16[1]})); + controller_->TrackGeolocationAttempted(app_names[2]); + EXPECT_EQ(controller_->GetActiveApps(3), app_names_u16); + controller_->TrackGeolocationRelinquished(app_names[2]); EXPECT_EQ(controller_->GetActiveApps(3), - (std::vector<std::u16string>{app_names[0], app_names[1]})); - controller_->OnAppStopsUsingGeolocation(app_names[1]); + (std::vector<std::u16string>{app_names_u16[0], app_names_u16[1]})); + controller_->TrackGeolocationRelinquished(app_names[1]); EXPECT_EQ(controller_->GetActiveApps(3), - (std::vector<std::u16string>{app_names[0], app_names[1]})); - controller_->OnAppStopsUsingGeolocation(app_names[1]); + (std::vector<std::u16string>{app_names_u16[0], app_names_u16[1]})); + controller_->TrackGeolocationRelinquished(app_names[1]); EXPECT_EQ(controller_->GetActiveApps(3), - (std::vector<std::u16string>{app_names[0]})); - controller_->OnAppStopsUsingGeolocation(app_names[0]); + (std::vector<std::u16string>{app_names_u16[0]})); + controller_->TrackGeolocationRelinquished(app_names[0]); EXPECT_EQ(controller_->GetActiveApps(3), (std::vector<std::u16string>{})); } TEST_F(PrivacyHubGeolocationControllerTest, NotificationOnActivityChangeTest) { - const std::u16string app_name = u"app"; + const std::string app_name = "app"; SetUserPref(false); EXPECT_FALSE(FindNotification()); - controller_->OnAppStartsUsingGeolocation(app_name); + controller_->TrackGeolocationAttempted(app_name); EXPECT_TRUE(FindNotification()); - controller_->OnAppStopsUsingGeolocation(app_name); + controller_->TrackGeolocationRelinquished(app_name); EXPECT_FALSE(FindNotification()); } TEST_F(PrivacyHubGeolocationControllerTest, NotificationOnPreferenceChangeTest) { - const std::u16string app_name = u"app"; + const std::string app_name = "app"; SetUserPref(true); - controller_->OnAppStartsUsingGeolocation(app_name); + controller_->TrackGeolocationAttempted(app_name); EXPECT_FALSE(FindNotification()); SetUserPref(false); EXPECT_TRUE(FindNotification()); @@ -126,9 +127,9 @@ } TEST_F(PrivacyHubGeolocationControllerTest, ClickOnNotificationTest) { - const std::u16string app_name = u"app"; + const std::string app_name = "app"; SetUserPref(false); - controller_->OnAppStartsUsingGeolocation(app_name); + controller_->TrackGeolocationAttempted(app_name); // We didn't log any notification clicks so far. EXPECT_EQ(histogram_tester_.GetBucketCount( privacy_hub_metrics::
diff --git a/ash/webui/camera_app_ui/resources/js/models/barcode.ts b/ash/webui/camera_app_ui/resources/js/models/barcode.ts index 33dd3d10..2827519 100644 --- a/ash/webui/camera_app_ui/resources/js/models/barcode.ts +++ b/ash/webui/camera_app_ui/resources/js/models/barcode.ts
@@ -52,9 +52,6 @@ }, SCAN_INTERVAL); } - /** - * Stops scanning barcodes. - */ stop(): void { if (this.scanRunner === null) { return;
diff --git a/ash/webui/camera_app_ui/resources/js/models/file_namer.ts b/ash/webui/camera_app_ui/resources/js/models/file_namer.ts index c7815917..afae0cf 100644 --- a/ash/webui/camera_app_ui/resources/js/models/file_namer.ts +++ b/ash/webui/camera_app_ui/resources/js/models/file_namer.ts
@@ -8,14 +8,8 @@ VideoType, } from '../type.js'; -/** - * The prefix of image files. - */ export const IMAGE_PREFIX = 'IMG_'; -/** - * The prefix of video files. - */ export const VIDEO_PREFIX = 'VID_'; /** @@ -34,10 +28,7 @@ const BURST_COVER_SUFFIX = '_COVER'; /** - * Transforms from capture timestamp to datetime name. - * - * @param timestamp Timestamp to be transformed. - * @return Transformed datetime name. + * Transforms from capture timestamp to datetime name as YYYYMMDD_HHMMSS. */ function timestampToDatetimeName(timestamp: number): string { function pad(n: number) { @@ -85,7 +76,8 @@ private burstCount = 0; /** - * @param timestamp Timestamp of camera session. + * @param timestamp Optional timestamp of camera session. If |timestamp| is + * not given, it will use current time. */ constructor(timestamp?: number) { this.timestamp = timestamp ?? Date.now(); @@ -95,7 +87,6 @@ * Creates new filename for burst image. * * @param isCover If the image is set as cover of the burst. - * @return New filename. */ newBurstName(isCover: boolean): string { function prependZeros(n: number, width: number) { @@ -108,8 +99,6 @@ /** * Creates new filename for video. - * - * @return New filename. */ newVideoName(videoType: VideoType): string { return VIDEO_PREFIX + timestampToDatetimeName(this.timestamp) + '.' + @@ -118,17 +107,13 @@ /** * Creates new filename for image. - * - * @return New filename. */ newImageName(): string { return IMAGE_PREFIX + timestampToDatetimeName(this.timestamp) + '.jpg'; } /** - * Creates new filename for pdf. - * - * @return New filename. + * Creates new filename for document. */ newDocumentName(mimeType: MimeType): string { const ext = (() => { @@ -146,20 +131,14 @@ } /** - * Get the metadata name from image name. - * - * @param imageName Name of image to derive the metadata name. - * @return Metadata name of the image. + * Gets the metadata name from given |imageName|. */ static getMetadataName(imageName: string): string { return imageName.replace(/\.[^/.]+$/, '.json'); } /** - * Returns true if the file name matches the format that CCA generates. - * - * @param fileName Name of the file. - * @return True if it matches CCA file naming format. + * Returns true if given |fileName| matches the format that CCA generates. */ static isCCAFileFormat(fileName: string): boolean { return FILE_NAME_PATTERN.test(fileName);
diff --git a/ash/webui/camera_app_ui/resources/js/models/file_system.ts b/ash/webui/camera_app_ui/resources/js/models/file_system.ts index ec92870..e7e8224 100644 --- a/ash/webui/camera_app_ui/resources/js/models/file_system.ts +++ b/ash/webui/camera_app_ui/resources/js/models/file_system.ts
@@ -22,9 +22,6 @@ /** * Checks if the entry's name has the video prefix. - * - * @param entry File entry. - * @return Has the video prefix or not. */ export function hasVideoPrefix(entry: FileAccessEntry): boolean { return entry.name.startsWith(VIDEO_PREFIX); @@ -32,9 +29,6 @@ /** * Checks if the entry's name has the image prefix. - * - * @param entry File entry. - * @return Has the image prefix or not. */ function hasImagePrefix(entry: FileAccessEntry): boolean { return entry.name.startsWith(IMAGE_PREFIX); @@ -42,9 +36,6 @@ /** * Checks if the entry's name has the document prefix. - * - * @param entry File entry. - * @return Has the document prefix or not. */ function hasDocumentPrefix(entry: FileAccessEntry): boolean { return entry.name.startsWith(DOCUMENT_PREFIX); @@ -126,11 +117,11 @@ } /** - * Saves photo blob or metadata blob into predefined default location. + * Saves photo blob or metadata blob into predefined default location and + * returns the file. * * @param blob Data of the photo to be saved. * @param name Filename of the photo to be saved. - * @return Promise for the result. */ export async function saveBlob( blob: Blob, name: string): Promise<FileAccessEntry> { @@ -145,7 +136,6 @@ const PRIVATE_TEMPFILE_NAME = 'video-tmp.mp4'; /** - * @return Newly created temporary file. * @throws If failed to create video temp file. */ export async function createPrivateTempVideoFile(name = PRIVATE_TEMPFILE_NAME): @@ -165,8 +155,6 @@ /** * Gets the picture entries. - * - * @return Promise for the picture entries. */ export async function getEntries(): Promise<FileAccessEntry[]> { assert(cameraDir !== null); @@ -182,9 +170,6 @@ /** * Returns an URL for a picture given by the file |entry|. - * - * @param entry The file entry of the picture. - * @return Promise for the result. */ export async function pictureURL(entry: FileAccessEntry): Promise<string> { const file = await entry.file();
diff --git a/ash/webui/camera_app_ui/resources/js/models/file_system_access_entry.ts b/ash/webui/camera_app_ui/resources/js/models/file_system_access_entry.ts index d9c87c0..b623c29 100644 --- a/ash/webui/camera_app_ui/resources/js/models/file_system_access_entry.ts +++ b/ash/webui/camera_app_ui/resources/js/models/file_system_access_entry.ts
@@ -26,7 +26,7 @@ /** * Writes |blob| data into the file. * - * @return The returned promise is resolved once the write operation is + * @return The promise is resolved once the write operation is * completed. */ async write(blob: Blob): Promise<void> { @@ -35,9 +35,6 @@ await writer.close(); } - /** - * Gets a writer to write data into the file. - */ async getWriter(): Promise<AsyncWriter> { const writer = await this.handle.createWritable(); // TODO(crbug.com/980846): We should write files in-place so that even the @@ -61,8 +58,6 @@ } /** - * Deletes the file. - * * @throws Thrown when trying to delete file with no parent directory. */ async remove(): Promise<void> { @@ -94,32 +89,14 @@ * The abstract interface for the directory entry. */ export interface DirectoryAccessEntry { - /** - * Gets the name of the directory. - */ readonly name: string; - /** - * Gets the handle of the directory. - */ getHandle(): Promise<FileSystemDirectoryHandle>; - /** - * Gets files in this directory. - */ getFiles(): Promise<FileAccessEntry[]>; - /** - * Gets directories in this directory. - */ getDirectories(): Promise<DirectoryAccessEntry[]>; - /** - * Gets the file given by its |name|. - * - * @param name The name of the file. - * @return The entry of the found file. - */ getFile(name: string): Promise<FileAccessEntry|null>; /** @@ -131,9 +108,6 @@ * Create the file given by its |name|. If there is already a file with same * name, it will try to use a name with index as suffix. * (e.g. IMG.png => IMG (1).png). - * - * @param name The name of the file. - * @return The entry of the created file. */ createFile(name: string): Promise<FileAccessEntry>; @@ -142,8 +116,6 @@ * create one if |createIfNotExist| is true. * TODO(crbug.com/1127587): Split this method to getDirectory() and * createDirectory(). - * - * @return The entry of the found/created directory. */ getDirectory({name, createIfNotExist}: {name: string, createIfNotExist: boolean}): @@ -151,8 +123,6 @@ /** * Removes file by given |name| from the directory. - * - * @param name The name of the file. */ removeEntry(name: string): Promise<void>; }
diff --git a/ash/webui/camera_app_ui/resources/js/models/idb.ts b/ash/webui/camera_app_ui/resources/js/models/idb.ts index 4f4f88f..070bf858 100644 --- a/ash/webui/camera_app_ui/resources/js/models/idb.ts +++ b/ash/webui/camera_app_ui/resources/js/models/idb.ts
@@ -28,7 +28,6 @@ * Retrieves serializable object from idb. * * @param key The key of the object. - * @return The promise of the retrieved object. */ export async function get<T>(key: string): Promise<T|null> { const transaction = (await idb).transaction(DB_STORE, 'readonly');
diff --git a/ash/webui/camera_app_ui/resources/js/models/lazy_directory_entry.ts b/ash/webui/camera_app_ui/resources/js/models/lazy_directory_entry.ts index 036c084..bcba50fc 100644 --- a/ash/webui/camera_app_ui/resources/js/models/lazy_directory_entry.ts +++ b/ash/webui/camera_app_ui/resources/js/models/lazy_directory_entry.ts
@@ -13,9 +13,6 @@ * Gets directory entry by given |name| under |parentDir| directory. If the * directory does not exist, returns a lazy directory which will only be created * once there is any file written in it. - * - * @param parentDir Parent directory. - * @param name Name of the target directory. */ export async function getMaybeLazyDirectory( parentDir: DirectoryAccessEntry, @@ -33,10 +30,6 @@ class LazyDirectoryEntry implements DirectoryAccessEntry { private directory: DirectoryAccessEntry|null = null; - /** - * @param parent The parent of the directory that will be lazily created. - * @param name The name of the directory that will be lazily created. - */ constructor( private readonly parent: DirectoryAccessEntry, readonly name: string) {}
diff --git a/ash/webui/camera_app_ui/resources/js/models/video_saver.ts b/ash/webui/camera_app_ui/resources/js/models/video_saver.ts index 3dd4f6e..a52cd7b3 100644 --- a/ash/webui/camera_app_ui/resources/js/models/video_saver.ts +++ b/ash/webui/camera_app_ui/resources/js/models/video_saver.ts
@@ -101,8 +101,6 @@ /** * Finishes the write of video data parts and returns result video file. - * - * @return Result video file. */ async endWrite(): Promise<FileAccessEntry> { await this.processor.close();
diff --git a/ash/wm/overview/overview_constants.h b/ash/wm/overview/overview_constants.h index 9a60d929..600ff51 100644 --- a/ash/wm/overview/overview_constants.h +++ b/ash/wm/overview/overview_constants.h
@@ -19,9 +19,12 @@ constexpr base::TimeDelta kWindowRestoreDurationCrOSNext = base::Milliseconds(350); -// In the conceptual overview table, the space between two adjacent items -// horizontally and vertically. -constexpr int kSpaceBetweenItemsDp = 10; +// In the conceptual overview table, the horizontal space between two adjacent +// items. +constexpr int kHorizontalSpaceBetweenItemsDp = 10; + +// The vertical space between two adjacent items. +constexpr int kVerticalSpaceBetweenItemsDp = 15; // The amount we want to enlarge the dragged overview window. constexpr int kDraggingEnlargeDp = 10;
diff --git a/ash/wm/overview/overview_grid.cc b/ash/wm/overview/overview_grid.cc index f6259796..dae5b3a 100644 --- a/ash/wm/overview/overview_grid.cc +++ b/ash/wm/overview/overview_grid.cc
@@ -2276,7 +2276,7 @@ // |high_height|. Once this optimal height is known, |height_fixed| is set to // true and the rows are balanced by repeatedly squeezing the widest row to // cause windows to overflow to the subsequent rows. - int low_height = kSpaceBetweenItemsDp; + int low_height = kVerticalSpaceBetweenItemsDp; int high_height = std::max(low_height, total_bounds.height() + 1); int height = 0.5 * (low_height + high_height); bool height_fixed = false; @@ -2396,7 +2396,7 @@ // |window_position| remains where the item was as to then reposition the // other window's bounds in place of that item. const int height = (total_bounds.height() - - ((kTabletLayoutRow - 1) * kSpaceBetweenItemsDp)) / + ((kTabletLayoutRow - 1) * kVerticalSpaceBetweenItemsDp)) / kTabletLayoutRow; int window_position = 0; std::vector<gfx::RectF> rects; @@ -2409,16 +2409,16 @@ // Calculate the width and y position of the item. const int width = CalculateWidthAndMaybeSetUnclippedBounds(item, height); - const int y = - (height + kSpaceBetweenItemsDp) * (window_position % kTabletLayoutRow) + - total_bounds.y(); + const int y = (height + kVerticalSpaceBetweenItemsDp) * + (window_position % kTabletLayoutRow) + + total_bounds.y(); // Use the right bounds of the item next to in the row as the x position, if // that item exists. const int x = right_edge_map.contains(y) ? right_edge_map[y] : total_bounds.x() + scroll_offset_; - right_edge_map[y] = x + width + kSpaceBetweenItemsDp; + right_edge_map[y] = x + width + kHorizontalSpaceBetweenItemsDp; DCHECK_LE(static_cast<int>(right_edge_map.size()), kTabletLayoutRow); const gfx::RectF bounds(x, y, width, height); @@ -2461,18 +2461,19 @@ int width = CalculateWidthAndMaybeSetUnclippedBounds(window_list_[i].get(), height); - if ((left + width + kSpaceBetweenItemsDp) > bounds.right()) { + if ((left + width + kHorizontalSpaceBetweenItemsDp) > bounds.right()) { // Move to the next row if possible. if (*out_min_right > left) *out_min_right = left; if (*out_max_right < left) *out_max_right = left; - top += (height + kSpaceBetweenItemsDp); + top += (height + kVerticalSpaceBetweenItemsDp); // Check if the new row reaches the bottom or if the first item in the new // row does not fit within the available width. - if ((top + height + kSpaceBetweenItemsDp) > bounds.bottom() || - bounds.x() + width + kSpaceBetweenItemsDp > bounds.right()) { + if ((top + height + kVerticalSpaceBetweenItemsDp) > bounds.bottom() || + bounds.x() + width + kHorizontalSpaceBetweenItemsDp > + bounds.right()) { return false; } left = bounds.x(); @@ -2482,7 +2483,7 @@ (*out_rects)[i] = gfx::RectF(left, top, width, height); // Increment horizontal position using sanitized positive `width`. - left += (width + kSpaceBetweenItemsDp); + left += (width + kHorizontalSpaceBetweenItemsDp); *out_max_bottom = top + height; }
diff --git a/base/allocator/partition_allocator/partition_alloc.gni b/base/allocator/partition_allocator/partition_alloc.gni index a344a4fa..e0c141b 100644 --- a/base/allocator/partition_allocator/partition_alloc.gni +++ b/base/allocator/partition_allocator/partition_alloc.gni
@@ -213,15 +213,16 @@ # enable_backup_ref_ptr_support is true. assert( enable_backup_ref_ptr_support || !put_ref_count_in_previous_slot, - "Can't put ref count in the previous slot if BackupRefPtr isn't enabled at all") + "Can't put ref count in the previous slot if BackupRefPtr isn't enabled " + + "at all") -# enable_backup_ref_ptr_slow_checks can only be used if enable_backup_ref_ptr_support -# is true. +# enable_backup_ref_ptr_slow_checks can only be used if +# enable_backup_ref_ptr_support is true. assert(enable_backup_ref_ptr_support || !enable_backup_ref_ptr_slow_checks, "Can't enable additional BackupRefPtr checks if it isn't enabled at all") -# enable_dangling_raw_ptr_checks can only be used if enable_backup_ref_ptr_support -# is true. +# enable_dangling_raw_ptr_checks can only be used if +# enable_backup_ref_ptr_support is true. assert( enable_backup_ref_ptr_support || !enable_dangling_raw_ptr_checks, "Can't enable dangling raw_ptr checks if BackupRefPtr isn't enabled at all") @@ -232,18 +233,21 @@ enable_dangling_raw_ptr_checks || !enable_dangling_raw_ptr_perf_experiment, "Missing dangling pointer checks feature for its performance experiment") -# To poison OOB pointers for BackupRefPtr, the underlying feature must -# be enabled, too. +# To poison OOB pointers for BackupRefPtr, the underlying feature must be +# enabled, too. assert( enable_backup_ref_ptr_support || !backup_ref_ptr_poison_oob_ptr, - "Can't enable poisoning for OOB pointers if BackupRefPtr isn't enabled at all") + "Can't enable poisoning for OOB pointers if BackupRefPtr isn't enabled " + + "at all") assert(has_64_bit_pointers || !backup_ref_ptr_poison_oob_ptr, "Can't enable poisoning for OOB pointers if pointers are only 32-bit") -# AsanBackupRefPtr and AsanUnownedPtr are mutually exclusive variants of raw_ptr. +# AsanBackupRefPtr and AsanUnownedPtr are mutually exclusive variants of +# raw_ptr. assert( !use_asan_unowned_ptr || !use_asan_backup_ref_ptr, - "Both AsanUnownedPtr and AsanBackupRefPtr can't be enabled at the same time") + "Both AsanUnownedPtr and AsanBackupRefPtr can't be enabled at the same " + + "time") # BackupRefPtr and AsanBackupRefPtr are mutually exclusive variants of raw_ptr. assert( @@ -254,15 +258,19 @@ assert(!enable_backup_ref_ptr_support || !use_asan_unowned_ptr, "Both BackupRefPtr and AsanUnownedPtr can't be enabled at the same time") -# RawPtrHookableImpl and BackupRefPtr are mutually exclusive variants of raw_ptr. +# RawPtrHookableImpl and BackupRefPtr are mutually exclusive variants of +# raw_ptr. assert( !use_hookable_raw_ptr || !enable_backup_ref_ptr_support, - "Both RawPtrHookableImpl and BackupRefPtr can't be enabled at the same time") + "Both RawPtrHookableImpl and BackupRefPtr can't be enabled at the same " + + "time") -# RawPtrHookableImpl and AsanUnownedPtr are mutually exclusive variants of raw_ptr. +# RawPtrHookableImpl and AsanUnownedPtr are mutually exclusive variants of +# raw_ptr. assert( !use_hookable_raw_ptr || !use_asan_unowned_ptr, - "Both RawPtrHookableImpl and AsanUnownedPtr can't be enabled at the same time") + "Both RawPtrHookableImpl and AsanUnownedPtr can't be enabled at the same " + + "time") assert(!use_asan_backup_ref_ptr || is_asan, "AsanBackupRefPtr requires AddressSanitizer") @@ -279,8 +287,8 @@ } # AsanBackupRefPtr is not supported outside Chromium. The implementation is -# entangled with `//base`. The code is only physically located with the -# rest of `raw_ptr` to keep it together. +# entangled with `//base`. The code is only physically located with the rest of +# `raw_ptr` to keep it together. assert(build_with_chromium || !use_asan_backup_ref_ptr, "AsanBackupRefPtr is not supported outside Chromium") @@ -288,9 +296,9 @@ "AsanBackupRefPtr requires RawPtrHookableImpl") declare_args() { - # pkeys support is explicitly disabled in all Cronet builds, as some test dependencies that - # use partition_allocator are compiled in AOSP against a version of glibc that does not - # include pkeys syscall numbers. + # pkeys support is explicitly disabled in all Cronet builds, as some test + # dependencies that use partition_allocator are compiled in AOSP against a + # version of glibc that does not include pkeys syscall numbers. enable_pkeys = is_linux && target_cpu == "x64" && !is_cronet_build } assert(!enable_pkeys || (is_linux && target_cpu == "x64"),
diff --git a/build/config/clang/BUILD.gn b/build/config/clang/BUILD.gn index 6a69428..bdf4303 100644 --- a/build/config/clang/BUILD.gn +++ b/build/config/clang/BUILD.gn
@@ -83,6 +83,12 @@ "-plugin-arg-find-bad-constructs", "-Xclang", "raw-ptr-exclude-path=ui/views/controls/native/native_view_host_mac_unittest.mm", + + # TODO(mikt): Remove this once crbug.com/1449812 is resolved. + "-Xclang", + "-plugin-arg-find-bad-constructs", + "-Xclang", + "raw-ptr-exclude-path=um/winnt.h", ] } }
diff --git a/build/config/clang/clang.gni b/build/config/clang/clang.gni index 474fde4..727a2ec 100644 --- a/build/config/clang/clang.gni +++ b/build/config/clang/clang.gni
@@ -16,7 +16,8 @@ enable_check_raw_ptr_fields = build_with_chromium && !is_official_build && - ((is_linux && !is_castos) || (is_android && !is_cast_android) || is_mac) + ((is_linux && !is_castos) || (is_android && !is_cast_android) || is_mac || + is_win) clang_base_path = default_clang_base_path
diff --git a/build/config/siso/configure_siso.py b/build/config/siso/configure_siso.py index 2770f6e7..bcf79ca 100755 --- a/build/config/siso/configure_siso.py +++ b/build/config/siso/configure_siso.py
@@ -12,25 +12,26 @@ def main(): - parser = argparse.ArgumentParser(description='configure siso') - parser.add_argument('--rbe_instance', help='RBE instance to use for Siso') + parser = argparse.ArgumentParser(description="configure siso") + parser.add_argument("--rbe_instance", help="RBE instance to use for Siso") args = parser.parse_args() project = None - if not args.rbe_instance: - return 0 rbe_instance = args.rbe_instance - elems = rbe_instance.split('/') - if len(elems) == 4 and elems[0] == 'projects': - project = elems[1] - rbe_instance = elems[-1] - siso_env_path = os.path.join(THIS_DIR, '.sisoenv') - with open(siso_env_path, 'w') as f: + if rbe_instance: + elems = rbe_instance.split("/") + if len(elems) == 4 and elems[0] == "projects": + project = elems[1] + rbe_instance = elems[-1] + + siso_env_path = os.path.join(THIS_DIR, ".sisoenv") + with open(siso_env_path, "w") as f: if project: - f.write('SISO_PROJECT=%s\n' % project) - f.write('SISO_REAPI_INSTANCE=%s\n' % rbe_instance) + f.write("SISO_PROJECT=%s\n" % project) + if rbe_instance: + f.write("SISO_REAPI_INSTANCE=%s\n" % rbe_instance) return 0 -if __name__ == '__main__': +if __name__ == "__main__": sys.exit(main())
diff --git a/build/config/siso/rewrapper_to_reproxy.star b/build/config/siso/rewrapper_to_reproxy.star index aec12d1..020ac73 100644 --- a/build/config/siso/rewrapper_to_reproxy.star +++ b/build/config/siso/rewrapper_to_reproxy.star
@@ -52,7 +52,7 @@ reproxy_config["exec_timeout"] = line.removeprefix("exec_timeout=") if line.startswith("inputs="): - reproxy_config["inputs"] = line.removeprefix("inputs").split(",") + reproxy_config["inputs"] = line.removeprefix("inputs=").split(",") if line.startswith("labels="): if "labels" not in reproxy_config:
diff --git a/build/fuchsia/linux_internal.sdk.sha1 b/build/fuchsia/linux_internal.sdk.sha1 index a532479..a81c0a90 100644 --- a/build/fuchsia/linux_internal.sdk.sha1 +++ b/build/fuchsia/linux_internal.sdk.sha1
@@ -1 +1 @@ -12.20230612.2.1 +13.20230613.0.1
diff --git a/cc/layers/video_layer_impl.cc b/cc/layers/video_layer_impl.cc index 9fabe7c..2ef7a02 100644 --- a/cc/layers/video_layer_impl.cc +++ b/cc/layers/video_layer_impl.cc
@@ -110,8 +110,7 @@ if (!updater_) { const LayerTreeSettings& settings = layer_tree_impl()->settings(); updater_ = std::make_unique<media::VideoResourceUpdater>( - /*context_provider=*/nullptr, - /*raster_context_provider=*/layer_tree_impl()->context_provider(), + layer_tree_impl()->context_provider(), layer_tree_impl()->layer_tree_frame_sink(), layer_tree_impl()->resource_provider(), settings.use_stream_video_draw_quad,
diff --git a/chrome/VERSION b/chrome/VERSION index 8b7371f..8d7641a 100644 --- a/chrome/VERSION +++ b/chrome/VERSION
@@ -1,4 +1,4 @@ MAJOR=116 MINOR=0 -BUILD=5829 +BUILD=5830 PATCH=0
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 880f45e..59fc9b5 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -10063,6 +10063,11 @@ kServiceWorkerBypassFetchHandlerForMainResourceDescription, kOsAll, FEATURE_VALUE_TYPE(features::kServiceWorkerBypassFetchHandler)}, + {"service-worker-static-router", + flag_descriptions::kServiceWorkerStaticRouterName, + flag_descriptions::kServiceWorkerStaticRouterDescription, kOsAll, + FEATURE_VALUE_TYPE(features::kServiceWorkerStaticRouter)}, + {"autofill-remove-card-expiration-and-type-titles", flag_descriptions::kAutofillRemoveCardExpirationAndTypeTitlesName, flag_descriptions::kAutofillRemoveCardExpirationAndTypeTitlesDescription, @@ -10425,6 +10430,13 @@ kOsDesktop | kOsAndroid, FEATURE_VALUE_TYPE(features::kProcessPerSiteUpToMainFrameThreshold)}, +#if BUILDFLAG(IS_CHROMEOS_ASH) + {"cros-battery-saver-always-on", + flag_descriptions::kCrosBatterySaverAlwaysOnName, + flag_descriptions::kCrosBatterySaverAlwaysOnDescription, kOsCrOS, + FEATURE_VALUE_TYPE(ash::features::kBatterySaverAlwaysOn)}, +#endif // BUILDFLAG(IS_CHROMEOS_ASH) + // NOTE: Adding a new flag requires adding a corresponding entry to enum // "LoginCustomFlags" in tools/metrics/histograms/enums.xml. See "Flag // Histograms" in tools/metrics/histograms/README.md (run the
diff --git a/chrome/browser/accessibility/accessibility_extension_api_chromeos.cc b/chrome/browser/accessibility/accessibility_extension_api_chromeos.cc index 3ff7c70..492c24e6 100644 --- a/chrome/browser/accessibility/accessibility_extension_api_chromeos.cc +++ b/chrome/browser/accessibility/accessibility_extension_api_chromeos.cc
@@ -46,7 +46,6 @@ #include "extensions/common/error_utils.h" #include "extensions/common/manifest_handlers/background_info.h" #include "ui/accessibility/accessibility_features.h" -#include "ui/accessibility/accessibility_switches.h" #include "ui/aura/client/cursor_client.h" #include "ui/aura/window_tree_host.h" #include "ui/base/ui_base_features.h"
diff --git a/chrome/browser/ash/BUILD.gn b/chrome/browser/ash/BUILD.gn index 896e541..6c84862aa 100644 --- a/chrome/browser/ash/BUILD.gn +++ b/chrome/browser/ash/BUILD.gn
@@ -4795,6 +4795,7 @@ "app_list/app_list_test_util.cc", "app_list/app_list_test_util.h", "app_list/app_service/app_service_app_model_builder_unittest.cc", + "app_list/app_service/app_service_promise_app_model_builder_unittest.cc", "app_list/arc/arc_app_metrics_data_unittest.cc", "app_list/arc/arc_app_metrics_util_unittest.cc", "app_list/arc/arc_app_sync_metrics_helper_unittest.cc", @@ -4965,6 +4966,7 @@ "arc/input_overlay/touch_injector_unittest.cc", "arc/input_overlay/ui/action_view_unittest.cc", "arc/input_overlay/ui/edit_label_unittest.cc", + "arc/input_overlay/ui/editing_list_unittest.cc", "arc/input_overlay/ui/menu_entry_view_unittest.cc", "arc/instance_throttle/arc_active_window_throttle_observer_unittest.cc", "arc/instance_throttle/arc_app_launch_throttle_observer_unittest.cc",
diff --git a/chrome/browser/ash/accessibility/select_to_speak_browsertest.cc b/chrome/browser/ash/accessibility/select_to_speak_browsertest.cc index 98dfc48b..7bc54a4 100644 --- a/chrome/browser/ash/accessibility/select_to_speak_browsertest.cc +++ b/chrome/browser/ash/accessibility/select_to_speak_browsertest.cc
@@ -47,7 +47,6 @@ #include "mojo/public/cpp/bindings/remote.h" #include "third_party/skia/include/core/SkColor.h" #include "ui/accessibility/accessibility_features.h" -#include "ui/accessibility/accessibility_switches.h" #include "ui/compositor/layer.h" #include "ui/display/manager/display_manager.h" #include "ui/display/screen.h"
diff --git a/chrome/browser/ash/android_sms/android_sms_app_setup_controller_impl.cc b/chrome/browser/ash/android_sms/android_sms_app_setup_controller_impl.cc index acacbc1..f7bafea 100644 --- a/chrome/browser/ash/android_sms/android_sms_app_setup_controller_impl.cc +++ b/chrome/browser/ash/android_sms/android_sms_app_setup_controller_impl.cc
@@ -83,8 +83,7 @@ webapps::WebappUninstallSource::kInternalPreinstalled, base::BindOnce( [](SuccessCallback callback, webapps::UninstallResultCode code) { - std::move(callback).Run(code == - webapps::UninstallResultCode::kSuccess); + std::move(callback).Run(UninstallSucceeded(code)); }, std::move(callback))); }
diff --git a/chrome/browser/ash/app_list/app_list_syncable_service.cc b/chrome/browser/ash/app_list/app_list_syncable_service.cc index a0b2e3d0..d0ccbad 100644 --- a/chrome/browser/ash/app_list/app_list_syncable_service.cc +++ b/chrome/browser/ash/app_list/app_list_syncable_service.cc
@@ -28,6 +28,7 @@ #include "chrome/browser/ash/app_list/app_list_model_updater.h" #include "chrome/browser/ash/app_list/app_list_sync_model_sanitizer.h" #include "chrome/browser/ash/app_list/app_service/app_service_app_model_builder.h" +#include "chrome/browser/ash/app_list/app_service/app_service_promise_app_model_builder.h" #include "chrome/browser/ash/app_list/arc/arc_app_list_prefs.h" #include "chrome/browser/ash/app_list/arc/arc_app_utils.h" #include "chrome/browser/ash/app_list/chrome_app_list_item.h" @@ -503,11 +504,19 @@ app_service_apps_builder_ = std::make_unique<AppServiceAppModelBuilder>(controller); + if (ash::features::ArePromiseIconsEnabled()) { + app_service_promise_apps_builder_ = + std::make_unique<AppServicePromiseAppModelBuilder>(controller); + } DCHECK(profile_); SyncStarted(); app_service_apps_builder_->Initialize(this, profile_, model_updater_.get()); + if (ash::features::ArePromiseIconsEnabled()) { + app_service_promise_apps_builder_->Initialize(this, profile_, + model_updater_.get()); + } HandleUpdateFinished(false /* clean_up_after_init_sync */); @@ -1182,6 +1191,9 @@ void AppListSyncableService::Shutdown() { app_service_apps_builder_.reset(); + if (ash::features::ArePromiseIconsEnabled()) { + app_service_promise_apps_builder_.reset(); + } } void AppListSyncableService::SetAppListPreferredOrder(
diff --git a/chrome/browser/ash/app_list/app_list_syncable_service.h b/chrome/browser/ash/app_list/app_list_syncable_service.h index 171e7fc..6c4d4a91 100644 --- a/chrome/browser/ash/app_list/app_list_syncable_service.h +++ b/chrome/browser/ash/app_list/app_list_syncable_service.h
@@ -32,6 +32,7 @@ class AppListModelUpdater; class AppServiceAppModelBuilder; +class AppServicePromiseAppModelBuilder; class ChromeAppListItem; class Profile; @@ -407,6 +408,8 @@ std::unique_ptr<AppListSyncModelSanitizer> sync_model_sanitizer_; std::unique_ptr<AppServiceAppModelBuilder> app_service_apps_builder_; + std::unique_ptr<AppServicePromiseAppModelBuilder> + app_service_promise_apps_builder_; std::unique_ptr<syncer::SyncChangeProcessor> sync_processor_; SyncItemMap sync_items_; // Map that keeps pending request to transfer attributes from one app to
diff --git a/chrome/browser/ash/app_list/app_service/app_service_promise_app_item.cc b/chrome/browser/ash/app_list/app_service/app_service_promise_app_item.cc new file mode 100644 index 0000000..3e784e3 --- /dev/null +++ b/chrome/browser/ash/app_list/app_service/app_service_promise_app_item.cc
@@ -0,0 +1,77 @@ +// 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/ash/app_list/app_service/app_service_promise_app_item.h" + +#include "base/check.h" +#include "chrome/browser/apps/app_service/promise_apps/promise_app_update.h" +#include "chrome/browser/ash/app_list/app_list_model_updater.h" +#include "chrome/browser/ash/app_list/chrome_app_list_item.h" + +// static +const char AppServicePromiseAppItem::kItemType[] = "AppServicePromiseAppItem"; + +AppServicePromiseAppItem::AppServicePromiseAppItem( + Profile* profile, + AppListModelUpdater* model_updater, + const apps::PromiseAppUpdate& update) + : ChromeAppListItem(profile, update.PackageId().ToString()) { + InitializeItem(update); + + // Promise icons should not be synced as they are transient and only present + // during app installations. + SetIsEphemeral(true); + + SetPosition(CalculateDefaultPositionIfApplicable()); + + // Set model updater last to avoid being called during construction. + set_model_updater(model_updater); +} + +void AppServicePromiseAppItem::Activate(int event_flags) { + base::DoNothing(); +} + +const char* AppServicePromiseAppItem::GetItemType() const { + return AppServicePromiseAppItem::kItemType; +} + +AppServicePromiseAppItem::~AppServicePromiseAppItem() = default; + +void AppServicePromiseAppItem::OnPromiseAppUpdate( + const apps::PromiseAppUpdate& update) { + if (update.NameChanged() && update.Name().has_value()) { + SetName(update.Name().value()); + } + if (update.ProgressChanged() && update.Progress().has_value()) { + progress_ = update.Progress(); + } +} + +void AppServicePromiseAppItem::LoadIcon() { + // TODO(b/261907495): Retrieve icon from Promise App Icon Cache. +} + +void AppServicePromiseAppItem::InitializeItem( + const apps::PromiseAppUpdate& update) { + CHECK(update.Name().has_value()); + CHECK(update.ShouldShow()); + SetName(update.Name().value()); + if (update.Progress().has_value()) { + progress_ = update.Progress(); + } + // TODO(b/261907495): Consider adding new AppStatus values specific to promise + // apps and update them in OnPromiseAppUpdate. + SetAppStatus(ash::AppStatus::kReady); +} + +void AppServicePromiseAppItem::GetContextMenuModel( + ash::AppListItemContext item_context, + GetMenuModelCallback callback) { + // TODO(b/261907495): Create Promise App Context Menu. +} + +app_list::AppContextMenu* AppServicePromiseAppItem::GetAppContextMenu() { + return nullptr; +}
diff --git a/chrome/browser/ash/app_list/app_service/app_service_promise_app_item.h b/chrome/browser/ash/app_list/app_service/app_service_promise_app_item.h new file mode 100644 index 0000000..348d9f6 --- /dev/null +++ b/chrome/browser/ash/app_list/app_service/app_service_promise_app_item.h
@@ -0,0 +1,48 @@ +// 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_ASH_APP_LIST_APP_SERVICE_APP_SERVICE_PROMISE_APP_ITEM_H_ +#define CHROME_BROWSER_ASH_APP_LIST_APP_SERVICE_APP_SERVICE_PROMISE_APP_ITEM_H_ + +#include "chrome/browser/apps/app_service/promise_apps/promise_app_update.h" +#include "chrome/browser/ash/app_list/app_context_menu_delegate.h" +#include "chrome/browser/ash/app_list/chrome_app_list_item.h" +#include "components/services/app_service/public/cpp/app_launch_util.h" +#include "components/services/app_service/public/cpp/app_types.h" +#include "components/services/app_service/public/cpp/app_update.h" +#include "components/services/app_service/public/cpp/icon_types.h" + +// A promise app list item provided by the App Service. +class AppServicePromiseAppItem : public ChromeAppListItem { + public: + static const char kItemType[]; + + AppServicePromiseAppItem(Profile* profile, + AppListModelUpdater* model_updater, + const apps::PromiseAppUpdate& app_update); + AppServicePromiseAppItem(const AppServicePromiseAppItem&) = delete; + AppServicePromiseAppItem& operator=(const AppServicePromiseAppItem&) = delete; + ~AppServicePromiseAppItem() override; + + // Update the promise app item with the new promise app info from the Promise + // App Registry Cache. + void OnPromiseAppUpdate(const apps::PromiseAppUpdate& update); + + private: + void InitializeItem(const apps::PromiseAppUpdate& update); + + // ChromeAppListItem overrides: + void LoadIcon() override; + void Activate(int event_flags) override; + const char* GetItemType() const override; + void GetContextMenuModel(ash::AppListItemContext item_context, + GetMenuModelCallback callback) override; + app_list::AppContextMenu* GetAppContextMenu() override; + + // Used to indicate the installation progress in the promise icon progress + // bar. + absl::optional<float> progress_; +}; + +#endif // CHROME_BROWSER_ASH_APP_LIST_APP_SERVICE_APP_SERVICE_PROMISE_APP_ITEM_H_
diff --git a/chrome/browser/ash/app_list/app_service/app_service_promise_app_item_browsertest.cc b/chrome/browser/ash/app_list/app_service/app_service_promise_app_item_browsertest.cc new file mode 100644 index 0000000..e935611 --- /dev/null +++ b/chrome/browser/ash/app_list/app_service/app_service_promise_app_item_browsertest.cc
@@ -0,0 +1,112 @@ +// 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/ash/app_list/app_service/app_service_promise_app_item.h" + +#include "ash/app_list/app_list_model_provider.h" +#include "ash/app_list/model/app_list_item.h" +#include "ash/constants/ash_features.h" +#include "chrome/browser/apps/app_service/app_service_proxy.h" +#include "chrome/browser/apps/app_service/app_service_proxy_ash.h" +#include "chrome/browser/apps/app_service/app_service_proxy_factory.h" +#include "chrome/browser/apps/app_service/package_id.h" +#include "chrome/browser/apps/app_service/promise_apps/promise_app.h" +#include "chrome/browser/apps/app_service/promise_apps/promise_app_registry_cache.h" +#include "chrome/browser/apps/platform_apps/app_browsertest_util.h" +#include "chrome/browser/ash/app_list/app_list_client_impl.h" +#include "chrome/browser/ash/app_list/app_list_syncable_service.h" +#include "chrome/browser/ash/app_list/app_list_syncable_service_factory.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/common/pref_names.h" +#include "components/services/app_service/public/cpp/app_types.h" +#include "components/sync/protocol/entity_specifics.pb.h" +#include "components/sync/test/fake_sync_change_processor.h" +#include "components/sync/test/sync_change_processor_wrapper_for_test.h" +#include "content/public/test/browser_test.h" + +namespace apps { + +const apps::PackageId kTestPackageId = + apps::PackageId(apps::AppType::kArc, "com.test.package"); + +ash::AppListItem* GetAppListItem(const std::string& id) { + return ash::AppListModelProvider::Get()->model()->FindItem(id); +} + +class AppServicePromiseAppItemBrowserTest + : public extensions::PlatformAppBrowserTest { + public: + AppServicePromiseAppItemBrowserTest() { + scoped_feature_list_.InitAndEnableFeature(ash::features::kPromiseIcons); + } + ~AppServicePromiseAppItemBrowserTest() override = default; + + // extensions::PlatformAppBrowserTest: + void SetUpOnMainThread() override { + extensions::PlatformAppBrowserTest::SetUpOnMainThread(); + AppListClientImpl* client = AppListClientImpl::GetInstance(); + ASSERT_TRUE(client); + client->UpdateProfile(); + cache_ = apps::AppServiceProxyFactory::GetForProfile(profile()) + ->PromiseAppRegistryCache(); + } + + apps::PromiseAppRegistryCache* cache() { return cache_; } + + private: + apps::PromiseAppRegistryCache* cache_; + base::test::ScopedFeatureList scoped_feature_list_; +}; + +IN_PROC_BROWSER_TEST_F(AppServicePromiseAppItemBrowserTest, + ShouldShowUpdateCreatesItem) { + // Sync setup. + std::unique_ptr<syncer::FakeSyncChangeProcessor> sync_processor = + std::make_unique<syncer::FakeSyncChangeProcessor>(); + app_list::AppListSyncableService* app_list_syncable_service_ = + app_list::AppListSyncableServiceFactory::GetForProfile(profile()); + app_list_syncable_service_->MergeDataAndStartSyncing( + syncer::APP_LIST, {}, + std::make_unique<syncer::SyncChangeProcessorWrapperForTest>( + sync_processor.get())); + content::RunAllTasksUntilIdle(); + + // Register a promise app in the promise app registry cache. + apps::PromiseAppPtr promise_app = + std::make_unique<PromiseApp>(kTestPackageId); + cache()->OnPromiseApp(std::move(promise_app)); + + // Promise app registration in the cache should not result in a promise app + // launcher item if should_show is false (which it is by default). + ash::AppListItem* item = GetAppListItem(kTestPackageId.ToString()); + ASSERT_FALSE(item); + + // Update the promise app to allow showing in the Launcher. + apps::PromiseAppPtr promise_app_update = + std::make_unique<PromiseApp>(kTestPackageId); + promise_app_update->name = "Test"; + promise_app_update->should_show = true; + cache()->OnPromiseApp(std::move(promise_app_update)); + + // Promise app item should now exist in the model. + item = GetAppListItem(kTestPackageId.ToString()); + ASSERT_TRUE(item); + ASSERT_EQ(item->name(), "Test"); + + // Verify that the promise app item is not added to local storage. + const base::Value::Dict& local_items = + profile()->GetPrefs()->GetDict(prefs::kAppListLocalState); + const base::Value::Dict* dict_item = + local_items.FindDict(kTestPackageId.ToString()); + EXPECT_FALSE(dict_item); + + // Verify that promise app item is not uploaded to sync data. + for (auto sync_change : sync_processor->changes()) { + const std::string item_id = + sync_change.sync_data().GetSpecifics().app_list().item_id(); + EXPECT_NE(item_id, kTestPackageId.ToString()); + } +} + +} // namespace apps
diff --git a/chrome/browser/ash/app_list/app_service/app_service_promise_app_model_builder.cc b/chrome/browser/ash/app_list/app_service/app_service_promise_app_model_builder.cc new file mode 100644 index 0000000..0570a43 --- /dev/null +++ b/chrome/browser/ash/app_list/app_service/app_service_promise_app_model_builder.cc
@@ -0,0 +1,60 @@ +// 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/ash/app_list/app_service/app_service_promise_app_model_builder.h" +#include <ostream> + +#include "chrome/browser/apps/app_service/app_service_proxy.h" +#include "chrome/browser/apps/app_service/app_service_proxy_factory.h" +#include "chrome/browser/apps/app_service/promise_apps/promise_app_registry_cache.h" +#include "chrome/browser/ash/app_list/app_list_controller_delegate.h" +#include "chrome/browser/ash/app_list/app_list_model_builder.h" +#include "chrome/browser/ash/app_list/app_service/app_service_promise_app_item.h" + +AppServicePromiseAppModelBuilder::AppServicePromiseAppModelBuilder( + AppListControllerDelegate* controller) + : AppListModelBuilder(controller, AppServicePromiseAppItem::kItemType) {} + +AppServicePromiseAppModelBuilder::~AppServicePromiseAppModelBuilder() = default; + +void AppServicePromiseAppModelBuilder::BuildModel() { + CHECK(!promise_app_registry_cache_observation_.IsObserving()); + promise_app_registry_cache_observation_.Observe( + apps::AppServiceProxyFactory::GetForProfile(profile()) + ->PromiseAppRegistryCache()); + + // No need to iterate through the registry cache and insert existing promise + // apps into the model since the registry cache will be empty on start up. + // Promise apps in the cache only get registered/ created when we start new + // app installations, at which point the AppServicePromiseAppModelBuilder + // should already exist. This will change in the future when we support ARC + // default promise apps. + // TODO(b/286981938): Insert existing promise app entries from the registry + // cache. +} + +// Update the App Service Promise App Item for the appropriate promise app if +// one already exists. Otherwise, create a new one. +void AppServicePromiseAppModelBuilder::OnPromiseAppUpdate( + const apps::PromiseAppUpdate& update) { + ChromeAppListItem* item = GetAppItem(update.PackageId().ToString()); + bool show = update.ShouldShow(); + if (item) { + if (show) { + CHECK(item->GetItemType() == AppServicePromiseAppItem::kItemType); + static_cast<AppServicePromiseAppItem*>(item)->OnPromiseAppUpdate(update); + } else { + RemoveApp(update.PackageId().ToString(), false); + } + } else if (show) { + auto promise_app_item = std::make_unique<AppServicePromiseAppItem>( + profile(), model_updater(), update); + InsertApp(std::move(promise_app_item)); + } +} + +void AppServicePromiseAppModelBuilder::OnPromiseAppRegistryCacheWillBeDestroyed( + apps::PromiseAppRegistryCache* cache) { + promise_app_registry_cache_observation_.Reset(); +}
diff --git a/chrome/browser/ash/app_list/app_service/app_service_promise_app_model_builder.h b/chrome/browser/ash/app_list/app_service/app_service_promise_app_model_builder.h new file mode 100644 index 0000000..8b160e1 --- /dev/null +++ b/chrome/browser/ash/app_list/app_service/app_service_promise_app_model_builder.h
@@ -0,0 +1,44 @@ +// 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_ASH_APP_LIST_APP_SERVICE_APP_SERVICE_PROMISE_APP_MODEL_BUILDER_H_ +#define CHROME_BROWSER_ASH_APP_LIST_APP_SERVICE_APP_SERVICE_PROMISE_APP_MODEL_BUILDER_H_ + +#include "base/scoped_observation.h" +#include "chrome/browser/apps/app_service/promise_apps/promise_app_registry_cache.h" +#include "chrome/browser/ash/app_list/app_list_model_builder.h" + +class AppListControllerDelegate; + +// Model builder that creates and manages App Service Promise App Items to track +// entries in the profile's Promise App Registry Cache. +class AppServicePromiseAppModelBuilder + : public AppListModelBuilder, + public apps::PromiseAppRegistryCache::Observer { + public: + explicit AppServicePromiseAppModelBuilder( + AppListControllerDelegate* controller); + + AppServicePromiseAppModelBuilder(const AppServicePromiseAppModelBuilder&) = + delete; + AppServicePromiseAppModelBuilder& operator=( + const AppServicePromiseAppModelBuilder&) = delete; + + ~AppServicePromiseAppModelBuilder() override; + + private: + // AppListModelBuilder overrides: + void BuildModel() override; + + // apps::PromiseAppRegistryCache::Observer overrides: + void OnPromiseAppUpdate(const apps::PromiseAppUpdate& update) override; + void OnPromiseAppRegistryCacheWillBeDestroyed( + apps::PromiseAppRegistryCache* cache) override; + + base::ScopedObservation<apps::PromiseAppRegistryCache, + apps::PromiseAppRegistryCache::Observer> + promise_app_registry_cache_observation_{this}; +}; + +#endif // CHROME_BROWSER_ASH_APP_LIST_APP_SERVICE_APP_SERVICE_PROMISE_APP_MODEL_BUILDER_H_
diff --git a/chrome/browser/ash/app_list/app_service/app_service_promise_app_model_builder_unittest.cc b/chrome/browser/ash/app_list/app_service/app_service_promise_app_model_builder_unittest.cc new file mode 100644 index 0000000..7618ab9 --- /dev/null +++ b/chrome/browser/ash/app_list/app_service/app_service_promise_app_model_builder_unittest.cc
@@ -0,0 +1,135 @@ +// 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/ash/app_list/app_service/app_service_promise_app_model_builder.h" + +#include "ash/constants/ash_features.h" +#include "ash/public/cpp/app_list/app_list_types.h" +#include "chrome/browser/apps/app_service/app_service_proxy.h" +#include "chrome/browser/apps/app_service/app_service_proxy_factory.h" +#include "chrome/browser/apps/app_service/app_service_test.h" +#include "chrome/browser/apps/app_service/package_id.h" +#include "chrome/browser/apps/app_service/promise_apps/promise_app.h" +#include "chrome/browser/apps/app_service/promise_apps/promise_app_registry_cache.h" +#include "chrome/browser/ash/app_list/app_list_test_util.h" +#include "chrome/browser/ash/app_list/chrome_app_list_item.h" +#include "chrome/browser/ash/app_list/internal_app/internal_app_metadata.h" +#include "chrome/browser/ash/app_list/test/fake_app_list_model_updater.h" +#include "chrome/browser/ash/app_list/test/test_app_list_controller_delegate.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/test/base/testing_profile.h" +#include "components/services/app_service/public/cpp/app_types.h" +#include "content/public/test/test_utils.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/display/test/test_screen.h" + +class AppServicePromiseAppModelBuilderTest : public app_list::AppListTestBase { + public: + AppServicePromiseAppModelBuilderTest() = default; + AppServicePromiseAppModelBuilderTest( + const AppServicePromiseAppModelBuilderTest&) = delete; + AppServicePromiseAppModelBuilderTest& operator=( + const AppServicePromiseAppModelBuilderTest&) = delete; + + void TearDown() override { + ResetBuilder(); + AppListTestBase::TearDown(); + } + + protected: + void ResetBuilder() { + scoped_callback_.reset(); + builder_.reset(); + controller_.reset(); + model_updater_.reset(); + } + + // Creates a new builder, destroying any existing one. + void CreateBuilder(bool guest_mode) { + ResetBuilder(); // Destroy any existing builder in the correct order. + scoped_feature_list_.InitAndEnableFeature(ash::features::kPromiseIcons); + testing_profile()->SetGuestSession(guest_mode); + app_service_test_.SetUp(profile()); + model_updater_ = std::make_unique<FakeAppListModelUpdater>( + /*profile=*/nullptr, /*reorder_delegate=*/nullptr); + controller_ = std::make_unique<test::TestAppListControllerDelegate>(); + builder_ = + std::make_unique<AppServicePromiseAppModelBuilder>(controller_.get()); + scoped_callback_ = std::make_unique< + AppServicePromiseAppModelBuilder::ScopedAppPositionInitCallbackForTest>( + builder_.get(), + base::BindRepeating( + &AppServicePromiseAppModelBuilderTest::InitAppPosition, + weak_ptr_factory_.GetWeakPtr())); + builder_->Initialize(nullptr, profile(), model_updater_.get()); + cache_ = apps::AppServiceProxyFactory::GetForProfile(profile()) + ->PromiseAppRegistryCache(); + } + + void InitAppPosition(ChromeAppListItem* item) { + if (!last_position_.IsValid()) { + last_position_ = syncer::StringOrdinal::CreateInitialOrdinal(); + } else { + last_position_ = last_position_.CreateAfter(); + } + item->SetChromePosition(last_position_); + } + + void RegisterTestApps() { + // Register two promise apps in the promise app registry cache. + apps::PromiseAppPtr promise_app_1 = std::make_unique<apps::PromiseApp>( + apps::PackageId(apps::AppType::kArc, "test1")); + promise_app_1->name = "Test 1"; + promise_app_1->should_show = true; + cache()->OnPromiseApp(std::move(promise_app_1)); + + apps::PromiseAppPtr promise_app_2 = std::make_unique<apps::PromiseApp>( + apps::PackageId(apps::AppType::kArc, "test2")); + promise_app_2->name = "Test 2"; + promise_app_2->should_show = true; + cache()->OnPromiseApp(std::move(promise_app_2)); + } + + void BuildModelTest(bool guest_mode) { + CreateBuilder(guest_mode); + EXPECT_EQ(model_updater()->ItemCount(), 0u); + + RegisterTestApps(); + + // Confirm there are 2 launcher promise app items. + EXPECT_EQ(model_updater()->ItemCount(), 2u); + EXPECT_EQ(model_updater()->ItemAtForTest(0)->id(), "android:test1"); + EXPECT_EQ(model_updater()->ItemAtForTest(0)->name(), "Test 1"); + EXPECT_EQ(model_updater()->ItemAtForTest(1)->id(), "android:test2"); + EXPECT_EQ(model_updater()->ItemAtForTest(1)->name(), "Test 2"); + } + + AppListModelUpdater* model_updater() { return model_updater_.get(); } + + apps::PromiseAppRegistryCache* cache() { return cache_; } + + private: + apps::AppServiceTest app_service_test_; + std::unique_ptr< + AppServicePromiseAppModelBuilder::ScopedAppPositionInitCallbackForTest> + scoped_callback_; + std::unique_ptr<AppServicePromiseAppModelBuilder> builder_; + std::unique_ptr<test::TestAppListControllerDelegate> controller_; + std::unique_ptr<FakeAppListModelUpdater> model_updater_; + display::test::TestScreen test_screen_; + std::unique_ptr<Profile> profile_; + base::test::ScopedFeatureList scoped_feature_list_; + apps::PromiseAppRegistryCache* cache_; + syncer::StringOrdinal last_position_; + base::WeakPtrFactory<AppServicePromiseAppModelBuilderTest> weak_ptr_factory_{ + this}; +}; + +TEST_F(AppServicePromiseAppModelBuilderTest, BuildModel) { + BuildModelTest(/*guest_mode=*/true); +} + +TEST_F(AppServicePromiseAppModelBuilderTest, BuildModelGuestMode) { + BuildModelTest(/*guest_mode=*/false); +}
diff --git a/chrome/browser/ash/apps/apk_web_app_service_lacros_browsertest.cc b/chrome/browser/ash/apps/apk_web_app_service_lacros_browsertest.cc index 6cc50b2..8ffda13 100644 --- a/chrome/browser/ash/apps/apk_web_app_service_lacros_browsertest.cc +++ b/chrome/browser/ash/apps/apk_web_app_service_lacros_browsertest.cc
@@ -65,7 +65,9 @@ public: ApkWebAppServiceLacrosBrowserTest() { scoped_feature_list_.InitWithFeatures( - {features::kLacrosSupport, features::kLacrosPrimary}, {}); + {features::kLacrosSupport, features::kLacrosPrimary, + features::kLacrosOnly, features::kLacrosProfileMigrationForceOff}, + {}); dependency_manager_subscription_ = BrowserContextDependencyManager::GetInstance() ->RegisterCreateServicesCallbackForTesting(base::BindRepeating(
diff --git a/chrome/browser/ash/arc/input_overlay/actions/action.cc b/chrome/browser/ash/arc/input_overlay/actions/action.cc index 5a0f0a4..3d838e1 100644 --- a/chrome/browser/ash/arc/input_overlay/actions/action.cc +++ b/chrome/browser/ash/arc/input_overlay/actions/action.cc
@@ -448,12 +448,6 @@ return id_ <= kMaxDefaultActionID; } -bool Action::IsOnLeftSide() { - auto* parent = action_view_->parent(); - DCHECK(parent); - return action_view_->GetTouchCenterInWindow().x() < parent->width() / 2; -} - bool Action::CreateTouchPressedEvent(const base::TimeTicks& time_stamp, std::list<ui::TouchEvent>& touch_events) { if (touch_id_) { @@ -579,17 +573,21 @@ const auto root_point = point.ToString(); float scale = touch_injector_->window()->GetHost()->device_scale_factor(); point.Scale(scale); - const auto root_point_pixel = point.ToString(); - if (touch_injector_->rotation_transform()) { - point = touch_injector_->rotation_transform()->MapPoint(point); - } - touch_down_positions_.emplace_back(point); VLOG(1) << "Calculate touch position for location at index " << i << ": local position {" << calculated_point << "}, root location {" - << root_point << "}, root location in pixels {" << root_point_pixel + << root_point << "}, root location in pixels {" << point.ToString() << "}"; + + if (touch_injector_->rotation_transform()) { + point = touch_injector_->rotation_transform()->MapPoint(point); + } + touch_down_positions_.emplace_back(std::move(point)); } + + on_left_or_middle_side_ = + touch_down_positions_[0].x() <= content_bounds.width() / 2 ? true : false; + DCHECK_EQ(touch_down_positions_.size(), original_positions_.size()); }
diff --git a/chrome/browser/ash/arc/input_overlay/actions/action.h b/chrome/browser/ash/arc/input_overlay/actions/action.h index b9073c0b..f34e904 100644 --- a/chrome/browser/ash/arc/input_overlay/actions/action.h +++ b/chrome/browser/ash/arc/input_overlay/actions/action.h
@@ -150,8 +150,6 @@ ActionView* action_view() const { return action_view_; } void set_action_view(ActionView* action_view) { action_view_ = action_view; } - bool IsOnLeftSide(); - protected: // |touch_injector| must be non-NULL and own this Action. explicit Action(TouchInjector* touch_injector);
diff --git a/chrome/browser/ash/arc/input_overlay/display_overlay_controller.cc b/chrome/browser/ash/arc/input_overlay/display_overlay_controller.cc index c0a1e87d..a64d0f17 100644 --- a/chrome/browser/ash/arc/input_overlay/display_overlay_controller.cc +++ b/chrome/browser/ash/arc/input_overlay/display_overlay_controller.cc
@@ -541,6 +541,10 @@ return type; } +void DisplayOverlayController::AddNewAction(ActionType action_type) { + touch_injector_->AddNewAction(action_type); +} + int DisplayOverlayController::GetTouchInjectorActionsSize() { return touch_injector_->actions().size(); }
diff --git a/chrome/browser/ash/arc/input_overlay/display_overlay_controller.h b/chrome/browser/ash/arc/input_overlay/display_overlay_controller.h index dc28fe0..02f4760 100644 --- a/chrome/browser/ash/arc/input_overlay/display_overlay_controller.h +++ b/chrome/browser/ash/arc/input_overlay/display_overlay_controller.h
@@ -72,6 +72,9 @@ // Get window state type. InputOverlayWindowStateType GetWindowStateType() const; + // For editor. + void AddNewAction(ActionType action_type = ActionType::TAP); + int GetTouchInjectorActionsSize(); // For menu entry hover state:
diff --git a/chrome/browser/ash/arc/input_overlay/touch_injector.cc b/chrome/browser/ash/arc/input_overlay/touch_injector.cc index 9e0c633..ecd3e59 100644 --- a/chrome/browser/ash/arc/input_overlay/touch_injector.cc +++ b/chrome/browser/ash/arc/input_overlay/touch_injector.cc
@@ -858,7 +858,7 @@ return action; } -void TouchInjector::NotifyActionAdded(const Action& action) { +void TouchInjector::NotifyActionAdded(Action& action) { for (auto& observer : observers_) { observer.OnActionAdded(action); } @@ -888,12 +888,15 @@ } void TouchInjector::AddNewAction(ActionType action_type) { + DCHECK(IsBeta()); auto action = CreateRawAction(action_type); if (!action) { return; } - action->InitFromEditor(); + + // Apply the change right away for beta. + NotifyActionAdded(*actions_.emplace_back(std::move(action))); } void TouchInjector::RemoveAction(Action* action) {
diff --git a/chrome/browser/ash/arc/input_overlay/touch_injector.h b/chrome/browser/ash/arc/input_overlay/touch_injector.h index d5192eb..294265d 100644 --- a/chrome/browser/ash/arc/input_overlay/touch_injector.h +++ b/chrome/browser/ash/arc/input_overlay/touch_injector.h
@@ -239,7 +239,7 @@ std::unique_ptr<Action> CreateRawAction(ActionType action_type); // For observers. - void NotifyActionAdded(const Action& action); + void NotifyActionAdded(Action& action); void NotifyActionRemoved(const Action& action); void NotifyActionTypeChanged(const Action& action, const Action& new_action); void NotifyActionUpdated(const Action& action);
diff --git a/chrome/browser/ash/arc/input_overlay/touch_injector_observer.h b/chrome/browser/ash/arc/input_overlay/touch_injector_observer.h index d608cb3e..eed352d 100644 --- a/chrome/browser/ash/arc/input_overlay/touch_injector_observer.h +++ b/chrome/browser/ash/arc/input_overlay/touch_injector_observer.h
@@ -17,7 +17,7 @@ public: TouchInjectorObserver(); - virtual void OnActionAdded(const Action& action) {} + virtual void OnActionAdded(Action& action) {} virtual void OnActionRemoved(const Action& action) {} // Once action type is changed, the original action is removed and // |new_action| with new type is added.
diff --git a/chrome/browser/ash/arc/input_overlay/ui/button_options_menu.cc b/chrome/browser/ash/arc/input_overlay/ui/button_options_menu.cc index d507ac3..5602bf56 100644 --- a/chrome/browser/ash/arc/input_overlay/ui/button_options_menu.cc +++ b/chrome/browser/ash/arc/input_overlay/ui/button_options_menu.cc
@@ -154,7 +154,7 @@ SetLayoutManager(std::make_unique<views::BoxLayout>( views::BoxLayout::Orientation::kVertical)); SetBorder(views::CreateEmptyBorder( - action_->IsOnLeftSide() + action_->on_left_or_middle_side() ? gfx::Insets::TLBR(16, 16 + kTriangleHeight, 16, 16) : gfx::Insets::TLBR(16, 16, 16, 16 + kTriangleHeight))); @@ -343,7 +343,7 @@ int y = action_->GetUICenterPosition().y(); auto parent_size = controller_->GetOverlayWidgetContentsView()->size(); - if (action_->IsOnLeftSide()) { + if (action_->on_left_or_middle_side()) { x += action_view->width() + kMenuActionGap; } else { x -= width() + kMenuActionGap; @@ -393,7 +393,7 @@ ui::ColorProvider* color_provider = GetColorProvider(); flags.setColor(color_provider->GetColor(cros_tokens::kCrosSysBaseElevated)); int height = GetHeightForWidth(kMenuWidth); - bool draw_triangle_on_left = action_->IsOnLeftSide(); + bool draw_triangle_on_left = action_->on_left_or_middle_side(); int action_offset = CalculateActionOffset(height); canvas->DrawPath(BackgroundPath(height, draw_triangle_on_left, action_offset), flags);
diff --git a/chrome/browser/ash/arc/input_overlay/ui/editing_list.cc b/chrome/browser/ash/arc/input_overlay/ui/editing_list.cc index 2bc1228b..4b6023b 100644 --- a/chrome/browser/ash/arc/input_overlay/ui/editing_list.cc +++ b/chrome/browser/ash/arc/input_overlay/ui/editing_list.cc
@@ -70,15 +70,23 @@ AddHeader(main_container); + scroll_content_ = + main_container->AddChildView(std::make_unique<views::View>()); + scroll_content_ + ->SetLayoutManager(std::make_unique<views::BoxLayout>( + views::BoxLayout::Orientation::kVertical, + /*inside_border_insets=*/gfx::Insets(), + /*between_child_spacing=*/8)) + ->set_main_axis_alignment(views::BoxLayout::MainAxisAlignment::kCenter); + // Add contents. if (HasControls()) { - AddControlListContent(main_container); + AddControlListContent(); } else { - AddZeroStateContent(main_container); + AddZeroStateContent(); } SizeToPreferredSize(); - InvalidateLayout(); } bool EditingList::HasControls() const { @@ -119,9 +127,11 @@ IDS_APP_LIST_FOLDER_NAME_PLACEHOLDER)); } -void EditingList::AddZeroStateContent(views::View* container) { +void EditingList::AddZeroStateContent() { + DCHECK(scroll_content_); + auto* content_container = - container->AddChildView(std::make_unique<ash::RoundedContainer>()); + scroll_content_->AddChildView(std::make_unique<ash::RoundedContainer>()); content_container->SetBackground( views::CreateThemedSolidBackground(cros_tokens::kCrosSysSystemOnBase)); content_container->SetBorderInsets(gfx::Insets::VH(48, 32)); @@ -147,7 +157,7 @@ u"Your button will show up here.", cros_tokens::kCrosSysSecondary)); } -void EditingList::AddControlListContent(views::View* container) { +void EditingList::AddControlListContent() { // Add list content as: // -------------------------- // | ---------------------- | @@ -159,14 +169,8 @@ // | ...... | // -------------------------- // TODO(b/270969479): Wrap |scroll_content| in a scroll view. - scroll_content_ = container->AddChildView(std::make_unique<views::View>()); - scroll_content_ - ->SetLayoutManager(std::make_unique<views::BoxLayout>( - views::BoxLayout::Orientation::kVertical, - /*inside_border_insets=*/gfx::Insets(), - /*between_child_spacing=*/8)) - ->set_main_axis_alignment(views::BoxLayout::MainAxisAlignment::kCenter); DCHECK(controller_); + DCHECK(scroll_content_); for (const auto& action : controller_->touch_injector()->actions()) { scroll_content_->AddChildView( std::make_unique<ActionViewListItem>(controller_, action.get())); @@ -174,8 +178,7 @@ } void EditingList::OnAddButtonPressed() { - // TODO(b/270969479): Implement the function for the button. - NOTIMPLEMENTED(); + controller_->AddNewAction(); } void EditingList::OnDoneButtonPressed() { @@ -188,9 +191,18 @@ return gfx::Size(kMainContainerWidth, GetHeightForWidth(kMainContainerWidth)); } -void EditingList::OnActionAdded(const Action& action) { - NOTIMPLEMENTED(); +void EditingList::OnActionAdded(Action& action) { + DCHECK(scroll_content_); + if (controller_->GetTouchInjectorActionsSize() == 1u) { + // Clear the zero-state. + scroll_content_->RemoveAllChildViews(); + } + scroll_content_->AddChildView( + std::make_unique<ActionViewListItem>(controller_, &action)); + + SizeToPreferredSize(); } + void EditingList::OnActionRemoved(const Action& action) { NOTIMPLEMENTED(); }
diff --git a/chrome/browser/ash/arc/input_overlay/ui/editing_list.h b/chrome/browser/ash/arc/input_overlay/ui/editing_list.h index bce8012..62e6336 100644 --- a/chrome/browser/ash/arc/input_overlay/ui/editing_list.h +++ b/chrome/browser/ash/arc/input_overlay/ui/editing_list.h
@@ -33,6 +33,7 @@ ~EditingList() override; private: + friend class EditingListTest; friend class EditLabelTest; void Init(); @@ -40,8 +41,8 @@ // Add UI components to |container| as children. void AddHeader(views::View* container); - void AddZeroStateContent(views::View* container); - void AddControlListContent(views::View* container); + void AddZeroStateContent(); + void AddControlListContent(); // Functions related to buttons. void OnAddButtonPressed(); @@ -51,7 +52,7 @@ gfx::Size CalculatePreferredSize() const override; // TouchInjectorObserver: - void OnActionAdded(const Action& action) override; + void OnActionAdded(Action& action) override; void OnActionRemoved(const Action& action) override; void OnActionTypeChanged(const Action& action, const Action& new_action) override;
diff --git a/chrome/browser/ash/arc/input_overlay/ui/editing_list_unittest.cc b/chrome/browser/ash/arc/input_overlay/ui/editing_list_unittest.cc new file mode 100644 index 0000000..8dee6b2b1 --- /dev/null +++ b/chrome/browser/ash/arc/input_overlay/ui/editing_list_unittest.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 "chrome/browser/ash/arc/input_overlay/ui/editing_list.h" + +#include <memory> + +#include "ash/constants/ash_features.h" +#include "chrome/browser/ash/arc/input_overlay/test/view_test_base.h" +#include "chrome/browser/ash/arc/input_overlay/touch_injector.h" +#include "chrome/browser/ash/arc/input_overlay/ui/input_mapping_view.h" + +namespace arc::input_overlay { + +class EditingListTest : public ViewTestBase { + public: + EditingListTest() = default; + ~EditingListTest() override = default; + + size_t GetActionListItemsSize() { + DCHECK(editing_list_->scroll_content_); + DCHECK(editing_list_); + if (editing_list_->HasControls()) { + return editing_list_->scroll_content_->children().size(); + } + return 0; + } + + size_t GetActionViewSize() { + DCHECK(input_mapping_view_); + return input_mapping_view_->children().size(); + } + + size_t GetTouchInjectorActionSize() { + DCHECK(touch_injector_); + return touch_injector_->actions().size(); + } + + void PressAddButton() { + DCHECK(editing_list_); + editing_list_->OnAddButtonPressed(); + } + + std::unique_ptr<EditingList> editing_list_; + + private: + void SetUp() override { + ViewTestBase::SetUp(); + InitWithFeature(ash::features::kArcInputOverlayBeta); + SetDisplayMode(DisplayMode::kEdit); + + editing_list_ = + std::make_unique<EditingList>(display_overlay_controller_.get()); + editing_list_->Init(); + DCHECK(editing_list_->scroll_content_); + } + + void TearDown() override { + editing_list_.reset(); + ViewTestBase::TearDown(); + } +}; + +TEST_F(EditingListTest, TestEditingListAddNewAction) { + EXPECT_EQ(2u, GetActionListItemsSize()); + EXPECT_EQ(2u, GetActionViewSize()); + EXPECT_EQ(2u, GetTouchInjectorActionSize()); + PressAddButton(); + EXPECT_EQ(3u, GetActionListItemsSize()); + EXPECT_EQ(3u, GetActionViewSize()); + EXPECT_EQ(3u, GetTouchInjectorActionSize()); +} + +} // namespace arc::input_overlay
diff --git a/chrome/browser/ash/arc/input_overlay/ui/input_mapping_view.cc b/chrome/browser/ash/arc/input_overlay/ui/input_mapping_view.cc index 1c5b27a..9e4cb72 100644 --- a/chrome/browser/ash/arc/input_overlay/ui/input_mapping_view.cc +++ b/chrome/browser/ash/arc/input_overlay/ui/input_mapping_view.cc
@@ -136,10 +136,14 @@ } } -void InputMappingView::OnActionAdded(const Action& action) { +void InputMappingView::OnActionAdded(Action& action) { // No add function for pre-beta version. DCHECK(IsBeta()); - NOTIMPLEMENTED(); + + auto view = action.CreateView(controller_); + if (view) { + AddChildView(std::move(view))->SetDisplayMode(current_display_mode_); + } } void InputMappingView::OnActionRemoved(const Action& action) {
diff --git a/chrome/browser/ash/arc/input_overlay/ui/input_mapping_view.h b/chrome/browser/ash/arc/input_overlay/ui/input_mapping_view.h index 35edad0..ec48173 100644 --- a/chrome/browser/ash/arc/input_overlay/ui/input_mapping_view.h +++ b/chrome/browser/ash/arc/input_overlay/ui/input_mapping_view.h
@@ -42,7 +42,7 @@ void OnGestureEvent(ui::GestureEvent* event) override; // TouchInjectorObserver: - void OnActionAdded(const Action& action) override; + void OnActionAdded(Action& action) override; void OnActionRemoved(const Action& action) override; void OnActionTypeChanged(const Action& action, const Action& new_action) override;
diff --git a/chrome/browser/ash/drive/drive_integration_service.cc b/chrome/browser/ash/drive/drive_integration_service.cc index de44327..e8efb6f 100644 --- a/chrome/browser/ash/drive/drive_integration_service.cc +++ b/chrome/browser/ash/drive/drive_integration_service.cc
@@ -22,6 +22,7 @@ #include "base/hash/md5.h" #include "base/logging.h" #include "base/memory/raw_ptr.h" +#include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" #include "base/strings/stringprintf.h" #include "base/system/sys_info.h" @@ -92,12 +93,16 @@ namespace drive { namespace { +using base::Seconds; +using base::SequencedTaskRunner; +using base::TimeDelta; using content::BrowserContext; using content::BrowserThread; using drivefs::mojom::DriveFs; using drivefs::pinning::PinManager; using network::NetworkConnectionTracker; using network::mojom::ConnectionType; +using prefs::kDriveFsBulkPinningEnabled; // Name of the directory used to store metadata. const base::FilePath::CharType kMetadataDirectory[] = FILE_PATH_LITERAL("meta"); @@ -287,7 +292,7 @@ // list of files to pin to the UI thread without waiting for the remaining // data to be cleared. metadata_storage.reset(); - base::SequencedTaskRunner::GetCurrentDefault()->PostTask( + SequencedTaskRunner::GetCurrentDefault()->PostTask( FROM_HERE, base::BindOnce(&CleanupGCacheV1, std::move(cache_directory), std::move(downloads_directory), std::move(dirty_files))); @@ -396,7 +401,7 @@ if (util::IsDriveFsBulkPinningEnabled(profile_)) { pref_change_registrar_.Add( - prefs::kDriveFsBulkPinningEnabled, + kDriveFsBulkPinningEnabled, base::BindRepeating(&PreferenceWatcher::ToggleBulkPinning, weak_ptr_factory_.GetWeakPtr())); } @@ -602,7 +607,7 @@ } void OnMountFailed(MountFailure failure, - absl::optional<base::TimeDelta> remount_delay) override { + absl::optional<TimeDelta> remount_delay) override { mount_observer_->OnMountFailed(failure, std::move(remount_delay)); } @@ -610,7 +615,7 @@ mount_observer_->OnMounted(path); } - void OnUnmounted(absl::optional<base::TimeDelta> remount_delay) override { + void OnUnmounted(absl::optional<TimeDelta> remount_delay) override { mount_observer_->OnUnmounted(std::move(remount_delay)); } @@ -733,9 +738,8 @@ void OnProgress(const Progress& progress) override { if (progress.IsError()) { - VLOG(1) << "Disabling bulk pinning preference"; - pref_service_->SetBoolean(drive::prefs::kDriveFsBulkPinningEnabled, - false); + pref_service_->SetBoolean(kDriveFsBulkPinningEnabled, false); + VLOG(1) << "Disabled bulk-pinning because of error " << progress.stage; } } @@ -797,6 +801,7 @@ DCHECK_CURRENTLY_ON(BrowserThread::UI); weak_ptr_factory_.InvalidateWeakPtrs(); + bulk_pinning_pref_sampling_ = false; RemoveDriveMountPoint(); @@ -917,14 +922,14 @@ } in_clear_cache_ = true; - base::TimeDelta delay; + TimeDelta delay; if (IsMounted()) { RemoveDriveMountPoint(); // TODO(crbug/1069328): We wait 2 seconds here so that DriveFS can unmount // completely. Ideally we'd wait for an unmount complete callback. - delay = base::Seconds(2); + delay = Seconds(2); } - base::SequencedTaskRunner::GetCurrentDefault()->PostDelayedTask( + SequencedTaskRunner::GetCurrentDefault()->PostDelayedTask( FROM_HERE, base::BindOnce( &DriveIntegrationService::ClearCacheAndRemountFileSystemAfterDelay, @@ -1001,6 +1006,7 @@ DCHECK(enabled_); weak_ptr_factory_.InvalidateWeakPtrs(); + bulk_pinning_pref_sampling_ = false; if (GetDriveFsHost()->IsMounted()) { AddDriveMountPointAfterMounted(); @@ -1049,7 +1055,7 @@ NotificationHandler::Type::TRANSIENT, *notification, nullptr); // Disable bulk-pinning. - GetPrefs()->SetBoolean(prefs::kDriveFsBulkPinningEnabled, false); + GetPrefs()->SetBoolean(kDriveFsBulkPinningEnabled, false); } } @@ -1118,7 +1124,7 @@ } void DriveIntegrationService::MaybeRemountFileSystem( - absl::optional<base::TimeDelta> remount_delay, + absl::optional<TimeDelta> remount_delay, bool failed_to_mount) { DCHECK_EQ(INITIALIZED, state_); @@ -1155,12 +1161,12 @@ return; } remount_delay = - base::Seconds(5 * (1 << (drivefs_consecutive_failures_count_ - 1))); + Seconds(5 * (1 << (drivefs_consecutive_failures_count_ - 1))); logger_->Log(logging::LOG_WARNING, "DriveFs died, retry in %d seconds", static_cast<int>(remount_delay.value().InSeconds())); } - base::SequencedTaskRunner::GetCurrentDefault()->PostDelayedTask( + SequencedTaskRunner::GetCurrentDefault()->PostDelayedTask( FROM_HERE, base::BindOnce(&DriveIntegrationService::AddDriveMountPoint, weak_ptr_factory_.GetWeakPtr()), @@ -1209,11 +1215,31 @@ } ToggleBulkPinning(); + + if (!bulk_pinning_pref_sampling_) { + bulk_pinning_pref_sampling_ = true; + SampleBulkPinningPref(); + } } } +void DriveIntegrationService::SampleBulkPinningPref() { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + DCHECK(bulk_pinning_pref_sampling_); + const bool enabled = GetPrefs()->GetBoolean(kDriveFsBulkPinningEnabled); + VLOG(1) << "Bulk-pinning is currently " << (enabled ? "en" : "dis") + << "abled"; + base::UmaHistogramBoolean("FileBrowser.GoogleDrive.BulkPinning.Enabled", + enabled); + SequencedTaskRunner::GetCurrentDefault()->PostDelayedTask( + FROM_HERE, + base::BindOnce(&DriveIntegrationService::SampleBulkPinningPref, + weak_ptr_factory_.GetWeakPtr()), + base::Hours(1)); +} + void DriveIntegrationService::OnUnmounted( - absl::optional<base::TimeDelta> remount_delay) { + absl::optional<TimeDelta> remount_delay) { UmaEmitUnmountOutcome(remount_delay ? DriveMountStatus::kTemporaryUnavailable : DriveMountStatus::kUnknownFailure); MaybeRemountFileSystem(remount_delay, false); @@ -1221,7 +1247,7 @@ void DriveIntegrationService::OnMountFailed( MountFailure failure, - absl::optional<base::TimeDelta> remount_delay) { + absl::optional<TimeDelta> remount_delay) { PrefService* prefs = GetPrefs(); DriveMountStatus status = ConvertMountFailure(failure); UmaEmitMountStatus(status); @@ -1329,7 +1355,7 @@ return; } - if (GetPrefs()->GetBoolean(prefs::kDriveFsBulkPinningEnabled)) { + if (GetPrefs()->GetBoolean(kDriveFsBulkPinningEnabled)) { pin_manager_->ShouldPin(true); pin_manager_->Start(); } else { @@ -1532,7 +1558,7 @@ } void DriveIntegrationService::RestartDrive() { - MaybeRemountFileSystem(base::TimeDelta(), false); + MaybeRemountFileSystem(TimeDelta(), false); } void DriveIntegrationService::SetStartupArguments(
diff --git a/chrome/browser/ash/drive/drive_integration_service.h b/chrome/browser/ash/drive/drive_integration_service.h index 372ac2e..e4d003e 100644 --- a/chrome/browser/ash/drive/drive_integration_service.h +++ b/chrome/browser/ash/drive/drive_integration_service.h
@@ -408,6 +408,10 @@ // Enable or disable DriveFS bulk pinning. void ToggleBulkPinning(); + // Regularly samples the bulk-pinning preference and stores the result in a + // UMA histogram. + void SampleBulkPinningPref(); + void OnGetOfflineItemsPage( int64_t total_size, mojo::Remote<drivefs::mojom::SearchQuery> search_query, @@ -446,6 +450,10 @@ bool enabled_; bool mount_failed_ = false; bool in_clear_cache_ = false; + + // Is the bulk-pinning preference sampling task currently scheduled? + bool bulk_pinning_pref_sampling_ = false; + // Custom mount point name that can be injected for testing in constructor. std::string mount_point_name_;
diff --git a/chrome/browser/ash/extensions/autotest_private/autotest_private_apitest.cc b/chrome/browser/ash/extensions/autotest_private/autotest_private_apitest.cc index 406c1dd..bf2adc08 100644 --- a/chrome/browser/ash/extensions/autotest_private/autotest_private_apitest.cc +++ b/chrome/browser/ash/extensions/autotest_private/autotest_private_apitest.cc
@@ -42,6 +42,7 @@ #include "chrome/browser/ash/settings/scoped_testing_cros_settings.h" #include "chrome/browser/ash/system_web_apps/test_support/test_system_web_app_installation.h" #include "chrome/browser/extensions/extension_apitest.h" +#include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/ui/ash/shelf/chrome_shelf_prefs.h" #include "chrome/browser/ui/browser_window.h" #include "components/feature_engagement/public/feature_constants.h" @@ -505,13 +506,29 @@ protected: AutotestPrivateLacrosTest() { - feature_list_.InitAndEnableFeature(ash::features::kLacrosSupport); + feature_list_.InitWithFeatures( + { + ash::features::kLacrosSupport, + ash::features::kLacrosPrimary, + ash::features::kLacrosOnly, + ash::features::kLacrosProfileMigrationForceOff, + }, + {}); crosapi::BrowserManager::DisableForTesting(); } ~AutotestPrivateLacrosTest() override { crosapi::BrowserManager::EnableForTesting(); } + void SetUpOnMainThread() override { + // For testing APIs, we need web browser instance as JS runtime. + Browser::CreateParams params(ProfileManager::GetLastUsedProfile(), false); + Browser::Create(params); + SelectFirstBrowser(); + + AutotestPrivateApiTest::SetUpOnMainThread(); + } + private: base::test::ScopedFeatureList feature_list_; };
diff --git a/chrome/browser/ash/extensions/file_manager/private_api_util.cc b/chrome/browser/ash/extensions/file_manager/private_api_util.cc index 25cbf9f..789a1fae 100644 --- a/chrome/browser/ash/extensions/file_manager/private_api_util.cc +++ b/chrome/browser/ash/extensions/file_manager/private_api_util.cc
@@ -248,8 +248,12 @@ switch (stage) { case drivefs::pinning::Stage::kStopped: return extensions::api::file_manager_private::BULK_PIN_STAGE_STOPPED; - case drivefs::pinning::Stage::kPaused: - return extensions::api::file_manager_private::BULK_PIN_STAGE_PAUSED; + case drivefs::pinning::Stage::kPausedOffline: + return extensions::api::file_manager_private:: + BULK_PIN_STAGE_PAUSED_OFFLINE; + case drivefs::pinning::Stage::kPausedBatterySaver: + return extensions::api::file_manager_private:: + BULK_PIN_STAGE_PAUSED_BATTERY_SAVER; case drivefs::pinning::Stage::kGettingFreeSpace: return extensions::api::file_manager_private:: BULK_PIN_STAGE_GETTING_FREE_SPACE;
diff --git a/chrome/browser/ash/file_manager/file_manager_string_util.cc b/chrome/browser/ash/file_manager/file_manager_string_util.cc index b01a0b5..9884375 100644 --- a/chrome/browser/ash/file_manager/file_manager_string_util.cc +++ b/chrome/browser/ash/file_manager/file_manager_string_util.cc
@@ -216,6 +216,8 @@ IDS_FILE_BROWSER_GOOGLE_DRIVE_SINGLE_FILE_SYNCING_LABEL); SET_STRING("DRIVE_ALL_FILES_SYNCED", IDS_FILE_BROWSER_GOOGLE_DRIVE_ALL_FILES_SYNCED_LABEL); + SET_STRING("DRIVE_BULK_PINNING_BATTERY_SAVER", + IDS_FILE_BROWSER_BULK_PINNING_BATTERY_SAVER_LABEL); SET_STRING("DRIVE_BULK_PINNING_OFFLINE", IDS_FILE_BROWSER_BULK_PINNING_OFFLINE_LABEL); SET_STRING("DRIVE_BULK_PINNING_NOT_ENOUGH_SPACE", @@ -355,7 +357,8 @@ SET_STRING("ARCHIVE_MOUNT_MESSAGE", IDS_FILE_BROWSER_ARCHIVE_MOUNT_MESSAGE); SET_STRING("ARCHIVE_MOUNT_INVALID_PATH", IDS_FILE_BROWSER_ARCHIVE_MOUNT_INVALID_PATH); - SET_STRING("BULK_PINNING_TURN_ON", IDS_FILE_BROWSER_BULK_PINNING_TURN_ON); + SET_STRING("BULK_PINNING_BATTERY_SAVER", + IDS_FILE_BROWSER_BULK_PINNING_BATTERY_SAVER); SET_STRING("BULK_PINNING_ERROR", IDS_FILE_BROWSER_BULK_PINNING_ERROR); SET_STRING("BULK_PINNING_EXPLANATION", IDS_FILE_BROWSER_BULK_PINNING_EXPLANATION); @@ -368,6 +371,7 @@ SET_STRING("BULK_PINNING_POINT_1", IDS_FILE_BROWSER_BULK_PINNING_POINT_1); SET_STRING("BULK_PINNING_SPACE", IDS_FILE_BROWSER_BULK_PINNING_SPACE); SET_STRING("BULK_PINNING_TITLE", IDS_FILE_BROWSER_BULK_PINNING_TITLE); + SET_STRING("BULK_PINNING_TURN_ON", IDS_FILE_BROWSER_BULK_PINNING_TURN_ON); SET_STRING("BULK_PINNING_VIEW_STORAGE", IDS_FILE_BROWSER_BULK_PINNING_VIEW_STORAGE); SET_STRING("CALCULATING_SIZE", IDS_FILE_BROWSER_CALCULATING_SIZE);
diff --git a/chrome/browser/ash/geolocation/system_geolocation_source.cc b/chrome/browser/ash/geolocation/system_geolocation_source.cc index a8f60a0..6d14041 100644 --- a/chrome/browser/ash/geolocation/system_geolocation_source.cc +++ b/chrome/browser/ash/geolocation/system_geolocation_source.cc
@@ -50,17 +50,29 @@ } } -void SystemGeolocationSource::AppAttemptsToUseGeolocation() { +void SystemGeolocationSource::TrackGeolocationAttempted( + const std::string& app_name) { if (auto* controller = GeolocationPrivacySwitchController::Get()) { - controller->OnAppStartsUsingGeolocation( - l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME)); + if (!app_name.empty()) { + controller->TrackGeolocationAttempted(app_name); + } else { + // Use the default name for this app. + controller->TrackGeolocationAttempted( + l10n_util::GetStringUTF8(IDS_SHORT_PRODUCT_NAME)); + } } } -void SystemGeolocationSource::AppCeasesToUseGeolocation() { +void SystemGeolocationSource::TrackGeolocationRelinquished( + const std::string& app_name) { if (auto* controller = GeolocationPrivacySwitchController::Get()) { - controller->OnAppStopsUsingGeolocation( - l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME)); + if (!app_name.empty()) { + controller->TrackGeolocationRelinquished(app_name); + } else { + // Use the default id for this app. + controller->TrackGeolocationAttempted( + l10n_util::GetStringUTF8(IDS_SHORT_PRODUCT_NAME)); + } } }
diff --git a/chrome/browser/ash/geolocation/system_geolocation_source.h b/chrome/browser/ash/geolocation/system_geolocation_source.h index 78d84b1..46ebd7d 100644 --- a/chrome/browser/ash/geolocation/system_geolocation_source.h +++ b/chrome/browser/ash/geolocation/system_geolocation_source.h
@@ -38,8 +38,8 @@ // device::SystemGeolocationSource: void RegisterPermissionUpdateCallback( PermissionUpdateCallback callback) override; - void AppAttemptsToUseGeolocation() override; - void AppCeasesToUseGeolocation() override; + void TrackGeolocationAttempted(const std::string& app_name) override; + void TrackGeolocationRelinquished(const std::string& app_name) override; private: // SessionObserver:
diff --git a/chrome/browser/ash/login/oobe_quick_start/second_device_auth_broker.cc b/chrome/browser/ash/login/oobe_quick_start/second_device_auth_broker.cc index ada7401..5f10d9d461 100644 --- a/chrome/browser/ash/login/oobe_quick_start/second_device_auth_broker.cc +++ b/chrome/browser/ash/login/oobe_quick_start/second_device_auth_broker.cc
@@ -80,6 +80,10 @@ constexpr char kHttpMethod[] = "POST"; constexpr char kHttpContentType[] = "application/json"; +constexpr char kGetChallengeDataRequest[] = R"({ + "target_device_type": "CHROME_OS" + })"; + constexpr auto kRejectionReasonErrorMap = base::MakeFixedFlatMap< base::StringPiece, SecondDeviceAuthBroker::RefreshTokenRejectionResponse::Reason>({ @@ -118,8 +122,8 @@ "Google's authentication server" trigger: "When the user starts the Quick Start flow from OOBE" data: - "Nothing. Authentication to this API is done through Chrome's API " - "key" + "A JSON dict that identifies the device type as ChromeOS. " + "Authentication to this API is done through Chrome's API key" destination: GOOGLE_OWNED_SERVICE } policy { @@ -596,7 +600,7 @@ /*http_method=*/kHttpMethod, /*content_type=*/kHttpContentType, /*timeout_ms=*/kGetChallengeDataTimeoutInSeconds * 1000, - /*post_data=*/std::string(), + /*post_data=*/kGetChallengeDataRequest, /*headers=*/std::vector<std::string>(), /*annotation_tag=*/kChallengeDataAnnotation, /*is_stable_channel=*/chrome::GetChannel() ==
diff --git a/chrome/browser/ash/login/oobe_quick_start/second_device_auth_broker_unittest.cc b/chrome/browser/ash/login/oobe_quick_start/second_device_auth_broker_unittest.cc index 7654acd..18dace9 100644 --- a/chrome/browser/ash/login/oobe_quick_start/second_device_auth_broker_unittest.cc +++ b/chrome/browser/ash/login/oobe_quick_start/second_device_auth_broker_unittest.cc
@@ -8,11 +8,14 @@ #include <string> #include <utility> +#include "base/json/json_reader.h" #include "base/memory/scoped_refptr.h" +#include "base/test/bind.h" #include "base/test/gtest_util.h" #include "base/test/task_environment.h" #include "base/test/test_future.h" #include "base/types/expected.h" +#include "base/values.h" #include "chrome/browser/ash/login/oobe_quick_start/connectivity/fido_assertion_info.h" #include "chromeos/ash/components/attestation/attestation_flow.h" #include "chromeos/ash/components/attestation/mock_attestation_flow.h" @@ -22,12 +25,16 @@ #include "google_apis/gaia/google_service_auth_error.h" #include "net/http/http_status_code.h" #include "services/data_decoder/public/cpp/test_support/in_process_data_decoder.h" +#include "services/network/public/cpp/data_element.h" +#include "services/network/public/cpp/resource_request.h" #include "services/network/public/cpp/shared_url_loader_factory.h" #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" #include "services/network/test/test_url_loader_factory.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/abseil-cpp/absl/types/variant.h" +#include "url/gurl.h" namespace ash::quick_start { @@ -84,6 +91,8 @@ constexpr char kFidoCredentialId[] = "fido_credential_id"; constexpr char kCertificate[] = "fake_certificate"; constexpr char kFakeDeviceId[] = "fake_device_id"; +constexpr char kTargetDeviceType[] = "target_device_type"; +constexpr char kChromeOS[] = "CHROME_OS"; MATCHER_P(ProtoBufContentBindingEq, expected, "") { return arg.content_binding() == expected; @@ -216,6 +225,18 @@ test_factory_.AddResponse(url, response, status); } + // Sets an `interceptor`. Overwrites any other interceptor that may have been + // previously set. + void SetInterceptor( + const network::TestURLLoaderFactory::Interceptor& interceptor) { + test_factory_.SetInterceptor(interceptor); + } + + void SimulateBadRequest(const std::string& url) { + test_factory_.AddResponse(url, /*content=*/std::string(), + net::HTTP_BAD_REQUEST); + } + void SimulateAuthError(const std::string& url) { test_factory_.AddResponse(url, /*content=*/std::string(), net::HTTP_UNAUTHORIZED); @@ -317,7 +338,41 @@ } TEST_F(SecondDeviceAuthBrokerTest, GetChallengeBytesReturnsChallengeBytes) { - AddFakeResponse(kGetChallengeDataUrl, kFakeChallengeDataResponse); + // Set an interceptor that checks the validity of the incoming request for + // challenge bytes. + SetInterceptor( + base::BindLambdaForTesting([&](const network::ResourceRequest& request) { + if (request.url != GURL(kGetChallengeDataUrl)) { + return; + } + + if (!request.request_body || !request.request_body->elements() || + request.request_body->elements()->empty()) { + SimulateBadRequest(kGetChallengeDataUrl); + return; + } + + absl::optional<base::Value> request_body = + base::JSONReader::Read(request.request_body->elements() + ->at(0) + .As<network::DataElementBytes>() + .AsStringPiece()); + if (!request_body || !request_body->is_dict()) { + SimulateBadRequest(kGetChallengeDataUrl); + return; + } + + const base::Value::Dict& request_dict = request_body->GetDict(); + const std::string* target_device_type = + request_dict.FindString(kTargetDeviceType); + if (!target_device_type || *target_device_type != kChromeOS) { + SimulateBadRequest(kGetChallengeDataUrl); + return; + } + + AddFakeResponse(kGetChallengeDataUrl, kFakeChallengeDataResponse); + })); + base::expected<std::string, GoogleServiceAuthError> response = GetChallengeBytes(); ASSERT_TRUE(response.has_value());
diff --git a/chrome/browser/companion/visual_search/BUILD.gn b/chrome/browser/companion/visual_search/BUILD.gn index 0499b37..129a6d1b 100644 --- a/chrome/browser/companion/visual_search/BUILD.gn +++ b/chrome/browser/companion/visual_search/BUILD.gn
@@ -6,6 +6,8 @@ sources = [ "features.cc", "features.h", + "visual_search_classifier_host.cc", + "visual_search_classifier_host.h", "visual_search_suggestions_service.cc", "visual_search_suggestions_service.h", ] @@ -21,12 +23,17 @@ source_set("unit_tests") { testonly = true - sources = [ "visual_search_suggestions_service_unittest.cc" ] - + sources = [ + "visual_search_classifier_host_unittest.cc", + "visual_search_suggestions_service_unittest.cc", + ] deps = [ ":visual_search", "//base", "//base/test:test_support", + "//chrome/browser", + "//chrome/common", + "//chrome/test:test_support", "//components/optimization_guide/core:test_support", "//components/optimization_guide/proto:optimization_guide_proto", "//testing/gmock",
diff --git a/chrome/browser/companion/visual_search/visual_search_classifier_host.cc b/chrome/browser/companion/visual_search/visual_search_classifier_host.cc new file mode 100644 index 0000000..878d695 --- /dev/null +++ b/chrome/browser/companion/visual_search/visual_search_classifier_host.cc
@@ -0,0 +1,115 @@ +// 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/companion/visual_search/visual_search_classifier_host.h" + +#include "base/base64.h" +#include "base/metrics/histogram_macros_local.h" +#include "base/task/thread_pool.h" +#include "chrome/browser/companion/visual_search/features.h" +#include "chrome/browser/companion/visual_search/visual_search_suggestions_service.h" +#include "third_party/abseil-cpp/absl/types/optional.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "third_party/skia/include/core/SkColorSpace.h" +#include "third_party/skia/include/core/SkStream.h" +#include "third_party/skia/include/encode/SkJpegEncoder.h" +#include "ui/gfx/image/buffer_w_stream.h" +#include "ui/gfx/image/image_skia.h" +#include "ui/gfx/image/image_skia_rep.h" +#include "url/gurl.h" + +namespace companion::visual_search { + +namespace { +absl::optional<std::string> Base64EncodeBitmap(const SkBitmap& bitmap) { + gfx::BufferWStream stream; + const bool encoding_succeeded = + SkJpegEncoder::Encode(&stream, bitmap.pixmap(), {}); + + if (!encoding_succeeded) { + return absl::nullopt; + } + + base::StringPiece mime_subtype = "jpg"; + std::string result = "data:image/"; + result.append(mime_subtype.begin(), mime_subtype.end()); + result.append(";base64,"); + result.append( + base::Base64Encode(base::as_bytes(base::make_span(stream.TakeBuffer())))); + return result; +} + +// Close the provided model file. +void CloseModelFile(base::File model_file) { + if (!model_file.IsValid()) { + return; + } + model_file.Close(); +} +} // namespace + +VisualSearchClassifierHost::VisualSearchClassifierHost( + VisualSearchSuggestionsService* visual_search_service) + : visual_search_service_(visual_search_service) {} + +VisualSearchClassifierHost::~VisualSearchClassifierHost() = default; + +void VisualSearchClassifierHost::OnClassificationResult( + const std::vector<SkBitmap>& images) { + std::vector<std::string> data_uris; + data_uris.reserve(images.size()); + LOCAL_HISTOGRAM_COUNTS_100("Companion.VisualSearch.ClassificationResultsSize", + images.size()); + + // converts list of SkBitmaps to data uris used as img.src for browser. + for (const auto& image : images) { + auto data_uri = Base64EncodeBitmap(image); + if (data_uri) { + data_uris.push_back(data_uri.value()); + } + } + + // TODO(b/284648407): Do mojom IPC to side panel using mojom::CompanionPage. +} + +// TODO(pstjuste): RenderFrameHost is used to setup IPC communication with +// renderer process via the InterfaceRegistry. Eventually, the url will be +// used for caching visual search suggestions without having to do IPC. +void VisualSearchClassifierHost::StartClassification( + content::RenderFrameHost* render_frame_host, + const GURL& validated_url) { + base::File model = visual_search_service_->GetModelFile(); + LOCAL_HISTOGRAM_BOOLEAN("Companion.VisualSearch.ModelFileSuccess", + model.IsValid()); + if (!model.IsValid()) { + return; + } + + std::string base64_config; + absl::optional<std::string> config_switch = + switches::GetVisualSearchConfigForCompanionOverride(); + + // Replace empty string with config switch if we have one. + if (config_switch) { + base64_config = std::move(config_switch.value()); + } + + VLOG(1) << "ClassificationSuccess " << classifier_agent_.is_null(); + LOCAL_HISTOGRAM_BOOLEAN("Companion.VisualSearch.StartClassificationSuccess", + !classifier_agent_.is_null()); + if (!classifier_agent_.is_null()) { + std::move(classifier_agent_).Run(0, std::move(model), base64_config); + } else { + // Closing file in background thread since we did not make IPC. + base::ThreadPool::PostTask( + FROM_HERE, {base::MayBlock()}, + base::BindOnce(&CloseModelFile, std::move(model))); + } +} + +void VisualSearchClassifierHost::SetClassifierAgentForTesting( + ClassifierAgent agent) { + classifier_agent_ = std::move(agent); +} +} // namespace companion::visual_search
diff --git a/chrome/browser/companion/visual_search/visual_search_classifier_host.h b/chrome/browser/companion/visual_search/visual_search_classifier_host.h new file mode 100644 index 0000000..7277636 --- /dev/null +++ b/chrome/browser/companion/visual_search/visual_search_classifier_host.h
@@ -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. + +#ifndef CHROME_BROWSER_COMPANION_VISUAL_SEARCH_VISUAL_SEARCH_CLASSIFIER_HOST_H_ +#define CHROME_BROWSER_COMPANION_VISUAL_SEARCH_VISUAL_SEARCH_CLASSIFIER_HOST_H_ + +#include <memory> +#include "chrome/browser/companion/visual_search/visual_search_suggestions_service.h" +#include "content/public/browser/render_frame_host.h" +#include "url/gurl.h" + +namespace companion::visual_search { + +// This class serves as the main orchestator for visual search suggestions +// components. It handles mojom IPC with both main renderer and side panel. +// It also fetches model file descriptors from the keyed service. +class VisualSearchClassifierHost { + public: + using ClassifierAgent = + base::OnceCallback<void(int, base::File, std::string)>; + + explicit VisualSearchClassifierHost( + VisualSearchSuggestionsService* visual_search_service); + + VisualSearchClassifierHost(const VisualSearchClassifierHost&) = delete; + VisualSearchClassifierHost& operator=(const VisualSearchClassifierHost&) = + delete; + ~VisualSearchClassifierHost(); + + // This is the main method used by the companion page handler to start the + // visual search classification task. The RenderFrameHost is needed to + // establish IPC channel with the Renderer process. + void StartClassification(content::RenderFrameHost* render_frame_host, + const GURL& validated_url); + + // Set the classifier agent that will be used to do mojom IPC. + // This should only be used for testing, not for production. + void SetClassifierAgentForTesting(ClassifierAgent agent); + + private: + // Processes the list of images returned from the visual search classifier. + // Its main job is to take a list of SkBitmap and convert to data uris. + // The list of image data uris are sent to side panel companion for rendering. + void OnClassificationResult(const std::vector<SkBitmap>& images); + + // Pointer to visual search service which we do not own. + raw_ptr<VisualSearchSuggestionsService> visual_search_service_ = nullptr; + + // This classifier agent is used to send mojom IPC to renderer. + ClassifierAgent classifier_agent_; +}; +} // namespace companion::visual_search + +#endif // CHROME_BROWSER_COMPANION_VISUAL_SEARCH_VISUAL_SEARCH_CLASSIFIER_HOST_H_
diff --git a/chrome/browser/companion/visual_search/visual_search_classifier_host_unittest.cc b/chrome/browser/companion/visual_search/visual_search_classifier_host_unittest.cc new file mode 100644 index 0000000..67ccfa1a --- /dev/null +++ b/chrome/browser/companion/visual_search/visual_search_classifier_host_unittest.cc
@@ -0,0 +1,175 @@ +// 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/companion/visual_search/visual_search_classifier_host.h" + +#include <memory> + +#include "base/containers/flat_set.h" +#include "base/files/file_path.h" +#include "base/files/file_util.h" +#include "base/functional/bind.h" +#include "base/memory/scoped_refptr.h" +#include "base/path_service.h" +#include "base/task/sequenced_task_runner.h" +#include "base/task/task_traits.h" +#include "base/task/thread_pool.h" +#include "base/test/metrics/histogram_tester.h" +#include "chrome/browser/companion/visual_search/features.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/test/base/chrome_render_view_host_test_harness.h" +#include "components/optimization_guide/core/test_model_info_builder.h" +#include "components/optimization_guide/core/test_optimization_guide_model_provider.h" +#include "components/optimization_guide/proto/models.pb.h" +#include "content/public/browser/render_frame_host.h" +#include "content/public/browser/web_contents.h" +#include "content/public/test/browser_test_utils.h" +#include "content/public/test/mock_render_process_host.h" +#include "content/public/test/test_renderer_host.h" +#include "content/public/test/web_contents_tester.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace companion::visual_search { + +namespace { + +static const char kModelFilename[] = "visual_model.tflite"; + +} // namespace + +class VisualSearchClassifierHostTest : public ChromeRenderViewHostTestHarness { + public: + VisualSearchClassifierHostTest() : url_("www.style-files.com") {} + ~VisualSearchClassifierHostTest() override = default; + + void SetUp() override { + ChromeRenderViewHostTestHarness::SetUp(); + + scoped_refptr<base::SequencedTaskRunner> background_task_runner = + base::ThreadPool::CreateSequencedTaskRunner( + {base::MayBlock(), base::TaskPriority::BEST_EFFORT}); + test_model_provider_ = std::make_unique< + optimization_guide::TestOptimizationGuideModelProvider>(); + service_ = std::make_unique< + companion::visual_search::VisualSearchSuggestionsService>( + test_model_provider_.get(), background_task_runner); + + visual_search_host_ = + std::make_unique<companion::visual_search::VisualSearchClassifierHost>( + service_.get()); + } + + void SetModelPath() { + base::FilePath test_data_dir; + base::PathService::Get(base::DIR_SOURCE_ROOT, &test_data_dir); + test_data_dir = test_data_dir.AppendASCII("components/test/data"); + + base::flat_set<base::FilePath> additional_files; + additional_files.insert(test_data_dir.AppendASCII(kModelFilename)); + + model_info_ = + optimization_guide::TestModelInfoBuilder() + .SetModelFilePath(test_data_dir.AppendASCII(kModelFilename)) + .SetAdditionalFiles(additional_files) + .SetVersion(123) + .Build(); + + service_->OnModelUpdated( + optimization_guide::proto::OptimizationTarget:: + OPTIMIZATION_TARGET_VISUAL_SEARCH_CLASSIFICATION, + *model_info_); + + base::RunLoop().RunUntilIdle(); + } + + void TearDown() override { + service_->Shutdown(); + ChromeRenderViewHostTestHarness::TearDown(); + } + + protected: + std::unique_ptr<optimization_guide::TestOptimizationGuideModelProvider> + test_model_provider_; + std::unique_ptr<optimization_guide::ModelInfo> model_info_; + std::unique_ptr<companion::visual_search::VisualSearchSuggestionsService> + service_; + std::unique_ptr<companion::visual_search::VisualSearchClassifierHost> + visual_search_host_; + const GURL url_; + base::HistogramTester histogram_tester_; +}; + +TEST_F(VisualSearchClassifierHostTest, StartClassification) { + SetModelPath(); + VisualSearchClassifierHost::ClassifierAgent agent = base::BindOnce( + [](int request_id, base::File model_file, std::string proto_string) { + EXPECT_EQ(request_id, 0); + ASSERT_TRUE(model_file.IsValid()); + EXPECT_EQ(proto_string, ""); + }); + visual_search_host_->SetClassifierAgentForTesting(std::move(agent)); + visual_search_host_->StartClassification( + web_contents()->GetPrimaryMainFrame(), url_); + histogram_tester_.ExpectBucketCount("Companion.VisualSearch.ModelFileSuccess", + true, 1); + histogram_tester_.ExpectBucketCount( + "Companion.VisualSearch.StartClassificationSuccess", true, 1); +} + +TEST_F(VisualSearchClassifierHostTest, StartClassification_WithOverride) { + SetModelPath(); + const std::string config_string = "config_string"; + base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( + switches::kVisualSearchConfigForCompanion, config_string); + VisualSearchClassifierHost::ClassifierAgent agent = base::BindOnce( + [](int request_id, base::File model_file, std::string proto_string) { + EXPECT_EQ(request_id, 0); + ASSERT_TRUE(model_file.IsValid()); + EXPECT_EQ(proto_string, "config_string"); + }); + visual_search_host_->SetClassifierAgentForTesting(std::move(agent)); + visual_search_host_->StartClassification( + web_contents()->GetPrimaryMainFrame(), url_); + histogram_tester_.ExpectBucketCount("Companion.VisualSearch.ModelFileSuccess", + true, 1); + histogram_tester_.ExpectBucketCount( + "Companion.VisualSearch.StartClassificationSuccess", true, 1); +} + +TEST_F(VisualSearchClassifierHostTest, StartClassification_NoModelSet) { + VisualSearchClassifierHost::ClassifierAgent agent = base::BindOnce( + [](int request_id, base::File model_file, std::string proto_string) { + EXPECT_EQ(request_id, 0); + ASSERT_FALSE(model_file.IsValid()); + EXPECT_EQ(proto_string, ""); + }); + visual_search_host_->SetClassifierAgentForTesting(std::move(agent)); + visual_search_host_->StartClassification( + web_contents()->GetPrimaryMainFrame(), url_); + histogram_tester_.ExpectBucketCount("Companion.VisualSearch.ModelFileSuccess", + false, 1); +} + +TEST_F(VisualSearchClassifierHostTest, + StartClassification_ModelSetWithNoCallbackSet) { + SetModelPath(); + visual_search_host_->StartClassification( + web_contents()->GetPrimaryMainFrame(), url_); + histogram_tester_.ExpectBucketCount("Companion.VisualSearch.ModelFileSuccess", + true, 1); + histogram_tester_.ExpectBucketCount( + "Companion.VisualSearch.StartClassificationSuccess", false, 1); +} + +TEST_F(VisualSearchClassifierHostTest, + StartClassification_NoModelSetAndNoCallbackSet) { + base::HistogramTester histogram_tester; + visual_search_host_->StartClassification( + web_contents()->GetPrimaryMainFrame(), url_); + histogram_tester_.ExpectBucketCount("Companion.VisualSearch.ModelFileSuccess", + false, 1); +} + +} // namespace companion::visual_search
diff --git a/chrome/browser/extensions/extension_keeplist_chromeos.cc b/chrome/browser/extensions/extension_keeplist_chromeos.cc index cf19d3e..ab92bb8 100644 --- a/chrome/browser/extensions/extension_keeplist_chromeos.cc +++ b/chrome/browser/extensions/extension_keeplist_chromeos.cc
@@ -74,6 +74,7 @@ extension_misc::kSigninProfileTestExtensionId, extension_misc::kGuestModeTestExtensionId, extension_misc::kHelpAppExtensionId, + extension_misc::kAutotestPrivateTestExtensionId, file_manager::kImageLoaderExtensionId, #endif extension_misc::kKeyboardExtensionId,
diff --git a/chrome/browser/extensions/service_worker_lifetime_strong_keepalive_browsertest.cc b/chrome/browser/extensions/service_worker_lifetime_strong_keepalive_browsertest.cc index 4971738b..2913c4c 100644 --- a/chrome/browser/extensions/service_worker_lifetime_strong_keepalive_browsertest.cc +++ b/chrome/browser/extensions/service_worker_lifetime_strong_keepalive_browsertest.cc
@@ -201,8 +201,16 @@ // Tests that the service workers will not stop if both extensions are // allowlisted via policy and the port is not closed. +// TODO(https://crbug.com/1454339): Flakes on Linux. +#if BUILDFLAG(IS_LINUX) +#define MAYBE_ServiceWorkersDoNotTimeOutWithPolicy \ + DISABLED_ServiceWorkersDoNotTimeOutWithPolicy +#else +#define MAYBE_ServiceWorkersDoNotTimeOutWithPolicy \ + ServiceWorkersDoNotTimeOutWithPolicy +#endif IN_PROC_BROWSER_TEST_F(ServiceWorkerLifetimeStrongKeepaliveBrowsertest, - ServiceWorkersDoNotTimeOutWithPolicy) { + MAYBE_ServiceWorkersDoNotTimeOutWithPolicy) { base::Value::List urls; // Both extensions receive extended lifetime. urls.Append(kTestOpenerExtensionUrl);
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index 1064c8a..9b4bda3 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -1292,6 +1292,11 @@ "expiry_milestone": 122 }, { + "name": "cros-battery-saver-always-on", + "owners": [ "chromeos-bsm@google.com", "cwd" ], + "expiry_milestone": 122 + }, + { "name": "cros-labs-overview-desk-navigation", "owners": [ "richui", "janetmac" ], "expiry_milestone": 122 @@ -6860,6 +6865,11 @@ "expiry_milestone": 116 }, { + "name": "service-worker-static-router", + "owners": [ "yyanagisawa@google.com", "sisidovski@google.com", "chrome-worker@google.com" ], + "expiry_milestone": 125 + }, + { "name": "set-market-url-for-testing", "owners": [ "//chrome/android/java/src/org/chromium/chrome/browser/omaha/OWNERS" ], // This is required by test teams to verify functionality on devices which
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index 6021349..6569e33 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -740,6 +740,11 @@ "fetch handler, the feature may affect the page load. This feature will be " "overridden by chrome://flags/#service-worker-bypass-fetch-handler"; +const char kServiceWorkerStaticRouterName[] = "Service Worker Static Router"; +const char kServiceWorkerStaticRouterDescription[] = + "When enabled, Chrome will enable the Service Worker Static Routing API. " + "https://chromestatus.com/feature/5185352976826368"; + const char kChromeLabsName[] = "Chrome Labs"; const char kChromeLabsDescription[] = "Access Chrome Labs through the toolbar menu to see featured user-facing " @@ -5349,6 +5354,12 @@ "Show a desk button that provides quick access to the desk menu in the " "shelf in clamshell mode when there is more than one desk."; +const char kCrosBatterySaverAlwaysOnName[] = + "Make ChromeOS Battery Saver on all the time"; +const char kCrosBatterySaverAlwaysOnDescription[] = + "Turns on ChomeOS Battery Saver all the time, even when charging or fully " + "charged. Used for testing ChromeOS Battery Saver Mode."; + const char kCrosBatterySaverName[] = "Enable ChromeOS Battery Saver Mode Support"; const char kCrosBatterySaverDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index 02cad043..fa256da 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -403,6 +403,9 @@ extern const char kServiceWorkerBypassFetchHandlerForMainResourceName[]; extern const char kServiceWorkerBypassFetchHandlerForMainResourceDescription[]; +extern const char kServiceWorkerStaticRouterName[]; +extern const char kServiceWorkerStaticRouterDescription[]; + extern const char kCanvasOopRasterizationName[]; extern const char kCanvasOopRasterizationDescription[]; @@ -3059,6 +3062,9 @@ extern const char kCaptureModeGifRecordingName[]; extern const char kCaptureModeGifRecordingDescription[]; +extern const char kCrosBatterySaverAlwaysOnName[]; +extern const char kCrosBatterySaverAlwaysOnDescription[]; + extern const char kCrosBatterySaverName[]; extern const char kCrosBatterySaverDescription[];
diff --git a/chrome/browser/pdf/pdf_extension_accessibility_test.cc b/chrome/browser/pdf/pdf_extension_accessibility_test.cc index 98a9b1dc..21aee1f 100644 --- a/chrome/browser/pdf/pdf_extension_accessibility_test.cc +++ b/chrome/browser/pdf/pdf_extension_accessibility_test.cc
@@ -640,6 +640,13 @@ return enabled; } + std::vector<base::test::FeatureRef> GetDisabledFeatures() const override { + auto disabled = PDFExtensionAccessibilityTest::GetDisabledFeatures(); + // PDF OCR should not modify the dump. + disabled.push_back(::features::kPdfOcr); + return disabled; + } + void RunPDFTest(const base::FilePath::CharType* pdf_file) { base::FilePath test_path = ui_test_utils::GetTestFilePath( base::FilePath(FILE_PATH_LITERAL("pdf")),
diff --git a/chrome/browser/resources/chromeos/emoji_picker/emoji_category_button.html b/chrome/browser/resources/chromeos/emoji_picker/emoji_category_button.html index e5d2e5e8..0846bc12 100644 --- a/chrome/browser/resources/chromeos/emoji_picker/emoji_category_button.html +++ b/chrome/browser/resources/chromeos/emoji_picker/emoji_category_button.html
@@ -40,5 +40,6 @@ iron-icon="[[icon]]" on-click="handleClick" aria-label$="[[getAriaLabel(name, gifSupport)]]" + aria-pressed$="[[getAriaPressedState(gifSupport)]]" > </cr-icon-button>
diff --git a/chrome/browser/resources/chromeos/emoji_picker/emoji_category_button.ts b/chrome/browser/resources/chromeos/emoji_picker/emoji_category_button.ts index f0ee885..c68d0916 100644 --- a/chrome/browser/resources/chromeos/emoji_picker/emoji_category_button.ts +++ b/chrome/browser/resources/chromeos/emoji_picker/emoji_category_button.ts
@@ -63,6 +63,10 @@ return ARIA_LABELS_WITH_GIF_SUPPORT[name] ?? name; } + + private getAriaPressedState(active: boolean): string { + return active ? 'true' : 'false'; + } } declare global {
diff --git a/chrome/browser/resources/chromeos/emoji_picker/emoji_group_button.html b/chrome/browser/resources/chromeos/emoji_picker/emoji_group_button.html index c328f5a3..66d74c4e 100644 --- a/chrome/browser/resources/chromeos/emoji_picker/emoji_group_button.html +++ b/chrome/browser/resources/chromeos/emoji_picker/emoji_group_button.html
@@ -31,6 +31,7 @@ class$="[[calculateClassName(active)]]" on-click="handleClick" aria-label="[[name]]" + aria-pressed$="[[getAriaPressedState(active)]]" disabled="[[disabled]]" custom-tab-index="[[customTabIndex]]"> </cr-icon-button>
diff --git a/chrome/browser/resources/chromeos/emoji_picker/emoji_group_button.ts b/chrome/browser/resources/chromeos/emoji_picker/emoji_group_button.ts index aa36ab3..6bc3d7ff 100644 --- a/chrome/browser/resources/chromeos/emoji_picker/emoji_group_button.ts +++ b/chrome/browser/resources/chromeos/emoji_picker/emoji_group_button.ts
@@ -45,6 +45,10 @@ private calculateClassName(active: boolean): string { return active ? 'emoji-group-active' : ''; } + + private getAriaPressedState(active: boolean): string { + return active ? 'true' : 'false'; + } } declare global {
diff --git a/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.html b/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.html index 6e95323..aa981d6 100644 --- a/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.html +++ b/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.html
@@ -374,6 +374,7 @@ </template> <cr-icon-button id="right-chevron" class="chevron" on-click="onRightChevronClick" + on-keydown="onRightChevronKeyDown" iron-icon="emoji_picker:keyboard_arrow_right"> </cr-icon-button> </div>
diff --git a/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.ts b/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.ts index f3e2992..49d2514 100644 --- a/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.ts +++ b/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.ts
@@ -700,6 +700,28 @@ } } + private onRightChevronKeyDown(event: KeyboardEvent) { + // Moves focus to the first button under the group of current category if + // user tries to move to the next element from right chevron button in a11y + // mode. + if (event.code === 'Tab' && !event.shiftKey) { + const currentGroups = this.shadowRoot! + .querySelectorAll<EmojiGroupComponent>( + `emoji-group[category='${this.category}'`); + + // The first group might be a history group. If the user has no history + // item, we should continue to check the second group. + for (const group of currentGroups) { + const button = group.firstEmojiButton(); + if (button) { + button.focus(); + event.preventDefault(); + return; + } + } + } + } + private onLeftChevronClick() { this.pagination = Math.max(this.pagination - 1, 1); this.updateCurrentGroupTabs();
diff --git a/chrome/browser/safe_browsing/client_side_detection_service_unittest.cc b/chrome/browser/safe_browsing/client_side_detection_service_unittest.cc index 979bfea..82006a59 100644 --- a/chrome/browser/safe_browsing/client_side_detection_service_unittest.cc +++ b/chrome/browser/safe_browsing/client_side_detection_service_unittest.cc
@@ -106,7 +106,7 @@ class ClientSideDetectionServiceTest : public testing::Test, - public testing::WithParamInterface<std::tuple<bool, bool>> { + public testing::WithParamInterface<std::tuple<bool, bool, bool>> { public: ClientSideDetectionServiceTest() : profile_manager_(TestingBrowserProcess::GetGlobal()) { @@ -125,12 +125,18 @@ {kSafeBrowsingDailyPhishingReportsLimit, params}); } + if (ShouldEnableImageEmbeddingModelCacao()) { + enabled_features.push_back({kClientSideDetectionModelImageEmbedder, {}}); + } + feature_list_.InitWithFeaturesAndParameters(enabled_features, {}); } bool ShouldEnableCacao() { return get<0>(GetParam()); } bool ShouldEnableESBDailyPhishingLimit() { return get<1>(GetParam()); } + bool ShouldEnableImageEmbeddingModelCacao() { return get<2>(GetParam()); } + protected: void SetUp() override { test_shared_loader_factory_ = @@ -316,7 +322,9 @@ INSTANTIATE_TEST_SUITE_P(All, ClientSideDetectionServiceTest, - testing::Combine(testing::Bool(), testing::Bool())); + testing::Combine(testing::Bool(), + testing::Bool(), + testing::Bool())); TEST_P(ClientSideDetectionServiceTest, ServiceObjectDeletedBeforeCallbackDone) { csd_service_ = std::make_unique<ClientSideDetectionService>( @@ -604,4 +612,29 @@ EXPECT_TRUE(csd_service_->enabled()); } +TEST_P(ClientSideDetectionServiceTest, + TestReceivingImageEmbedderUpdatesAfterResubscription) { + if (!(base::FeatureList::IsEnabled( + kClientSideDetectionModelOptimizationGuide) && + base::FeatureList::IsEnabled(kClientSideDetectionModelImageEmbedder))) { + return; + } + + profile_->GetPrefs()->SetBoolean(prefs::kSafeBrowsingEnabled, true); + profile_->GetPrefs()->SetBoolean(prefs::kSafeBrowsingEnhanced, true); + csd_service_ = std::make_unique<ClientSideDetectionService>( + std::make_unique<ChromeClientSideDetectionServiceDelegate>(profile_), + model_observer_tracker_.get(), background_task_runner_); + + EXPECT_TRUE(csd_service_->IsSubscribedToImageEmbeddingModelUpdates()); + + profile_->GetPrefs()->SetBoolean(prefs::kSafeBrowsingEnhanced, false); + EXPECT_TRUE(csd_service_->IsSubscribedToImageEmbeddingModelUpdates()); + EXPECT_FALSE(csd_service_->ShouldSendImageEmbeddingModelToRenderer()); + + profile_->GetPrefs()->SetBoolean(prefs::kSafeBrowsingEnhanced, true); + EXPECT_TRUE(csd_service_->IsSubscribedToImageEmbeddingModelUpdates()); + EXPECT_TRUE(csd_service_->ShouldSendImageEmbeddingModelToRenderer()); +} + } // namespace safe_browsing
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index 94549cd..0a794e87 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -510,6 +510,7 @@ "//chrome/browser/breadcrumbs", "//chrome/browser/chrome_for_testing:buildflags", "//chrome/browser/companion/core", + "//chrome/browser/companion/visual_search", "//chrome/browser/devtools", "//chrome/browser/favicon", "//chrome/browser/google", @@ -2118,6 +2119,10 @@ "../ash/app_list/app_service/app_service_app_model_builder.h", "../ash/app_list/app_service/app_service_context_menu.cc", "../ash/app_list/app_service/app_service_context_menu.h", + "../ash/app_list/app_service/app_service_promise_app_item.cc", + "../ash/app_list/app_service/app_service_promise_app_item.h", + "../ash/app_list/app_service/app_service_promise_app_model_builder.cc", + "../ash/app_list/app_service/app_service_promise_app_model_builder.h", "../ash/app_list/app_sync_ui_state.cc", "../ash/app_list/app_sync_ui_state.h", "../ash/app_list/app_sync_ui_state_factory.cc",
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhone.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhone.java index 804935b..db277f2 100644 --- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhone.java +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhone.java
@@ -1124,7 +1124,10 @@ * Updates the toolbar height and bottom padding during URL focus changing. */ private void updateToolbarLayoutForUrlFocusChangeAnimation() { - if (!OmniboxFeatures.shouldShowModernizeVisualUpdate(getContext())) { + // With the smallest margins variant enabled, we still increase the height of the location + // bar bg but don't increase the height of the toolbar. + if (!OmniboxFeatures.shouldShowModernizeVisualUpdate(getContext()) + || OmniboxFeatures.shouldShowSmallestMargins(getContext())) { return; }
diff --git a/chrome/browser/ui/ash/shelf/chrome_shelf_controller_unittest.cc b/chrome/browser/ui/ash/shelf/chrome_shelf_controller_unittest.cc index 653d67c1..33704616 100644 --- a/chrome/browser/ui/ash/shelf/chrome_shelf_controller_unittest.cc +++ b/chrome/browser/ui/ash/shelf/chrome_shelf_controller_unittest.cc
@@ -1345,7 +1345,11 @@ class ChromeShelfControllerLacrosTest : public ChromeShelfControllerTestBase { public: ChromeShelfControllerLacrosTest() { - feature_list_.InitAndEnableFeature(ash::features::kLacrosSupport); + feature_list_.InitWithFeatures( + {ash::features::kLacrosSupport, ash::features::kLacrosPrimary, + ash::features::kLacrosOnly, + ash::features::kLacrosProfileMigrationForceOff}, + {}); crosapi::browser_util::SetProfileMigrationCompletedForTest(true); } ChromeShelfControllerLacrosTest(const ChromeShelfControllerLacrosTest&) = @@ -1380,18 +1384,22 @@ std::unique_ptr<user_manager::ScopedUserManager> scoped_user_manager_; }; -class ChromeShelfControllerLacrosPrimaryTest +// TODO(hidehiko): Merge this base class into ChromeShelfControllerLacrosTest. +class ChromeShelfControllerLacrosOnlyTest : public ChromeShelfControllerLacrosTest { public: - ChromeShelfControllerLacrosPrimaryTest() { + ChromeShelfControllerLacrosOnlyTest() { scoped_feature_list_.InitWithFeatures( - {ash::features::kLacrosSupport, ash::features::kLacrosPrimary}, {}); + {ash::features::kLacrosSupport, ash::features::kLacrosPrimary, + ash::features::kLacrosOnly, + ash::features::kLacrosProfileMigrationForceOff}, + {}); } - ChromeShelfControllerLacrosPrimaryTest( - const ChromeShelfControllerLacrosPrimaryTest&) = delete; - ChromeShelfControllerLacrosPrimaryTest& operator=( - const ChromeShelfControllerLacrosPrimaryTest&) = delete; - ~ChromeShelfControllerLacrosPrimaryTest() override = default; + ChromeShelfControllerLacrosOnlyTest( + const ChromeShelfControllerLacrosOnlyTest&) = delete; + ChromeShelfControllerLacrosOnlyTest& operator=( + const ChromeShelfControllerLacrosOnlyTest&) = delete; + ~ChromeShelfControllerLacrosOnlyTest() override = default; void SetUp() override { ChromeShelfControllerLacrosTest::SetUp(); @@ -1830,12 +1838,12 @@ TEST_F(ChromeShelfControllerLacrosTest, LacrosPinnedByDefault) { InitShelfController(); - EXPECT_EQ("Chrome, Lacros", GetPinnedAppStatus()); + EXPECT_EQ("Chrome", GetPinnedAppStatus()); } // Checks that AppService instance is updated appropriately for one Chrome app // window. -TEST_F(ChromeShelfControllerLacrosPrimaryTest, ChromeAppWindow) { +TEST_F(ChromeShelfControllerLacrosOnlyTest, ChromeAppWindow) { InitShelfController(); auto window = std::make_unique<aura::Window>(nullptr); @@ -1888,7 +1896,7 @@ // Checks that AppService instance is updated appropriately for multiple Chrome // app windows. -TEST_F(ChromeShelfControllerLacrosPrimaryTest, ChromeAppWindows) { +TEST_F(ChromeShelfControllerLacrosOnlyTest, ChromeAppWindows) { InitShelfController(); auto window1 = std::make_unique<aura::Window>(nullptr); @@ -1956,7 +1964,7 @@ } // Regression test for crash. crbug.com/1296949 -TEST_F(ChromeShelfControllerLacrosPrimaryTest, WithoutAppService) { +TEST_F(ChromeShelfControllerLacrosOnlyTest, WithoutAppService) { Profile* const controller_profile = profile()->GetOffTheRecordProfile( Profile::OTRProfileID::CreateUniqueForTesting(), /*create_if_needed=*/true);
diff --git a/chrome/browser/ui/views/web_apps/frame_toolbar/web_app_frame_toolbar_browsertest.cc b/chrome/browser/ui/views/web_apps/frame_toolbar/web_app_frame_toolbar_browsertest.cc index 6916c91..06010bd2 100644 --- a/chrome/browser/ui/views/web_apps/frame_toolbar/web_app_frame_toolbar_browsertest.cc +++ b/chrome/browser/ui/views/web_apps/frame_toolbar/web_app_frame_toolbar_browsertest.cc
@@ -121,6 +121,77 @@ test_extension_dir.UnpackedPath()); } +void TestDraggableRegions(BrowserView* browser_view, + gfx::Point& draggable_point, + gfx::Point& non_draggable_point, + gfx::Point& border_point, + bool is_isolated_web_app) { + views::NonClientFrameView* frame_view = + browser_view->GetWidget()->non_client_view()->frame_view(); + + views::View::ConvertPointToTarget(browser_view->contents_web_view(), + frame_view, &draggable_point); + views::View::ConvertPointToTarget(browser_view->contents_web_view(), + frame_view, &non_draggable_point); + + // Wait for draggable regions value to update. This is to avoid flakiness + // crbug.com/1277860. + while (frame_view->NonClientHitTest(draggable_point) != HTCAPTION) { + base::RunLoop run_loop; + base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask( + FROM_HERE, run_loop.QuitClosure(), TestTimeouts::tiny_timeout()); + run_loop.Run(); + } + + // Validate that a point marked "app-region: drag" is draggable. + EXPECT_EQ(frame_view->NonClientHitTest(draggable_point), HTCAPTION); + EXPECT_FALSE(browser_view->ShouldDescendIntoChildForEventHandling( + browser_view->GetWidget()->GetNativeView(), draggable_point)); + + // Validate that a point marked "app-region: no-drag" within a draggable + // region is not draggable. + EXPECT_EQ(frame_view->NonClientHitTest(non_draggable_point), HTCLIENT); + EXPECT_TRUE(browser_view->ShouldDescendIntoChildForEventHandling( + browser_view->GetWidget()->GetNativeView(), non_draggable_point)); + + // Validate that a point at the border that does not intersect with the + // overlays is not marked as draggable. + EXPECT_NE(frame_view->NonClientHitTest(border_point), HTCAPTION); + EXPECT_TRUE(browser_view->ShouldDescendIntoChildForEventHandling( + browser_view->GetWidget()->GetNativeView(), border_point)); + + // Validate that draggable region does not clear after history.replaceState is + // invoked. + std::string kHistoryReplaceState = + "history.replaceState({ test: 'test' }, null);"; + EXPECT_TRUE( + ExecJs(browser_view->GetActiveWebContents(), kHistoryReplaceState)); + EXPECT_FALSE(browser_view->ShouldDescendIntoChildForEventHandling( + browser_view->GetWidget()->GetNativeView(), draggable_point)); + + // Isolated Web Apps do not support out-scope navigations. + if (is_isolated_web_app) { + return; + } + + // Validate that the draggable region reset behaviour on navigation. + ASSERT_TRUE(ui_test_utils::NavigateToURL(browser_view->browser(), + GURL("http://example.test/"))); + + // Wait for draggable regions value to update. This is to avoid flakiness + // crbug.com/1277860. + while (frame_view->NonClientHitTest(draggable_point) == HTCAPTION) { + base::RunLoop run_loop; + base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask( + FROM_HERE, run_loop.QuitClosure(), TestTimeouts::tiny_timeout()); + run_loop.Run(); + } + + EXPECT_NE(frame_view->NonClientHitTest(draggable_point), HTCAPTION); + EXPECT_TRUE(browser_view->ShouldDescendIntoChildForEventHandling( + browser_view->GetWidget()->GetNativeView(), draggable_point)); +} + } // namespace class WebAppFrameToolbarBrowserTest @@ -790,6 +861,20 @@ EXPECT_EQ(frame_view()->GetMinimumSize(), gfx::Size(1, 1)); #endif } + +IN_PROC_BROWSER_TEST_F(BorderlessIsolatedWebAppBrowserTest, DraggableRegions) { + InstallAndLaunchIsolatedWebApp(/*uses_borderless=*/true); + GrantWindowManagementPermission(); + + // The draggable and non-draggable regions are defined in + // borderless_isolated_app/styles.css. + gfx::Point draggable_point(100, 100), non_draggable_point(106, 106), + border_point(100, 1); + TestDraggableRegions(browser_view(), draggable_point, non_draggable_point, + border_point, + /*is_isolated_web_app=*/true); +} + #endif // (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)) class WebAppFrameToolbarBrowserTest_WindowControlsOverlay @@ -1241,13 +1326,19 @@ EXPECT_EQ(initial_height_value, updated_rect_list[3].GetInt()); } -// TODO(https://crbug.com/1277860): Flaky. Also enable for borderless mode when -// fixed. IN_PROC_BROWSER_TEST_F(WebAppFrameToolbarBrowserTest_WindowControlsOverlay, - DISABLED_WindowControlsOverlayDraggableRegions) { + DraggableRegions) { InstallAndLaunchWebApp(); ToggleWindowControlsOverlayAndWait(); - helper()->TestDraggableRegions(); + + // The draggable and non-draggable regions are defined in kTestHTML in + // `WebAppFrameToolbarTestHelper:: + // LoadWindowControlsOverlayTestPageWithDataAndGetURL`. + gfx::Point draggable_point(100, 100), non_draggable_point(106, 106), + border_point(100, 1); + TestDraggableRegions(helper()->browser_view(), draggable_point, + non_draggable_point, border_point, + /*is_isolated_web_app=*/false); } IN_PROC_BROWSER_TEST_F(WebAppFrameToolbarBrowserTest_WindowControlsOverlay,
diff --git a/chrome/browser/ui/views/web_apps/frame_toolbar/web_app_frame_toolbar_test_helper.cc b/chrome/browser/ui/views/web_apps/frame_toolbar/web_app_frame_toolbar_test_helper.cc index 8cba4bc..7a5546d 100644 --- a/chrome/browser/ui/views/web_apps/frame_toolbar/web_app_frame_toolbar_test_helper.cc +++ b/chrome/browser/ui/views/web_apps/frame_toolbar/web_app_frame_toolbar_test_helper.cc
@@ -7,7 +7,6 @@ #include "base/files/file_util.h" #include "base/files/scoped_temp_dir.h" #include "base/notreached.h" -#include "base/run_loop.h" #include "base/strings/utf_string_conversions.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/views/frame/browser_non_client_frame_view.h" @@ -183,64 +182,6 @@ "}")); } -// TODO(https://crbug.com/1277860): Flaky. -void WebAppFrameToolbarTestHelper::TestDraggableRegions() { - views::NonClientFrameView* frame_view = - browser_view()->GetWidget()->non_client_view()->frame_view(); - - // Draggable regions take some time to initialize after opening and tests fail - // if not exhausting the run loop before checking the value. - base::RunLoop run_loop; - run_loop.RunUntilIdle(); - - // Validate that a point marked "app-region: drag" is draggable. The draggable - // region is defined in the kTestHTML of WebAppFrameToolbarTestHelper's - // LoadWindowControlsOverlayTestPageWithDataAndGetURL. - gfx::Point draggable_point(100, 100); - views::View::ConvertPointToTarget(browser_view()->contents_web_view(), - frame_view, &draggable_point); - - EXPECT_EQ(frame_view->NonClientHitTest(draggable_point), HTCAPTION); - - EXPECT_FALSE(browser_view()->ShouldDescendIntoChildForEventHandling( - browser_view()->GetWidget()->GetNativeView(), draggable_point)); - - // Validate that a point marked "app-region: no-drag" within a draggable - // region is not draggable. - gfx::Point non_draggable_point(106, 106); - views::View::ConvertPointToTarget(browser_view()->contents_web_view(), - frame_view, &non_draggable_point); - - EXPECT_EQ(frame_view->NonClientHitTest(non_draggable_point), HTCLIENT); - - EXPECT_TRUE(browser_view()->ShouldDescendIntoChildForEventHandling( - browser_view()->GetWidget()->GetNativeView(), non_draggable_point)); - - // Validate that a point at the border that does not intersect with the - // overlays is not marked as draggable. - constexpr gfx::Point kBorderPoint(100, 1); - EXPECT_NE(frame_view->NonClientHitTest(kBorderPoint), HTCAPTION); - EXPECT_TRUE(browser_view()->ShouldDescendIntoChildForEventHandling( - browser_view()->GetWidget()->GetNativeView(), kBorderPoint)); - - // Validate that draggable region does not clear after history.replaceState is - // invoked. - std::string kHistoryReplaceState = - "history.replaceState({ test: 'test' }, null);"; - EXPECT_TRUE( - ExecJs(browser_view()->GetActiveWebContents(), kHistoryReplaceState)); - EXPECT_FALSE(browser_view()->ShouldDescendIntoChildForEventHandling( - browser_view()->GetWidget()->GetNativeView(), draggable_point)); - - // Validate that the draggable region is reset on navigation and the point is - // no longer draggable. - ASSERT_TRUE(ui_test_utils::NavigateToURL(browser_view()->browser(), - GURL("http://example.test/"))); - EXPECT_NE(frame_view->NonClientHitTest(draggable_point), HTCAPTION); - EXPECT_TRUE(browser_view()->ShouldDescendIntoChildForEventHandling( - browser_view()->GetWidget()->GetNativeView(), draggable_point)); -} - BrowserView* WebAppFrameToolbarTestHelper::OpenPopup( const std::string& window_open_script) { content::ExecuteScriptAsync(browser_view_->GetActiveWebContents(),
diff --git a/chrome/browser/ui/views/web_apps/frame_toolbar/web_app_frame_toolbar_test_helper.h b/chrome/browser/ui/views/web_apps/frame_toolbar/web_app_frame_toolbar_test_helper.h index b719837..7c088ac2 100644 --- a/chrome/browser/ui/views/web_apps/frame_toolbar/web_app_frame_toolbar_test_helper.h +++ b/chrome/browser/ui/views/web_apps/frame_toolbar/web_app_frame_toolbar_test_helper.h
@@ -66,8 +66,6 @@ // Add window-controls-overlay's ongeometrychange callback into the document. void SetupGeometryChangeCallback(content::WebContents* web_contents); - void TestDraggableRegions(); - // Opens a new popup window from |app_browser_| by running // |window_open_script| and returns the |BrowserView| it opened in. BrowserView* OpenPopup(const std::string& window_open_script);
diff --git a/chrome/browser/ui/webui/side_panel/companion/companion_page_handler.cc b/chrome/browser/ui/webui/side_panel/companion/companion_page_handler.cc index d6d1e567..c4e0ac7 100644 --- a/chrome/browser/ui/webui/side_panel/companion/companion_page_handler.cc +++ b/chrome/browser/ui/webui/side_panel/companion/companion_page_handler.cc
@@ -12,6 +12,8 @@ #include "chrome/browser/companion/core/promo_handler.h" #include "chrome/browser/companion/text_finder/text_finder_manager.h" #include "chrome/browser/companion/text_finder/text_highlighter_manager.h" +#include "chrome/browser/companion/visual_search/features.h" +#include "chrome/browser/companion/visual_search/visual_search_suggestions_service_factory.h" #include "chrome/browser/feature_engagement/tracker_factory.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/search/search.h" @@ -61,6 +63,13 @@ identity_manager_observation_.Observe( IdentityManagerFactory::GetForProfile(GetProfile())); consent_helper_observation_.Observe(consent_helper_.get()); + if (base::FeatureList::IsEnabled( + visual_search::features::kVisualSearchSuggestions)) { + visual_search_host_ = + std::make_unique<visual_search::VisualSearchClassifierHost>( + visual_search::VisualSearchSuggestionsServiceFactory::GetForProfile( + GetProfile())); + } } CompanionPageHandler::~CompanionPageHandler() { @@ -128,6 +137,22 @@ NotifyURLChanged(/*is_full_reload=*/false); } +void CompanionPageHandler::DidFinishLoad( + content::RenderFrameHost* render_frame_host, + const GURL& validated_url) { + // We only want to classify images in the main frame. + if (!render_frame_host->IsInPrimaryMainFrame()) { + return; + } + + // TODO(b/284640445) - Add browser test to verify side effect of feature + // on/off, use histogram check to determine whether or not classification was + // called. + if (visual_search_host_) { + visual_search_host_->StartClassification(render_frame_host, validated_url); + } +} + void CompanionPageHandler::ShowUI() { if (auto embedder = companion_untrusted_ui_->embedder()) { embedder->ShowUI();
diff --git a/chrome/browser/ui/webui/side_panel/companion/companion_page_handler.h b/chrome/browser/ui/webui/side_panel/companion/companion_page_handler.h index 5409321..64713f8 100644 --- a/chrome/browser/ui/webui/side_panel/companion/companion_page_handler.h +++ b/chrome/browser/ui/webui/side_panel/companion/companion_page_handler.h
@@ -10,6 +10,7 @@ #include "base/scoped_observation.h" #include "chrome/browser/companion/core/constants.h" #include "chrome/browser/companion/core/mojom/companion.mojom.h" +#include "chrome/browser/companion/visual_search/visual_search_classifier_host.h" #include "chrome/browser/ui/side_panel/side_panel_enums.h" #include "components/lens/buildflags.h" #include "components/signin/public/identity_manager/identity_manager.h" @@ -72,6 +73,8 @@ // IdentityManager::Observer overrides. void OnPrimaryAccountChanged( const signin::PrimaryAccountChangeEvent& event) override; + void DidFinishLoad(content::RenderFrameHost* render_frame_host, + const GURL& validated_url) override; // UrlKeyedDataCollectionConsentHelper::Observer overrides. void OnUrlKeyedDataCollectionConsentStateChanged( @@ -110,6 +113,10 @@ std::unique_ptr<unified_consent::UrlKeyedDataCollectionConsentHelper> consent_helper_; + // Owns the orchestrator for visual search suggestions. + std::unique_ptr<visual_search::VisualSearchClassifierHost> + visual_search_host_; + // Logs metrics for companion page. Reset when there is a new navigation. std::unique_ptr<CompanionMetricsLogger> metrics_logger_;
diff --git a/chrome/browser/web_applications/BUILD.gn b/chrome/browser/web_applications/BUILD.gn index b45f448..660e8f6 100644 --- a/chrome/browser/web_applications/BUILD.gn +++ b/chrome/browser/web_applications/BUILD.gn
@@ -183,10 +183,16 @@ "preinstalled_web_apps/preinstalled_web_app_definition_utils.h", "preinstalled_web_apps/preinstalled_web_apps.cc", "preinstalled_web_apps/preinstalled_web_apps.h", - "remove_web_app_job.cc", - "remove_web_app_job.h", "scope_extension_info.cc", "scope_extension_info.h", + "uninstall/remove_install_source_job.cc", + "uninstall/remove_install_source_job.h", + "uninstall/remove_install_url_job.cc", + "uninstall/remove_install_url_job.h", + "uninstall/remove_web_app_job.cc", + "uninstall/remove_web_app_job.h", + "uninstall/uninstall_job.cc", + "uninstall/uninstall_job.h", "user_display_mode.cc", "user_display_mode.h", "user_uninstalled_preinstalled_web_app_prefs.cc",
diff --git a/chrome/browser/web_applications/commands/web_app_uninstall_command.cc b/chrome/browser/web_applications/commands/web_app_uninstall_command.cc index 70c6fc6..2238544 100644 --- a/chrome/browser/web_applications/commands/web_app_uninstall_command.cc +++ b/chrome/browser/web_applications/commands/web_app_uninstall_command.cc
@@ -5,147 +5,39 @@ #include "chrome/browser/web_applications/commands/web_app_uninstall_command.h" #include <memory> -#include <sstream> #include <utility> -#include "base/containers/contains.h" +#include "base/check.h" #include "base/functional/bind.h" #include "base/metrics/histogram_functions.h" -#include "base/strings/to_string.h" -#include "chrome/browser/profiles/profile.h" #include "chrome/browser/web_applications/locks/all_apps_lock.h" -#include "chrome/browser/web_applications/remove_web_app_job.h" -#include "chrome/browser/web_applications/user_uninstalled_preinstalled_web_app_prefs.h" -#include "chrome/browser/web_applications/web_app.h" -#include "chrome/browser/web_applications/web_app_constants.h" -#include "chrome/browser/web_applications/web_app_id.h" -#include "chrome/browser/web_applications/web_app_install_manager.h" -#include "chrome/browser/web_applications/web_app_install_utils.h" -#include "chrome/browser/web_applications/web_app_registrar.h" -#include "chrome/browser/web_applications/web_app_registry_update.h" +#include "chrome/browser/web_applications/uninstall/uninstall_job.h" #include "components/webapps/browser/installable/installable_metrics.h" #include "components/webapps/browser/uninstall_result_code.h" namespace web_app { -namespace { - -bool CanUninstallAllManagementSources( - webapps::WebappUninstallSource uninstall_source) { - // Check that the source was from a known 'user' or allowed ones such - // as kMigration. - return uninstall_source == webapps::WebappUninstallSource::kUnknown || - uninstall_source == webapps::WebappUninstallSource::kAppMenu || - uninstall_source == webapps::WebappUninstallSource::kAppsPage || - uninstall_source == webapps::WebappUninstallSource::kOsSettings || - uninstall_source == webapps::WebappUninstallSource::kAppManagement || - uninstall_source == webapps::WebappUninstallSource::kMigration || - uninstall_source == webapps::WebappUninstallSource::kAppList || - uninstall_source == webapps::WebappUninstallSource::kShelf || - uninstall_source == webapps::WebappUninstallSource::kSync || - uninstall_source == webapps::WebappUninstallSource::kStartupCleanup || - uninstall_source == webapps::WebappUninstallSource::kTestCleanup; -} - -} // namespace - WebAppUninstallCommand::WebAppUninstallCommand( - const AppId& app_id, - absl::optional<WebAppManagement::Type> management_type_or_all, - webapps::WebappUninstallSource uninstall_source, - UninstallWebAppCallback callback, - Profile& profile) + std::unique_ptr<UninstallJob> job, + UninstallJob::Callback callback) : WebAppCommandTemplate<AllAppsLock>("WebAppUninstallCommand"), lock_description_(std::make_unique<AllAppsLockDescription>()), - app_id_(app_id), - callback_(std::move(callback)), - profile_(profile) { - // Initializing data for uninstallation tracking. - queued_uninstalls_.emplace_back(app_id_, management_type_or_all, - uninstall_source); - - webapps::InstallableMetrics::TrackUninstallEvent(uninstall_source); + job_(std::move(job)), + callback_(std::move(callback)) { + webapps::InstallableMetrics::TrackUninstallEvent(job_->uninstall_source()); } WebAppUninstallCommand::~WebAppUninstallCommand() = default; void WebAppUninstallCommand::StartWithLock(std::unique_ptr<AllAppsLock> lock) { lock_ = std::move(lock); - - while (!queued_uninstalls_.empty()) { - DCHECK(!all_uninstalled_queued_); - const UninstallInfo current_uninstall = - std::move(queued_uninstalls_.back()); - queued_uninstalls_.pop_back(); - AppendUninstallInfoToDebugLog(current_uninstall); - - const AppId& app_id = current_uninstall.app_id; - const WebApp* app = lock_->registrar().GetAppById(app_id); - if (!app) { - uninstall_results_[app_id] = - webapps::UninstallResultCode::kNoAppToUninstall; - AppendUninstallResultsToDebugLog(app_id); - continue; - } - - // This contains the external uninstall logic. - if (current_uninstall.management_type_or_all.has_value()) { - const WebAppManagement::Type source = - current_uninstall.management_type_or_all.value(); - // If there is more than a single source, then we can just remove the - // source from the web_app DB. Else we end up calling Uninstall() at the - // end. - if (!app->HasOnlySource(source)) { - // There is a chance that removed source type is NOT user uninstallable - // but the remaining source (after removal) types are user - // uninstallable. In this case, the following call will register os - // uninstallation. - apps_pending_uninstall_[app_id] = nullptr; - MaybeRegisterOsUninstall( - app, source, lock_->os_integration_manager(), - base::BindOnce(&WebAppUninstallCommand:: - RemoveManagementTypeAfterOsUninstallRegistration, - weak_factory_.GetWeakPtr(), app_id, source, - current_uninstall.uninstall_source)); - } else { - Uninstall(app_id, current_uninstall.uninstall_source); - } - } else { - // This contains the user uninstall and sync uninstall logic. - DCHECK( - CanUninstallAllManagementSources(current_uninstall.uninstall_source)); - // The following DCHECK streamlines the user uninstall and sync uninstall - // flow, because for sync uninstalls, the web_app source is removed before - // being synced, so the first condition fails by the time an Uninstall is - // invoked. - DCHECK(app->CanUserUninstallWebApp() || - current_uninstall.uninstall_source == - webapps::WebappUninstallSource::kSync); - if (app->IsPreinstalledApp()) { - // Update the default uninstalled web_app prefs if it is a preinstalled - // app but being removed by user. - const WebApp::ExternalConfigMap& config_map = - app->management_to_external_config_map(); - auto it = config_map.find(WebAppManagement::kDefault); - if (it != config_map.end()) { - UserUninstalledPreinstalledWebAppPrefs(profile_->GetPrefs()) - .Add(app_id, it->second.install_urls); - } else { - base::UmaHistogramBoolean( - "WebApp.Preinstalled.ExternalConfigMapAbsentDuringUninstall", - true); - } - } - Uninstall(app_id, current_uninstall.uninstall_source); - } - } - all_uninstalled_queued_ = true; - MaybeFinishUninstallAndDestruct(); + job_->Start(*lock_, + base::BindOnce(&WebAppUninstallCommand::CompleteAndSelfDestruct, + weak_factory_.GetWeakPtr())); } void WebAppUninstallCommand::OnShutdown() { - Abort(webapps::UninstallResultCode::kError); - return; + CompleteAndSelfDestruct(webapps::UninstallResultCode::kShutdown); } const LockDescription& WebAppUninstallCommand::lock_description() const { @@ -153,122 +45,28 @@ } base::Value WebAppUninstallCommand::ToDebugValue() const { - base::Value::Dict uninstall_info; - uninstall_info.Set("command_data", debug_log_.Clone()); - return base::Value(std::move(uninstall_info)); + return job_->ToDebugValue(); } -WebAppUninstallCommand::UninstallInfo::UninstallInfo( - AppId app_id, - absl::optional<WebAppManagement::Type> management_type_or_all, - webapps::WebappUninstallSource uninstall_source) - : app_id(app_id), - management_type_or_all(management_type_or_all), - uninstall_source(uninstall_source) {} - -WebAppUninstallCommand::UninstallInfo::~UninstallInfo() = default; - -WebAppUninstallCommand::UninstallInfo::UninstallInfo( - const UninstallInfo& uninstall_info) = default; - -WebAppUninstallCommand::UninstallInfo::UninstallInfo( - UninstallInfo&& uninstall_info) = default; - -void WebAppUninstallCommand::AppendUninstallInfoToDebugLog( - const UninstallInfo& uninstall_info) { - base::Value::Dict source_info; - if (uninstall_info.management_type_or_all.has_value()) { - source_info.Set( - "management_type", - base::ToString(uninstall_info.management_type_or_all.value())); - } - source_info.Set("uninstall_source", ConvertUninstallSourceToStringType( - uninstall_info.uninstall_source)); - debug_log_.Set(uninstall_info.app_id, base::Value(std::move(source_info))); -} - -void WebAppUninstallCommand::AppendUninstallResultsToDebugLog( - const AppId& app_id) { - base::Value::Dict* app_dict = debug_log_.FindDict(app_id); - DCHECK(app_dict); - app_dict->Set("uninstall_result", webapps::ConvertUninstallResultCodeToString( - uninstall_results_[app_id])); -} - -void WebAppUninstallCommand::Abort(webapps::UninstallResultCode code) { +void WebAppUninstallCommand::CompleteAndSelfDestruct( + webapps::UninstallResultCode code) { + CHECK(callback_); base::UmaHistogramBoolean("WebApp.Uninstall.Result", - (code == webapps::UninstallResultCode::kSuccess)); - if (!callback_) - return; - SignalCompletionAndSelfDestruct(CommandResult::kFailure, - base::BindOnce(std::move(callback_), code)); -} - -void WebAppUninstallCommand::Uninstall( - const AppId& app_id, - webapps::WebappUninstallSource uninstall_source) { - QueueSubAppsForUninstallIfAny(app_id); - apps_pending_uninstall_[app_id] = RemoveWebAppJob::Start( - uninstall_source, app_id, *lock_, profile_.get(), - base::BindOnce(&WebAppUninstallCommand::OnSingleUninstallComplete, - weak_factory_.GetWeakPtr(), app_id, uninstall_source)); -} - -void WebAppUninstallCommand::QueueSubAppsForUninstallIfAny( - const AppId& app_id) { - std::vector<AppId> sub_app_ids = lock_->registrar().GetAllSubAppIds(app_id); - for (const AppId& sub_app_id : sub_app_ids) { - queued_uninstalls_.emplace_back( - sub_app_id, WebAppManagement::kSubApp, - webapps::WebappUninstallSource::kParentUninstall); - } -} - -void WebAppUninstallCommand::RemoveManagementTypeAfterOsUninstallRegistration( - const AppId& app_id, - const WebAppManagement::Type& management_type, - webapps::WebappUninstallSource uninstall_source, - OsHooksErrors os_hooks_errors) { - { - ScopedRegistryUpdate update(&lock_->sync_bridge()); - WebApp* app_to_update = update->UpdateApp(app_id); - app_to_update->RemoveSource(management_type); - if (management_type == WebAppManagement::kSubApp) { - app_to_update->SetParentAppId(absl::nullopt); - } - } - - lock_->install_manager().NotifyWebAppSourceRemoved(app_id); - - // Registering an OS uninstall is also an "uninstall", so the - // state is updated for the command. - OnSingleUninstallComplete(app_id, uninstall_source, - /*success=*/true); -} - -void WebAppUninstallCommand::OnSingleUninstallComplete( - const AppId& app_id, - webapps::WebappUninstallSource source, - bool success) { - DCHECK(base::Contains(apps_pending_uninstall_, app_id)); - apps_pending_uninstall_.erase(app_id); - - if (source == webapps::WebappUninstallSource::kSync) { - base::UmaHistogramBoolean("Webapp.SyncInitiatedUninstallResult", success); - } - uninstall_results_[app_id] = success ? webapps::UninstallResultCode::kSuccess - : webapps::UninstallResultCode::kError; - AppendUninstallResultsToDebugLog(app_id); - MaybeFinishUninstallAndDestruct(); -} - -void WebAppUninstallCommand::MaybeFinishUninstallAndDestruct() { - if (apps_pending_uninstall_.empty() && all_uninstalled_queued_) { - // All uninstall jobs have finished. - SignalCompletionAndSelfDestruct( - CommandResult::kSuccess, - base::BindOnce(std::move(callback_), uninstall_results_[app_id_])); - } + UninstallSucceeded(code)); + SignalCompletionAndSelfDestruct( + [code]() { + switch (code) { + case webapps::UninstallResultCode::kSuccess: + case webapps::UninstallResultCode::kNoAppToUninstall: + return CommandResult::kSuccess; + case webapps::UninstallResultCode::kCancelled: + case webapps::UninstallResultCode::kError: + return CommandResult::kFailure; + case webapps::UninstallResultCode::kShutdown: + return CommandResult::kShutdown; + } + }(), + base::BindOnce(std::move(callback_), code)); } } // namespace web_app
diff --git a/chrome/browser/web_applications/commands/web_app_uninstall_command.h b/chrome/browser/web_applications/commands/web_app_uninstall_command.h index c11d8f5..1fca1933 100644 --- a/chrome/browser/web_applications/commands/web_app_uninstall_command.h +++ b/chrome/browser/web_applications/commands/web_app_uninstall_command.h
@@ -7,24 +7,13 @@ #include <memory> -#include "base/containers/circular_deque.h" -#include "base/containers/flat_map.h" -#include "base/functional/callback_forward.h" -#include "base/memory/raw_ptr.h" #include "base/memory/weak_ptr.h" #include "base/values.h" #include "chrome/browser/web_applications/commands/web_app_command.h" -#include "chrome/browser/web_applications/os_integration/os_integration_manager.h" -#include "chrome/browser/web_applications/web_app_id.h" -#include "components/webapps/browser/installable/installable_metrics.h" -#include "components/webapps/browser/uninstall_result_code.h" -#include "third_party/abseil-cpp/absl/types/optional.h" - -class Profile; +#include "chrome/browser/web_applications/uninstall/uninstall_job.h" namespace webapps { enum class UninstallResultCode; -enum class WebappUninstallSource; } // namespace webapps namespace web_app { @@ -32,45 +21,13 @@ class AllAppsLock; class AllAppsLockDescription; class LockDescription; -class RemoveWebAppJob; -// This command is used to uninstall a web_app. Once started, this command will: -// 1. Start maintaining a queue of all app_ids that need to be uninstalled. -// 2. For each app_id: -// a. If an app was triggered by an external install source (like policy, -// default or system) and was installed by multiple sources, it will -// remove the source that triggered the uninstallation. Sometimes doing so -// might change the behavior of an app from being user uninstallable to not -// being user uninstallable in which case, OS integration for user -// uninstallation is unregistered. -// b. If an app uninstallation was triggered by any other source and if the -// app was a default app, the app_id is stored in the -// UserUninstalledPreinstalledWebAppPrefs so that the -// ExternallyManagedAppManager does not auto synchronize and reinstall the -// default app on next step. See -// `ExternallyManagedAppManager::SynchronizeInstalledApps()` for more info. -// c. If the app being uninstalled is a parent app with multiple sub apps, -// all sub app IDs are queued onto the overall uninstallation queue. -// 3. For all other use-cases, a RemoveWebAppJob is initialized and kicked -// off per app_id. The job is owned by the command, and the command keeps -// track of all currently running jobs. -// 4. The command ends only when both of the conditions below are successful: -// a. All running RemoveWebAppJobs have been completed. -// b. The queue that was keeping track of app_ids that needed to be -// uninstalled is empty. +// This command acquires the AllAppsLock needed by three uninstall related jobs: +// `RemoveInstallUrlJob`, `RemoveInstallSourceJob`, and `RemoveWebAppJob`. class WebAppUninstallCommand : public WebAppCommandTemplate<AllAppsLock> { public: - using UninstallWebAppCallback = - base::OnceCallback<void(webapps::UninstallResultCode)>; - using RemoveManagementTypeCallback = - base::RepeatingCallback<void(const AppId& app_id)>; - - WebAppUninstallCommand( - const AppId& app_id, - absl::optional<WebAppManagement::Type> management_type_or_all, - webapps::WebappUninstallSource uninstall_source, - UninstallWebAppCallback callback, - Profile& profile); + WebAppUninstallCommand(std::unique_ptr<UninstallJob> job, + UninstallJob::Callback callback); ~WebAppUninstallCommand() override; // WebAppCommandTemplate<AllAppsLock>: @@ -80,53 +37,13 @@ base::Value ToDebugValue() const override; private: - // Used to store information needed for uninstalling an app with app_id. - struct UninstallInfo { - UninstallInfo(AppId app_id, - absl::optional<WebAppManagement::Type> management_type_or_all, - webapps::WebappUninstallSource uninstall_source); - ~UninstallInfo(); - UninstallInfo(const UninstallInfo& uninstall_info); - UninstallInfo(UninstallInfo&& uninstall_info); - UninstallInfo& operator=(const UninstallInfo& uninstall_info) = delete; - UninstallInfo& operator=(UninstallInfo&& uninstall_info) = delete; - - AppId app_id; - absl::optional<WebAppManagement::Type> management_type_or_all; - webapps::WebappUninstallSource uninstall_source; - }; - - void AppendUninstallInfoToDebugLog(const UninstallInfo& uninstall_info); - void AppendUninstallResultsToDebugLog(const AppId& app_id); - void Abort(webapps::UninstallResultCode code); - void Uninstall(const AppId& app_id, - webapps::WebappUninstallSource uninstall_source); - void QueueSubAppsForUninstallIfAny(const AppId& app_id); - void RemoveManagementTypeAfterOsUninstallRegistration( - const AppId& app_id, - const WebAppManagement::Type& install_source, - webapps::WebappUninstallSource uninstall_source, - OsHooksErrors os_hooks_errors); - void OnSingleUninstallComplete(const AppId& app_id, - webapps::WebappUninstallSource source, - bool success); - void MaybeFinishUninstallAndDestruct(); + void CompleteAndSelfDestruct(webapps::UninstallResultCode code); std::unique_ptr<AllAppsLockDescription> lock_description_; std::unique_ptr<AllAppsLock> lock_; - const AppId app_id_; - base::circular_deque<UninstallInfo> queued_uninstalls_; - base::flat_map<AppId, webapps::UninstallResultCode> uninstall_results_; - base::flat_map<AppId, std::unique_ptr<RemoveWebAppJob>> - apps_pending_uninstall_; - base::Value::Dict debug_log_; - bool all_uninstalled_queued_ = false; - - UninstallWebAppCallback callback_; - - // `this` is owned by `profile_`. - raw_ref<Profile> profile_; + std::unique_ptr<UninstallJob> job_; + UninstallJob::Callback callback_; base::WeakPtrFactory<WebAppUninstallCommand> weak_factory_{this}; };
diff --git a/chrome/browser/web_applications/commands/web_app_uninstall_command_unittest.cc b/chrome/browser/web_applications/commands/web_app_uninstall_command_unittest.cc index 04fc5f8..c934966 100644 --- a/chrome/browser/web_applications/commands/web_app_uninstall_command_unittest.cc +++ b/chrome/browser/web_applications/commands/web_app_uninstall_command_unittest.cc
@@ -21,6 +21,9 @@ #include "chrome/browser/web_applications/test/web_app_test.h" #include "chrome/browser/web_applications/test/web_app_test_observers.h" #include "chrome/browser/web_applications/test/web_app_test_utils.h" +#include "chrome/browser/web_applications/uninstall/remove_install_source_job.h" +#include "chrome/browser/web_applications/uninstall/remove_install_url_job.h" +#include "chrome/browser/web_applications/uninstall/remove_web_app_job.h" #include "chrome/browser/web_applications/user_uninstalled_preinstalled_web_app_prefs.h" #include "chrome/browser/web_applications/web_app.h" #include "chrome/browser/web_applications/web_app_command_manager.h" @@ -101,12 +104,12 @@ base::RunLoop loop; provider()->command_manager().ScheduleCommand( std::make_unique<WebAppUninstallCommand>( - app_id, absl::nullopt, webapps::WebappUninstallSource::kAppMenu, + std::make_unique<RemoveWebAppJob>( + webapps::WebappUninstallSource::kAppMenu, *profile(), app_id), base::BindLambdaForTesting([&](webapps::UninstallResultCode code) { EXPECT_EQ(webapps::UninstallResultCode::kSuccess, code); loop.Quit(); - }), - *profile())); + }))); loop.Run(); EXPECT_EQ(provider()->registrar_unsafe().GetAppById(app_id), nullptr); @@ -137,13 +140,13 @@ base::RunLoop loop; provider()->command_manager().ScheduleCommand( std::make_unique<WebAppUninstallCommand>( - app_id, WebAppManagement::kDefault, - webapps::WebappUninstallSource::kAppMenu, + std::make_unique<RemoveInstallSourceJob>( + webapps::WebappUninstallSource::kAppMenu, *profile(), app_id, + WebAppManagement::kDefault), base::BindLambdaForTesting([&](webapps::UninstallResultCode code) { EXPECT_EQ(webapps::UninstallResultCode::kSuccess, code); loop.Quit(); - }), - *profile())); + }))); loop.Run(); EXPECT_EQ(provider()->registrar_unsafe().GetAppById(app_id), nullptr); @@ -174,12 +177,12 @@ base::RunLoop loop; provider()->command_manager().ScheduleCommand( std::make_unique<WebAppUninstallCommand>( - app_id, absl::nullopt, webapps::WebappUninstallSource::kAppMenu, + std::make_unique<RemoveWebAppJob>( + webapps::WebappUninstallSource::kAppMenu, *profile(), app_id), base::BindLambdaForTesting([&](webapps::UninstallResultCode code) { EXPECT_EQ(webapps::UninstallResultCode::kError, code); loop.Quit(); - }), - *profile())); + }))); loop.Run(); EXPECT_EQ(provider()->registrar_unsafe().GetAppById(app_id), nullptr); @@ -211,12 +214,12 @@ base::RunLoop loop; provider()->command_manager().ScheduleCommand( std::make_unique<WebAppUninstallCommand>( - app_id, absl::nullopt, webapps::WebappUninstallSource::kAppMenu, + std::make_unique<RemoveWebAppJob>( + webapps::WebappUninstallSource::kAppMenu, *profile(), app_id), base::BindLambdaForTesting([&](webapps::UninstallResultCode code) { EXPECT_EQ(webapps::UninstallResultCode::kError, code); loop.Quit(); - }), - *profile())); + }))); loop.Run(); EXPECT_EQ(provider()->registrar_unsafe().GetAppById(app_id), nullptr); @@ -242,12 +245,12 @@ base::RunLoop loop; provider()->command_manager().ScheduleCommand( std::make_unique<WebAppUninstallCommand>( - app_id, absl::nullopt, webapps::WebappUninstallSource::kAppMenu, + std::make_unique<RemoveWebAppJob>( + webapps::WebappUninstallSource::kAppMenu, *profile(), app_id), base::BindLambdaForTesting([&](webapps::UninstallResultCode code) { EXPECT_EQ(webapps::UninstallResultCode::kNoAppToUninstall, code); loop.Quit(); - }), - *profile())); + }))); loop.Run(); EXPECT_EQ(provider()->registrar_unsafe().GetAppById(app_id), nullptr); @@ -276,11 +279,11 @@ provider()->command_manager().ScheduleCommand( std::make_unique<WebAppUninstallCommand>( - app_id, absl::nullopt, webapps::WebappUninstallSource::kAppMenu, + std::make_unique<RemoveWebAppJob>( + webapps::WebappUninstallSource::kAppMenu, *profile(), app_id), base::BindLambdaForTesting([&](webapps::UninstallResultCode code) { EXPECT_EQ(webapps::UninstallResultCode::kError, code); - }), - *profile())); + }))); provider()->command_manager().Shutdown(); // App is not uninstalled. @@ -316,12 +319,12 @@ base::RunLoop loop; provider()->command_manager().ScheduleCommand( std::make_unique<WebAppUninstallCommand>( - app_id, absl::nullopt, webapps::WebappUninstallSource::kAppMenu, + std::make_unique<RemoveWebAppJob>( + webapps::WebappUninstallSource::kAppMenu, *profile(), app_id), base::BindLambdaForTesting([&](webapps::UninstallResultCode code) { EXPECT_EQ(webapps::UninstallResultCode::kSuccess, code); loop.Quit(); - }), - *profile())); + }))); loop.Run(); EXPECT_EQ(provider()->registrar_unsafe().GetAppById(app_id), nullptr); @@ -354,12 +357,12 @@ base::RunLoop loop; provider()->command_manager().ScheduleCommand( std::make_unique<WebAppUninstallCommand>( - app_id, absl::nullopt, webapps::WebappUninstallSource::kAppMenu, + std::make_unique<RemoveWebAppJob>( + webapps::WebappUninstallSource::kAppMenu, *profile(), app_id), base::BindLambdaForTesting([&](webapps::UninstallResultCode code) { EXPECT_EQ(webapps::UninstallResultCode::kSuccess, code); loop.Quit(); - }), - *profile())); + }))); loop.Run(); EXPECT_EQ(provider()->registrar_unsafe().GetAppById(app_id), nullptr); @@ -417,13 +420,13 @@ base::RunLoop run_loop; auto command = std::make_unique<WebAppUninstallCommand>( - app_id, WebAppManagement::kPolicy, - webapps::WebappUninstallSource::kExternalPolicy, + std::make_unique<RemoveInstallSourceJob>( + webapps::WebappUninstallSource::kExternalPolicy, *profile(), app_id, + WebAppManagement::kPolicy), base::BindLambdaForTesting([&](webapps::UninstallResultCode code) { EXPECT_EQ(webapps::UninstallResultCode::kSuccess, code); run_loop.Quit(); - }), - *profile()); + })); WebAppInstallManagerObserverAdapter observer(profile()); observer.SetWebAppSourceRemovedDelegate( @@ -479,12 +482,12 @@ base::RunLoop loop; provider()->command_manager().ScheduleCommand( std::make_unique<WebAppUninstallCommand>( - app_id, absl::nullopt, GetParam().source, + std::make_unique<RemoveWebAppJob>(GetParam().source, *profile(), + app_id), base::BindLambdaForTesting([&](webapps::UninstallResultCode code) { EXPECT_EQ(webapps::UninstallResultCode::kSuccess, code); loop.Quit(); - }), - *profile())); + }))); loop.Run(); EXPECT_EQ(provider()->registrar_unsafe().GetAppById(app_id), nullptr);
diff --git a/chrome/browser/web_applications/extensions/externally_managed_app_install_task_unittest.cc b/chrome/browser/web_applications/extensions/externally_managed_app_install_task_unittest.cc index 32098093..40f17dd5 100644 --- a/chrome/browser/web_applications/extensions/externally_managed_app_install_task_unittest.cc +++ b/chrome/browser/web_applications/extensions/externally_managed_app_install_task_unittest.cc
@@ -4,55 +4,55 @@ #include "chrome/browser/web_applications/externally_managed_app_install_task.h" +#include <stddef.h> +#include <initializer_list> #include <map> #include <memory> #include <string> +#include <tuple> +#include <type_traits> #include <utility> #include <vector> +#include "base/check.h" #include "base/check_op.h" #include "base/containers/contains.h" -#include "base/containers/flat_set.h" #include "base/functional/bind.h" #include "base/functional/callback.h" #include "base/functional/callback_helpers.h" +#include "base/location.h" #include "base/memory/raw_ptr.h" +#include "base/memory/scoped_refptr.h" #include "base/notreached.h" #include "base/run_loop.h" +#include "base/strings/string_piece_forward.h" #include "base/strings/utf_string_conversions.h" #include "base/task/single_thread_task_runner.h" #include "base/test/bind.h" -#include "base/test/scoped_feature_list.h" -#include "build/chromeos_buildflags.h" -#include "chrome/browser/web_applications/mojom/user_display_mode.mojom.h" +#include "base/test/test_future.h" +#include "chrome/browser/web_applications/mojom/user_display_mode.mojom-shared.h" +#include "chrome/browser/web_applications/os_integration/os_integration_manager.h" #include "chrome/browser/web_applications/test/fake_data_retriever.h" #include "chrome/browser/web_applications/test/fake_install_finalizer.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/fake_web_app_ui_manager.h" #include "chrome/browser/web_applications/test/test_web_app_url_loader.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.h" -#include "chrome/browser/web_applications/web_app_command_scheduler.h" #include "chrome/browser/web_applications/web_app_helpers.h" #include "chrome/browser/web_applications/web_app_id.h" #include "chrome/browser/web_applications/web_app_install_finalizer.h" #include "chrome/browser/web_applications/web_app_install_info.h" -#include "chrome/browser/web_applications/web_app_provider.h" #include "chrome/browser/web_applications/web_app_registrar.h" -#include "chrome/browser/web_applications/web_app_sync_bridge.h" #include "chrome/browser/web_applications/web_contents/web_app_data_retriever.h" -#include "chrome/common/chrome_features.h" -#include "chrome/common/pref_names.h" #include "chrome/test/base/chrome_render_view_host_test_harness.h" #include "chrome/test/base/testing_profile.h" -#include "components/prefs/pref_service.h" #include "components/webapps/browser/install_result_code.h" #include "components/webapps/browser/installable/installable_logging.h" #include "components/webapps/browser/installable/installable_metrics.h" #include "components/webapps/browser/uninstall_result_code.h" -#include "content/public/test/test_utils.h" +#include "mojo/public/cpp/bindings/struct_ptr.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/blink/public/mojom/manifest/manifest.mojom.h" @@ -372,33 +372,24 @@ url_loader().SetNextLoadUrlResult(kWebAppUrl, WebAppUrlLoader::Result::kUrlLoaded); - base::RunLoop run_loop; + base::test::TestFuture<ExternallyManagedAppManager::InstallResult> future; + task->Install(web_contents(), future.GetCallback()); + const auto& result = future.Get(); - task->Install(web_contents(), - base::BindLambdaForTesting( - [&](ExternallyManagedAppManager::InstallResult result) { - absl::optional<AppId> id = - registrar()->LookupExternalAppId(kWebAppUrl); + absl::optional<AppId> id = registrar()->LookupExternalAppId(kWebAppUrl); - EXPECT_EQ(webapps::InstallResultCode::kSuccessNewInstall, - result.code); - EXPECT_TRUE(result.app_id.has_value()); + EXPECT_EQ(webapps::InstallResultCode::kSuccessNewInstall, result.code); + EXPECT_TRUE(result.app_id.has_value()); - EXPECT_FALSE(IsPlaceholderApp(kWebAppUrl)); + EXPECT_FALSE(IsPlaceholderApp(kWebAppUrl)); - EXPECT_EQ(result.app_id.value(), id.value()); + EXPECT_EQ(result.app_id.value(), id.value()); - EXPECT_EQ(0u, finalizer()->num_reparent_tab_calls()); + EXPECT_EQ(0u, finalizer()->num_reparent_tab_calls()); - EXPECT_EQ(web_app_info().user_display_mode, - mojom::UserDisplayMode::kBrowser); - EXPECT_EQ(webapps::WebappInstallSource::INTERNAL_DEFAULT, - finalize_options().install_surface); - - run_loop.Quit(); - })); - - run_loop.Run(); + EXPECT_EQ(web_app_info().user_display_mode, mojom::UserDisplayMode::kBrowser); + EXPECT_EQ(webapps::WebappInstallSource::INTERNAL_DEFAULT, + finalize_options().install_surface); } TEST_F(ExternallyManagedAppInstallTaskTest, InstallFails) { @@ -412,25 +403,17 @@ url_loader().SetNextLoadUrlResult(kWebAppUrl, WebAppUrlLoader::Result::kUrlLoaded); - base::RunLoop run_loop; + base::test::TestFuture<ExternallyManagedAppManager::InstallResult> future; + task->Install(web_contents(), future.GetCallback()); + const auto& result = future.Get(); - task->Install( - web_contents(), - base::BindLambdaForTesting( - [&](ExternallyManagedAppManager::InstallResult result) { - absl::optional<AppId> id = - registrar()->LookupExternalAppId(kWebAppUrl); + absl::optional<AppId> id = registrar()->LookupExternalAppId(kWebAppUrl); - EXPECT_EQ(webapps::InstallResultCode::kGetWebAppInstallInfoFailed, - result.code); - EXPECT_FALSE(result.app_id.has_value()); + EXPECT_EQ(webapps::InstallResultCode::kGetWebAppInstallInfoFailed, + result.code); + EXPECT_FALSE(result.app_id.has_value()); - EXPECT_FALSE(id.has_value()); - - run_loop.Quit(); - })); - - run_loop.Run(); + EXPECT_FALSE(id.has_value()); } TEST_F(ExternallyManagedAppInstallTaskTest, InstallForcedContainerWindow) { @@ -444,19 +427,14 @@ url_loader().SetNextLoadUrlResult(kWebAppUrl, WebAppUrlLoader::Result::kUrlLoaded); - base::RunLoop run_loop; - task->Install(web_contents(), - base::BindLambdaForTesting( - [&](ExternallyManagedAppManager::InstallResult result) { - EXPECT_EQ(webapps::InstallResultCode::kSuccessNewInstall, - result.code); - EXPECT_TRUE(result.app_id.has_value()); - EXPECT_EQ(web_app_info().user_display_mode, - mojom::UserDisplayMode::kStandalone); - run_loop.Quit(); - })); + base::test::TestFuture<ExternallyManagedAppManager::InstallResult> future; + task->Install(web_contents(), future.GetCallback()); + const auto& result = future.Get(); - run_loop.Run(); + EXPECT_EQ(webapps::InstallResultCode::kSuccessNewInstall, result.code); + EXPECT_TRUE(result.app_id.has_value()); + EXPECT_EQ(web_app_info().user_display_mode, + mojom::UserDisplayMode::kStandalone); } TEST_F(ExternallyManagedAppInstallTaskTest, InstallForcedContainerTab) { @@ -470,19 +448,13 @@ url_loader().SetNextLoadUrlResult(kWebAppUrl, WebAppUrlLoader::Result::kUrlLoaded); - base::RunLoop run_loop; - task->Install(web_contents(), - base::BindLambdaForTesting( - [&](ExternallyManagedAppManager::InstallResult result) { - EXPECT_EQ(webapps::InstallResultCode::kSuccessNewInstall, - result.code); - EXPECT_TRUE(result.app_id.has_value()); - EXPECT_EQ(web_app_info().user_display_mode, - mojom::UserDisplayMode::kBrowser); - run_loop.Quit(); - })); + base::test::TestFuture<ExternallyManagedAppManager::InstallResult> future; + task->Install(web_contents(), future.GetCallback()); + const auto& result = future.Get(); - run_loop.Run(); + EXPECT_EQ(webapps::InstallResultCode::kSuccessNewInstall, result.code); + EXPECT_TRUE(result.app_id.has_value()); + EXPECT_EQ(web_app_info().user_display_mode, mojom::UserDisplayMode::kBrowser); } TEST_F(ExternallyManagedAppInstallTaskTest, InstallPreinstalledApp) { @@ -495,20 +467,15 @@ url_loader().SetNextLoadUrlResult(kWebAppUrl, WebAppUrlLoader::Result::kUrlLoaded); - base::RunLoop run_loop; - task->Install(web_contents(), - base::BindLambdaForTesting( - [&](ExternallyManagedAppManager::InstallResult result) { - EXPECT_EQ(webapps::InstallResultCode::kSuccessNewInstall, - result.code); - EXPECT_TRUE(result.app_id.has_value()); + base::test::TestFuture<ExternallyManagedAppManager::InstallResult> future; + task->Install(web_contents(), future.GetCallback()); + const auto& result = future.Get(); - EXPECT_EQ(webapps::WebappInstallSource::INTERNAL_DEFAULT, - finalize_options().install_surface); - run_loop.Quit(); - })); + EXPECT_EQ(webapps::InstallResultCode::kSuccessNewInstall, result.code); + EXPECT_TRUE(result.app_id.has_value()); - run_loop.Run(); + EXPECT_EQ(webapps::WebappInstallSource::INTERNAL_DEFAULT, + finalize_options().install_surface); } TEST_F(ExternallyManagedAppInstallTaskTest, InstallAppFromPolicy) { @@ -521,20 +488,15 @@ url_loader().SetNextLoadUrlResult(kWebAppUrl, WebAppUrlLoader::Result::kUrlLoaded); - base::RunLoop run_loop; - task->Install(web_contents(), - base::BindLambdaForTesting( - [&](ExternallyManagedAppManager::InstallResult result) { - EXPECT_EQ(webapps::InstallResultCode::kSuccessNewInstall, - result.code); - EXPECT_TRUE(result.app_id.has_value()); + base::test::TestFuture<ExternallyManagedAppManager::InstallResult> future; + task->Install(web_contents(), future.GetCallback()); + const auto& result = future.Get(); - EXPECT_EQ(webapps::WebappInstallSource::EXTERNAL_POLICY, - finalize_options().install_surface); - run_loop.Quit(); - })); + EXPECT_EQ(webapps::InstallResultCode::kSuccessNewInstall, result.code); + EXPECT_TRUE(result.app_id.has_value()); - run_loop.Run(); + EXPECT_EQ(webapps::WebappInstallSource::EXTERNAL_POLICY, + finalize_options().install_surface); } TEST_F(ExternallyManagedAppInstallTaskTest, InstallPlaceholder) { @@ -548,33 +510,27 @@ url_loader().SetNextLoadUrlResult( kWebAppUrl, WebAppUrlLoader::Result::kRedirectedUrlLoaded); - base::RunLoop run_loop; - task->Install( - web_contents(), - base::BindLambdaForTesting( - [&](ExternallyManagedAppManager::InstallResult result) { - EXPECT_EQ(webapps::InstallResultCode::kSuccessNewInstall, - result.code); - EXPECT_TRUE(result.app_id.has_value()); + base::test::TestFuture<ExternallyManagedAppManager::InstallResult> future; + task->Install(web_contents(), future.GetCallback()); + const auto& result = future.Get(); - EXPECT_TRUE(IsPlaceholderApp(kWebAppUrl)); + EXPECT_EQ(webapps::InstallResultCode::kSuccessNewInstall, result.code); + EXPECT_TRUE(result.app_id.has_value()); - EXPECT_EQ(1u, finalizer()->finalize_options_list().size()); - EXPECT_EQ(webapps::WebappInstallSource::EXTERNAL_POLICY, - finalize_options().install_surface); - const WebAppInstallInfo& web_app_info = - finalizer()->web_app_info_list().at(0); + EXPECT_TRUE(IsPlaceholderApp(kWebAppUrl)); - EXPECT_EQ(base::UTF8ToUTF16(kWebAppUrl.spec()), web_app_info.title); - EXPECT_EQ(kWebAppUrl, web_app_info.start_url); - EXPECT_EQ(web_app_info.user_display_mode, - mojom::UserDisplayMode::kStandalone); - EXPECT_TRUE(web_app_info.manifest_icons.empty()); - EXPECT_TRUE(web_app_info.icon_bitmaps.any.empty()); + EXPECT_EQ(1u, finalizer()->finalize_options_list().size()); + EXPECT_EQ(webapps::WebappInstallSource::EXTERNAL_POLICY, + finalize_options().install_surface); + const WebAppInstallInfo& web_app_info = + finalizer()->web_app_info_list().at(0); - run_loop.Quit(); - })); - run_loop.Run(); + EXPECT_EQ(base::UTF8ToUTF16(kWebAppUrl.spec()), web_app_info.title); + EXPECT_EQ(kWebAppUrl, web_app_info.start_url); + EXPECT_EQ(web_app_info.user_display_mode, + mojom::UserDisplayMode::kStandalone); + EXPECT_TRUE(web_app_info.manifest_icons.empty()); + EXPECT_TRUE(web_app_info.icon_bitmaps.any.empty()); } TEST_F(ExternallyManagedAppInstallTaskTest, InstallPlaceholderTwice) { @@ -592,19 +548,14 @@ url_loader().SetNextLoadUrlResult( kWebAppUrl, WebAppUrlLoader::Result::kRedirectedUrlLoaded); - base::RunLoop run_loop; - task->Install( - web_contents(), - base::BindLambdaForTesting( - [&](ExternallyManagedAppManager::InstallResult result) { - EXPECT_EQ(webapps::InstallResultCode::kSuccessNewInstall, - result.code); - placeholder_app_id = result.app_id.value(); + base::test::TestFuture<ExternallyManagedAppManager::InstallResult> future; + task->Install(web_contents(), future.GetCallback()); + const auto& result = future.Get(); - EXPECT_EQ(1u, finalizer()->finalize_options_list().size()); - run_loop.Quit(); - })); - run_loop.Run(); + EXPECT_EQ(webapps::InstallResultCode::kSuccessNewInstall, result.code); + placeholder_app_id = result.app_id.value(); + + EXPECT_EQ(1u, finalizer()->finalize_options_list().size()); } // Try to install it again. @@ -613,21 +564,15 @@ url_loader().SetNextLoadUrlResult( kWebAppUrl, WebAppUrlLoader::Result::kRedirectedUrlLoaded); - base::RunLoop run_loop; - task->Install(web_contents(), - base::BindLambdaForTesting( - [&](ExternallyManagedAppManager::InstallResult result) { - EXPECT_EQ(webapps::InstallResultCode::kSuccessNewInstall, - result.code); - EXPECT_EQ(placeholder_app_id, result.app_id.value()); + base::test::TestFuture<ExternallyManagedAppManager::InstallResult> future; + task->Install(web_contents(), future.GetCallback()); + const auto& result = future.Get(); - // There shouldn't be a second call to the finalizer. - EXPECT_EQ(1u, - finalizer()->finalize_options_list().size()); + EXPECT_EQ(webapps::InstallResultCode::kSuccessNewInstall, result.code); + EXPECT_EQ(placeholder_app_id, result.app_id.value()); - run_loop.Quit(); - })); - run_loop.Run(); + // There shouldn't be a second call to the finalizer. + EXPECT_EQ(1u, finalizer()->finalize_options_list().size()); } TEST_F(ExternallyManagedAppInstallTaskTest, ReinstallPlaceholderSucceeds) { @@ -645,19 +590,14 @@ url_loader().SetNextLoadUrlResult( kWebAppUrl, WebAppUrlLoader::Result::kRedirectedUrlLoaded); - base::RunLoop run_loop; - task->Install( - web_contents(), - base::BindLambdaForTesting( - [&](ExternallyManagedAppManager::InstallResult result) { - EXPECT_EQ(webapps::InstallResultCode::kSuccessNewInstall, - result.code); - placeholder_app_id = result.app_id.value(); + base::test::TestFuture<ExternallyManagedAppManager::InstallResult> future; + task->Install(web_contents(), future.GetCallback()); + const auto& result = future.Get(); - EXPECT_EQ(1u, finalizer()->finalize_options_list().size()); - run_loop.Quit(); - })); - run_loop.Run(); + EXPECT_EQ(webapps::InstallResultCode::kSuccessNewInstall, result.code); + placeholder_app_id = result.app_id.value(); + + EXPECT_EQ(1u, finalizer()->finalize_options_list().size()); } // Replace the placeholder with a real app. @@ -670,24 +610,16 @@ url_loader().SetNextLoadUrlResult(kWebAppUrl, WebAppUrlLoader::Result::kUrlLoaded); - base::RunLoop run_loop; - task->Install( - web_contents(), - base::BindLambdaForTesting( - [&](ExternallyManagedAppManager::InstallResult result) { - EXPECT_EQ(webapps::InstallResultCode::kSuccessNewInstall, - result.code); - EXPECT_TRUE(result.app_id.has_value()); - EXPECT_FALSE(IsPlaceholderApp(kWebAppUrl)); + base::test::TestFuture<ExternallyManagedAppManager::InstallResult> future; + task->Install(web_contents(), future.GetCallback()); + const auto& result = future.Get(); - EXPECT_EQ(1u, - finalizer()->uninstall_external_web_app_urls().size()); - EXPECT_EQ(kWebAppUrl, - finalizer()->uninstall_external_web_app_urls().at(0)); + EXPECT_EQ(webapps::InstallResultCode::kSuccessNewInstall, result.code); + EXPECT_TRUE(result.app_id.has_value()); + EXPECT_FALSE(IsPlaceholderApp(kWebAppUrl)); - run_loop.Quit(); - })); - run_loop.Run(); + EXPECT_EQ(1u, finalizer()->uninstall_external_web_app_urls().size()); + EXPECT_EQ(kWebAppUrl, finalizer()->uninstall_external_web_app_urls().at(0)); } TEST_F(ExternallyManagedAppInstallTaskTest, ReinstallPlaceholderFails) { @@ -705,20 +637,14 @@ url_loader().SetNextLoadUrlResult( kWebAppUrl, WebAppUrlLoader::Result::kRedirectedUrlLoaded); - base::RunLoop run_loop; - task->Install( - web_contents(), - base::BindLambdaForTesting( - [&](ExternallyManagedAppManager::InstallResult result) { - EXPECT_EQ(webapps::InstallResultCode::kSuccessNewInstall, - result.code); - placeholder_app_id = result.app_id.value(); + base::test::TestFuture<ExternallyManagedAppManager::InstallResult> future; + task->Install(web_contents(), future.GetCallback()); + const auto& result = future.Get(); - EXPECT_EQ(1u, finalizer()->finalize_options_list().size()); + EXPECT_EQ(webapps::InstallResultCode::kSuccessNewInstall, result.code); + placeholder_app_id = result.app_id.value(); - run_loop.Quit(); - })); - run_loop.Run(); + EXPECT_EQ(1u, finalizer()->finalize_options_list().size()); } // Replace the placeholder with a real app. @@ -732,27 +658,20 @@ url_loader().SetNextLoadUrlResult(kWebAppUrl, WebAppUrlLoader::Result::kUrlLoaded); - base::RunLoop run_loop; - task->Install( - web_contents(), - base::BindLambdaForTesting( - [&](ExternallyManagedAppManager::InstallResult result) { - EXPECT_EQ(webapps::InstallResultCode::kFailedPlaceholderUninstall, - result.code); - EXPECT_FALSE(result.app_id.has_value()); - EXPECT_TRUE(IsPlaceholderApp(kWebAppUrl)); + base::test::TestFuture<ExternallyManagedAppManager::InstallResult> future; + task->Install(web_contents(), future.GetCallback()); + const auto& result = future.Get(); - EXPECT_EQ(1u, - finalizer()->uninstall_external_web_app_urls().size()); - EXPECT_EQ(kWebAppUrl, - finalizer()->uninstall_external_web_app_urls().at(0)); + EXPECT_EQ(webapps::InstallResultCode::kFailedPlaceholderUninstall, + result.code); + EXPECT_FALSE(result.app_id.has_value()); + EXPECT_TRUE(IsPlaceholderApp(kWebAppUrl)); - // There should have been no new calls to install a placeholder. - EXPECT_EQ(1u, finalizer()->finalize_options_list().size()); + EXPECT_EQ(1u, finalizer()->uninstall_external_web_app_urls().size()); + EXPECT_EQ(kWebAppUrl, finalizer()->uninstall_external_web_app_urls().at(0)); - run_loop.Quit(); - })); - run_loop.Run(); + // There should have been no new calls to install a placeholder. + EXPECT_EQ(1u, finalizer()->finalize_options_list().size()); } #if defined(CHROMEOS) @@ -770,22 +689,16 @@ url_loader().SetNextLoadUrlResult( kWebAppUrl, WebAppUrlLoader::Result::kRedirectedUrlLoaded); - base::RunLoop run_loop; - task->Install(web_contents(), - base::BindLambdaForTesting( - [&](ExternallyManagedAppManager::InstallResult result) { - EXPECT_EQ(webapps::InstallResultCode::kSuccessNewInstall, - result.code); + base::test::TestFuture<ExternallyManagedAppManager::InstallResult> future; + task->Install(web_contents(), future.GetCallback()); + const auto& result = future.Get(); - const WebAppInstallInfo& web_app_info = - finalizer()->web_app_info_list().at(0); + EXPECT_EQ(webapps::InstallResultCode::kSuccessNewInstall, result.code); - EXPECT_EQ(base::UTF8ToUTF16(kCustomName), - web_app_info.title); + const WebAppInstallInfo& web_app_info = + finalizer()->web_app_info_list().at(0); - run_loop.Quit(); - })); - run_loop.Run(); + EXPECT_EQ(base::UTF8ToUTF16(kCustomName), web_app_info.title); } #endif // defined(CHROMEOS) @@ -798,7 +711,6 @@ // Migrate app1 and app2. options.uninstall_and_replace = {"app1", "app2"}; - base::RunLoop run_loop; auto task = GetInstallationTaskWithTestMocks(options); url_loader().AddPrepareForLoadResults( {WebAppUrlLoader::Result::kUrlLoaded, @@ -806,26 +718,19 @@ url_loader().SetNextLoadUrlResult(kWebAppUrl, WebAppUrlLoader::Result::kUrlLoaded); - task->Install( - web_contents(), - base::BindLambdaForTesting( - [&](ExternallyManagedAppManager::InstallResult result) { - app_id = result.app_id.value(); + base::test::TestFuture<ExternallyManagedAppManager::InstallResult> future; + task->Install(web_contents(), future.GetCallback()); + const auto& result = future.Get(); - EXPECT_EQ(webapps::InstallResultCode::kSuccessNewInstall, - result.code); - EXPECT_EQ(result.app_id, - *registrar()->LookupExternalAppId(kWebAppUrl)); + app_id = result.app_id.value(); - run_loop.Quit(); - })); - run_loop.Run(); + EXPECT_EQ(webapps::InstallResultCode::kSuccessNewInstall, result.code); + EXPECT_EQ(result.app_id, *registrar()->LookupExternalAppId(kWebAppUrl)); } { // Migration should run on every install of the app. options.uninstall_and_replace = {"app3"}; - base::RunLoop run_loop; auto task = GetInstallationTaskWithTestMocks(options); url_loader().AddPrepareForLoadResults( {WebAppUrlLoader::Result::kUrlLoaded, @@ -833,17 +738,12 @@ url_loader().SetNextLoadUrlResult(kWebAppUrl, WebAppUrlLoader::Result::kUrlLoaded); - task->Install( - web_contents(), - base::BindLambdaForTesting( - [&](ExternallyManagedAppManager::InstallResult result) { - EXPECT_EQ(webapps::InstallResultCode::kSuccessNewInstall, - result.code); - EXPECT_EQ(app_id, result.app_id.value()); + base::test::TestFuture<ExternallyManagedAppManager::InstallResult> future; + task->Install(web_contents(), future.GetCallback()); + const auto& result = future.Get(); - run_loop.Quit(); - })); - run_loop.Run(); + EXPECT_EQ(webapps::InstallResultCode::kSuccessNewInstall, result.code); + EXPECT_EQ(app_id, result.app_id.value()); } } @@ -859,8 +759,6 @@ webapps::InstallResultCode::kInstallURLLoadTimeOut}}; for (const auto& result_pair : result_pairs) { - base::RunLoop run_loop; - ExternalInstallOptions install_options( GURL(), mojom::UserDisplayMode::kStandalone, ExternalInstallSource::kInternalDefault); @@ -871,15 +769,11 @@ url_loader().SetPrepareForLoadResultLoaded(); url_loader().SetNextLoadUrlResult(GURL(), result_pair.loader_result); - install_task.Install( - web_contents(), - base::BindLambdaForTesting( - [&](ExternallyManagedAppManager::InstallResult result) { - EXPECT_EQ(result.code, result_pair.install_result); - run_loop.Quit(); - })); + base::test::TestFuture<ExternallyManagedAppManager::InstallResult> future; + install_task.Install(web_contents(), future.GetCallback()); + const auto& result = future.Get(); - run_loop.Run(); + EXPECT_EQ(result.code, result_pair.install_result); } } @@ -923,31 +817,25 @@ finalizer()->SetNextFinalizeInstallResult( kWebAppUrl, webapps::InstallResultCode::kSuccessNewInstall); - base::RunLoop run_loop; - task.Install( - /*web_contents=*/nullptr, - base::BindLambdaForTesting( - [&](ExternallyManagedAppManager::InstallResult result) { - absl::optional<AppId> id = - registrar()->LookupExternalAppId(kWebAppUrl); - EXPECT_EQ(webapps::InstallResultCode::kSuccessOfflineOnlyInstall, - result.code); - EXPECT_TRUE(result.app_id.has_value()); + base::test::TestFuture<ExternallyManagedAppManager::InstallResult> future; + task.Install(/*web_contents=*/nullptr, future.GetCallback()); + const auto& result = future.Get(); - EXPECT_FALSE(IsPlaceholderApp(kWebAppUrl)); + absl::optional<AppId> id = registrar()->LookupExternalAppId(kWebAppUrl); + EXPECT_EQ(webapps::InstallResultCode::kSuccessOfflineOnlyInstall, + result.code); + EXPECT_TRUE(result.app_id.has_value()); - EXPECT_EQ(result.app_id.value(), id.value()); + EXPECT_FALSE(IsPlaceholderApp(kWebAppUrl)); - EXPECT_EQ(0u, finalizer()->num_reparent_tab_calls()); + EXPECT_EQ(result.app_id.value(), id.value()); - EXPECT_EQ(web_app_info().user_display_mode, - mojom::UserDisplayMode::kStandalone); - EXPECT_EQ(webapps::WebappInstallSource::SYSTEM_DEFAULT, - finalize_options().install_surface); + EXPECT_EQ(0u, finalizer()->num_reparent_tab_calls()); - run_loop.Quit(); - })); - run_loop.Run(); + EXPECT_EQ(web_app_info().user_display_mode, + mojom::UserDisplayMode::kStandalone); + EXPECT_EQ(webapps::WebappInstallSource::SYSTEM_DEFAULT, + finalize_options().install_surface); } TEST_F(ExternallyManagedAppInstallTaskTest, InstallWithWebAppInfoFails) { @@ -971,24 +859,16 @@ finalizer()->SetNextFinalizeInstallResult( kWebAppUrl, webapps::InstallResultCode::kWriteDataFailed); - base::RunLoop run_loop; + base::test::TestFuture<ExternallyManagedAppManager::InstallResult> future; + task.Install(web_contents(), future.GetCallback()); + const auto& result = future.Get(); - task.Install(web_contents(), - base::BindLambdaForTesting( - [&](ExternallyManagedAppManager::InstallResult result) { - absl::optional<AppId> id = - registrar()->LookupExternalAppId(kWebAppUrl); + absl::optional<AppId> id = registrar()->LookupExternalAppId(kWebAppUrl); - EXPECT_EQ(webapps::InstallResultCode::kWriteDataFailed, - result.code); - EXPECT_FALSE(result.app_id.has_value()); + EXPECT_EQ(webapps::InstallResultCode::kWriteDataFailed, result.code); + EXPECT_FALSE(result.app_id.has_value()); - EXPECT_FALSE(id.has_value()); - - run_loop.Quit(); - })); - - run_loop.Run(); + EXPECT_FALSE(id.has_value()); } } // namespace web_app
diff --git a/chrome/browser/web_applications/externally_managed_app_install_task.h b/chrome/browser/web_applications/externally_managed_app_install_task.h index 01b4b41..a6380965 100644 --- a/chrome/browser/web_applications/externally_managed_app_install_task.h +++ b/chrome/browser/web_applications/externally_managed_app_install_task.h
@@ -5,20 +5,20 @@ #ifndef CHROME_BROWSER_WEB_APPLICATIONS_EXTERNALLY_MANAGED_APP_INSTALL_TASK_H_ #define CHROME_BROWSER_WEB_APPLICATIONS_EXTERNALLY_MANAGED_APP_INSTALL_TASK_H_ +#include <memory> + #include "base/functional/callback.h" -#include "base/functional/callback_helpers.h" #include "base/memory/raw_ptr.h" #include "base/memory/weak_ptr.h" #include "chrome/browser/web_applications/external_install_options.h" #include "chrome/browser/web_applications/externally_managed_app_manager.h" -#include "chrome/browser/web_applications/os_integration/os_integration_manager.h" +#include "chrome/browser/web_applications/web_app_constants.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_install_utils.h" #include "chrome/browser/web_applications/web_contents/web_app_url_loader.h" #include "third_party/abseil-cpp/absl/types/optional.h" class Profile; +class GURL; namespace content { class WebContents; @@ -31,7 +31,6 @@ namespace web_app { -class WebAppUrlLoader; class WebAppInstallFinalizer; class WebAppCommandScheduler; class WebAppUiManager;
diff --git a/chrome/browser/web_applications/externally_managed_app_manager.cc b/chrome/browser/web_applications/externally_managed_app_manager.cc index d00ff4eb..31a6535 100644 --- a/chrome/browser/web_applications/externally_managed_app_manager.cc +++ b/chrome/browser/web_applications/externally_managed_app_manager.cc
@@ -174,8 +174,7 @@ base::BindOnce( [](const UninstallCallback& callback, const GURL& app_url, webapps::UninstallResultCode code) { - callback.Run(app_url, - code == webapps::UninstallResultCode::kSuccess); + callback.Run(app_url, UninstallSucceeded(code)); }, callback, url)); }
diff --git a/chrome/browser/web_applications/externally_managed_app_manager_unittest.cc b/chrome/browser/web_applications/externally_managed_app_manager_unittest.cc index 0f02a47..7339efb 100644 --- a/chrome/browser/web_applications/externally_managed_app_manager_unittest.cc +++ b/chrome/browser/web_applications/externally_managed_app_manager_unittest.cc
@@ -501,6 +501,113 @@ /*additional_policy_ids=*/{})))); } +TEST_F(ExternallyAppManagerTest, RemovingInstallUrlsFromSource) { + const GURL kStartUrl = GURL("https://www.example.com/index.html"); + const GURL kInstallUrl1 = + GURL("https://www.example.com/nested/install_url.html"); + const GURL kInstallUrl2 = + GURL("https://www.example.com/nested/install_url2.html"); + const GURL kManifestUrl = GURL("https://www.example.com/manifest.json"); + + AppId app_id = PopulateBasicInstallPageWithManifest(kInstallUrl1, + kManifestUrl, kStartUrl); + AppId app_id2 = PopulateBasicInstallPageWithManifest(kInstallUrl2, + kManifestUrl, kStartUrl); + EXPECT_EQ(app_id, app_id2); + + // Synchronize with 2 install URLs. + { + SynchronizeFuture result; + provider().externally_managed_app_manager().SynchronizeInstalledApps( + CreateExternalInstallOptionsFromTemplate( + {kInstallUrl1, kInstallUrl2}, + ExternalInstallSource::kExternalPolicy), + ExternalInstallSource::kExternalPolicy, result.GetCallback()); + ASSERT_TRUE(result.Wait()); + + // Empty uninstall results. + EXPECT_THAT(result.Get<UninstallResults>(), IsEmpty()); + + // Installs should have both succeeded. + EXPECT_THAT( + result.Get<InstallResults>(), + UnorderedElementsAre( + std::make_pair( + kInstallUrl1, + ExternallyManagedAppManager::InstallResult( + webapps::InstallResultCode::kSuccessNewInstall, app_id)), + std::make_pair( + kInstallUrl2, + ExternallyManagedAppManager::InstallResult( + webapps::InstallResultCode::kSuccessNewInstall, app_id)))); + + EXPECT_EQ(app_registrar().GetAppIds().size(), 1ul); + const WebApp* app = app_registrar().GetAppById(app_id); + ASSERT_TRUE(app); + EXPECT_THAT(app->management_to_external_config_map(), + ElementsAre(std::make_pair( + WebAppManagement::kPolicy, + WebApp::ExternalManagementConfig( + /*is_placeholder=*/false, + /*install_urls=*/{kInstallUrl1, kInstallUrl2}, + /*additional_policy_ids=*/{})))); + } + + // Synchronize with 1 install URL. + { + SynchronizeFuture result; + provider().externally_managed_app_manager().SynchronizeInstalledApps( + CreateExternalInstallOptionsFromTemplate( + {kInstallUrl1}, ExternalInstallSource::kExternalPolicy), + ExternalInstallSource::kExternalPolicy, result.GetCallback()); + ASSERT_TRUE(result.Wait()); + + // Empty install results. + EXPECT_THAT(result.Get<InstallResults>(), + UnorderedElementsAre(std::make_pair( + kInstallUrl1, + ExternallyManagedAppManager::InstallResult( + webapps::InstallResultCode::kSuccessAlreadyInstalled, + app_id)))); + + // One install URL uninstalled. + EXPECT_THAT(result.Get<UninstallResults>(), + UnorderedElementsAre(std::make_pair(kInstallUrl2, true))); + + EXPECT_EQ(app_registrar().GetAppIds().size(), 1ul); + const WebApp* app = app_registrar().GetAppById(app_id); + ASSERT_TRUE(app); + EXPECT_THAT(app->management_to_external_config_map(), + ElementsAre(std::make_pair(WebAppManagement::kPolicy, + WebApp::ExternalManagementConfig( + /*is_placeholder=*/false, + /*install_urls=*/{kInstallUrl1}, + /*additional_policy_ids=*/{})))); + } + + // Synchronize with 0 install URLs. + { + SynchronizeFuture result; + provider().externally_managed_app_manager().SynchronizeInstalledApps( + CreateExternalInstallOptionsFromTemplate( + {}, ExternalInstallSource::kExternalPolicy), + ExternalInstallSource::kExternalPolicy, result.GetCallback()); + ASSERT_TRUE(result.Wait()); + + // Empty install results. + EXPECT_THAT(result.Get<InstallResults>(), IsEmpty()); + + // One install URL uninstalled. + EXPECT_THAT(result.Get<UninstallResults>(), + UnorderedElementsAre(std::make_pair(kInstallUrl1, true))); + + // App should be cleaned up. + EXPECT_EQ(app_registrar().GetAppIds().size(), 0ul); + const WebApp* app = app_registrar().GetAppById(app_id); + ASSERT_FALSE(app); + } +} + TEST_F(ExternallyAppManagerTest, InstallUrlChanges) { const GURL kStartUrl = GURL("https://www.example.com/index.html"); const GURL kInstallUrl =
diff --git a/chrome/browser/web_applications/remove_web_app_job.cc b/chrome/browser/web_applications/remove_web_app_job.cc deleted file mode 100644 index 674e3262..0000000 --- a/chrome/browser/web_applications/remove_web_app_job.cc +++ /dev/null
@@ -1,181 +0,0 @@ -// Copyright 2023 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/web_applications/remove_web_app_job.h" - -#include <memory> - -#include "base/functional/bind.h" -#include "base/memory/ptr_util.h" -#include "base/metrics/histogram_functions.h" -#include "chrome/browser/web_applications/locks/with_app_resources.h" -#include "chrome/browser/web_applications/os_integration/os_integration_manager.h" -#include "chrome/browser/web_applications/web_app.h" -#include "chrome/browser/web_applications/web_app_icon_manager.h" -#include "chrome/browser/web_applications/web_app_install_finalizer.h" -#include "chrome/browser/web_applications/web_app_install_manager.h" -#include "chrome/browser/web_applications/web_app_registrar.h" -#include "chrome/browser/web_applications/web_app_registry_update.h" -#include "chrome/browser/web_applications/web_app_sync_bridge.h" -#include "chrome/browser/web_applications/web_app_translation_manager.h" -#include "components/webapps/browser/uninstall_result_code.h" - -#if BUILDFLAG(IS_CHROMEOS_LACROS) -#include "base/feature_list.h" -#include "base/functional/callback_helpers.h" -#include "chrome/browser/browser_process.h" -#include "chrome/browser/profiles/profile_attributes_storage.h" -#include "chrome/browser/profiles/profile_manager.h" -#include "chrome/browser/profiles/profile_metrics.h" -#include "chrome/browser/web_applications/web_app_utils.h" -#endif // BUILDFLAG(IS_CHROMEOS_LACROS) - -namespace web_app { - -RemoveWebAppJob::~RemoveWebAppJob() = default; - -std::unique_ptr<RemoveWebAppJob> RemoveWebAppJob::Start( - webapps::WebappUninstallSource uninstall_source, - AppId app_id, - WithAppResources& resources, - Profile& profile, - UninstallCallback callback) { - CHECK(resources.registrar().GetAppById(app_id)); - - auto job = base::WrapUnique(new RemoveWebAppJob( - uninstall_source, app_id, resources, profile, std::move(callback))); - base::WeakPtr<RemoveWebAppJob> job_weak_ptr = - job->weak_ptr_factory_.GetWeakPtr(); - - resources.install_manager().NotifyWebAppWillBeUninstalled(app_id); - - { - // Note: It is supported to re-start an uninstall on startup, so - // `is_uninstalling()` is not checked. It is a class invariant that there - // can never be more than one uninstall task operating on the same web app - // at the same time. - ScopedRegistryUpdate update(&resources.sync_bridge()); - WebApp* app = update->UpdateApp(app_id); - CHECK(app); - app->SetIsUninstalling(true); - } - - auto synchronize_barrier = OsIntegrationManager::GetBarrierForSynchronize( - base::BindOnce(&RemoveWebAppJob::OnOsHooksUninstalled, job_weak_ptr)); - - // TODO(crbug.com/1401125): Remove UninstallAllOsHooks() once OS integration - // sub managers have been implemented. - resources.os_integration_manager().UninstallAllOsHooks(app_id, - synchronize_barrier); - resources.os_integration_manager().Synchronize( - app_id, base::BindOnce(synchronize_barrier, OsHooksErrors())); - - // While sometimes `Synchronize` needs to read icon data, for the uninstall - // case it never needs to be read. Thus, it is safe to schedule this now and - // not after the `Synchronize` call completes. - resources.icon_manager().DeleteData( - app_id, - base::BindOnce(&RemoveWebAppJob::OnIconDataDeleted, job_weak_ptr)); - - resources.translation_manager().DeleteTranslations( - app_id, - base::BindOnce(&RemoveWebAppJob::OnTranslationDataDeleted, job_weak_ptr)); - -#if BUILDFLAG(IS_CHROMEOS_LACROS) - if (ResolveExperimentalWebAppIsolationFeature() == - ExperimentalWebAppIsolationMode::kProfile) { - const WebApp& app = *resources.registrar().GetAppById(app_id); - if (app.chromeos_data() && app.chromeos_data()->app_profile_path) { - const base::FilePath& app_profile_path = - app.chromeos_data()->app_profile_path.value(); - CHECK(Profile::IsWebAppProfilePath(app_profile_path)); - if (g_browser_process->profile_manager() - ->GetProfileAttributesStorage() - .GetProfileAttributesWithPath(app_profile_path)) { - job->pending_app_profile_deletion_ = true; - g_browser_process->profile_manager() - ->GetDeleteProfileHelper() - .MaybeScheduleProfileForDeletion( - app_profile_path, - base::BindOnce(&RemoveWebAppJob::OnWebAppProfileDeleted, - job_weak_ptr), - ProfileMetrics::ProfileDelete::DELETE_PROFILE_USER_MANAGER); - } else { - LOG(ERROR) << "cannot find web app profile at " << app_profile_path; - } - } - } -#endif // BUILDFLAG(IS_CHROMEOS_LACROS) - - return job; -} - -RemoveWebAppJob::RemoveWebAppJob( - webapps::WebappUninstallSource uninstall_source, - AppId app_id, - WithAppResources& resources, - Profile& profile, - UninstallCallback callback) - : uninstall_source_(uninstall_source), - app_id_(app_id), - resources_(resources), - profile_(profile), - callback_(std::move(callback)) {} - -void RemoveWebAppJob::OnOsHooksUninstalled(OsHooksErrors errors) { - CHECK(!done_); - CHECK(!hooks_uninstalled_); - hooks_uninstalled_ = true; - base::UmaHistogramBoolean("WebApp.Uninstall.OsHookSuccess", errors.none()); - errors_ = errors_ || errors.any(); - MaybeFinishUninstall(); -} - -void RemoveWebAppJob::OnIconDataDeleted(bool success) { - CHECK(!done_); - CHECK(!app_data_deleted_); - app_data_deleted_ = true; - base::UmaHistogramBoolean("WebApp.Uninstall.IconDataSuccess", success); - errors_ = errors_ || !success; - MaybeFinishUninstall(); -} - -void RemoveWebAppJob::OnTranslationDataDeleted(bool success) { - CHECK(!done_); - CHECK(!translation_data_deleted_); - translation_data_deleted_ = true; - errors_ = errors_ || !success; - MaybeFinishUninstall(); -} - -void RemoveWebAppJob::OnWebAppProfileDeleted(Profile* profile) { - CHECK(!done_); - CHECK(pending_app_profile_deletion_); - // This must be an isolated web app profile rather than the WebAppProvider - // profile. - CHECK_NE(&profile_.get(), profile); - pending_app_profile_deletion_ = false; - MaybeFinishUninstall(); -} - -void RemoveWebAppJob::MaybeFinishUninstall() { - CHECK(!done_); - if (!hooks_uninstalled_ || !app_data_deleted_ || !translation_data_deleted_ || - pending_app_profile_deletion_) { - return; - } - done_ = true; - - base::UmaHistogramBoolean("WebApp.Uninstall.Result", !errors_); - { - CHECK_NE(resources_->registrar().GetAppById(app_id_), nullptr); - ScopedRegistryUpdate update(&resources_->sync_bridge()); - update->DeleteApp(app_id_); - } - resources_->install_manager().NotifyWebAppUninstalled(app_id_, - uninstall_source_); - std::move(callback_).Run(!errors_); -} - -} // namespace web_app
diff --git a/chrome/browser/web_applications/remove_web_app_job.h b/chrome/browser/web_applications/remove_web_app_job.h deleted file mode 100644 index acd5567..0000000 --- a/chrome/browser/web_applications/remove_web_app_job.h +++ /dev/null
@@ -1,83 +0,0 @@ -// Copyright 2023 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_WEB_APPLICATIONS_REMOVE_WEB_APP_JOB_H_ -#define CHROME_BROWSER_WEB_APPLICATIONS_REMOVE_WEB_APP_JOB_H_ - -#include <memory> - -#include "base/functional/callback.h" -#include "base/memory/raw_ref.h" -#include "base/memory/weak_ptr.h" -#include "chrome/browser/web_applications/os_integration/os_integration_manager.h" -#include "chrome/browser/web_applications/web_app_id.h" - -namespace webapps { -enum class UninstallResultCode; -enum class WebappUninstallSource; -} // namespace webapps - -class Profile; - -namespace web_app { - -class WithAppResources; - -// Uninstalls a given web app by: -// 1) Unregistering OS hooks. -// 2) Deleting the app from the database. -// 3) Deleting data on disk. -// Extra invariants: -// * There is never more than one uninstall task operating on the same app at -// the same time. -class RemoveWebAppJob { - public: - using UninstallCallback = base::OnceCallback<void(bool success)>; - - static std::unique_ptr<RemoveWebAppJob> Start( - webapps::WebappUninstallSource uninstall_source, - AppId app_id, - WithAppResources& resources, - Profile& profile, - UninstallCallback callback); - - ~RemoveWebAppJob(); - - private: - RemoveWebAppJob(webapps::WebappUninstallSource uninstall_source, - AppId app_id, - WithAppResources& resources, - Profile& profile, - UninstallCallback callback); - - void OnOsHooksUninstalled(OsHooksErrors errors); - void OnIconDataDeleted(bool success); - void OnTranslationDataDeleted(bool success); - void OnWebAppProfileDeleted(Profile* profile); - void MaybeFinishUninstall(); - - webapps::WebappUninstallSource uninstall_source_; - AppId app_id_; - // The RemoveWebAppJob is kicked off by the WebAppUninstallCommand - // and is constructed and destructed well within the lifetime of the - // Uninstall command. This ensures that this class is guaranteed to be - // destructed before any of the WebAppProvider systems shut down. - raw_ref<WithAppResources> resources_; - // `this` is owned by `profile_`. - raw_ref<Profile> profile_; - UninstallCallback callback_; - - bool app_data_deleted_ = false; - bool translation_data_deleted_ = false; - bool hooks_uninstalled_ = false; - bool pending_app_profile_deletion_ = false; - bool errors_ = false; - bool done_ = false; - - base::WeakPtrFactory<RemoveWebAppJob> weak_ptr_factory_{this}; -}; - -} // namespace web_app - -#endif // CHROME_BROWSER_WEB_APPLICATIONS_REMOVE_WEB_APP_JOB_H_
diff --git a/chrome/browser/web_applications/test/web_app_install_test_utils.cc b/chrome/browser/web_applications/test/web_app_install_test_utils.cc index 98fc35af..54a0d04 100644 --- a/chrome/browser/web_applications/test/web_app_install_test_utils.cc +++ b/chrome/browser/web_applications/test/web_app_install_test_utils.cc
@@ -120,17 +120,12 @@ void UninstallWebApp(Profile* profile, const AppId& app_id) { WebAppProvider* const provider = WebAppProvider::GetForTest(profile); - base::RunLoop run_loop; - + base::test::TestFuture<webapps::UninstallResultCode> future; DCHECK(provider->registrar_unsafe().CanUserUninstallWebApp(app_id)); provider->install_finalizer().UninstallWebApp( - app_id, webapps::WebappUninstallSource::kAppMenu, - base::BindLambdaForTesting([&](webapps::UninstallResultCode code) { - EXPECT_EQ(code, webapps::UninstallResultCode::kSuccess); - run_loop.Quit(); - })); + app_id, webapps::WebappUninstallSource::kAppMenu, future.GetCallback()); + EXPECT_TRUE(UninstallSucceeded(future.Get())); - run_loop.Run(); // Allow updates to be published to App Service listeners. base::RunLoop().RunUntilIdle(); }
diff --git a/chrome/browser/web_applications/uninstall/remove_install_source_job.cc b/chrome/browser/web_applications/uninstall/remove_install_source_job.cc new file mode 100644 index 0000000..8993e708 --- /dev/null +++ b/chrome/browser/web_applications/uninstall/remove_install_source_job.cc
@@ -0,0 +1,152 @@ +// 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/uninstall/remove_install_source_job.h" + +#include "base/strings/to_string.h" +#include "chrome/browser/web_applications/locks/all_apps_lock.h" +#include "chrome/browser/web_applications/uninstall/remove_web_app_job.h" +#include "chrome/browser/web_applications/web_app.h" +#include "chrome/browser/web_applications/web_app_install_manager.h" +#include "chrome/browser/web_applications/web_app_install_utils.h" +#include "chrome/browser/web_applications/web_app_registrar.h" +#include "chrome/browser/web_applications/web_app_registry_update.h" +#include "chrome/browser/web_applications/web_app_sync_bridge.h" + +namespace web_app { + +namespace { + +enum class Action { + kNone, + kRemoveInstallSource, + kRemoveApp, +}; + +Action GetAction(const WebAppSources& sources, + WebAppManagement::Type install_source) { + if (sources.none()) { + // TODO(crbug.com/1427340): Return a different UninstallResultCode + // for this case and log it in metrics. + return Action::kRemoveApp; + } + + if (!sources[install_source]) { + return Action::kNone; + } + + if (sources.count() > 1) { + return Action::kRemoveInstallSource; + } + + CHECK_EQ(sources.count(), 1u); + CHECK(sources[install_source]); + return Action::kRemoveApp; +} + +} // namespace + +RemoveInstallSourceJob::RemoveInstallSourceJob( + webapps::WebappUninstallSource uninstall_source, + Profile& profile, + AppId app_id, + WebAppManagement::Type install_source) + : uninstall_source_(uninstall_source), + profile_(profile), + app_id_(app_id), + install_source_(install_source) {} + +RemoveInstallSourceJob::~RemoveInstallSourceJob() = default; + +void RemoveInstallSourceJob::Start(AllAppsLock& lock, Callback callback) { + lock_ = &lock; + callback_ = std::move(callback); + + const WebApp* app = lock_->registrar().GetAppById(app_id_); + if (!app) { + CompleteAndSelfDestruct(webapps::UninstallResultCode::kNoAppToUninstall); + return; + } + + WebAppManagement::Type install_source = install_source_; + switch (GetAction(app->GetSources(), install_source)) { + case Action::kNone: + // TODO(crbug.com/1427340): Return a different UninstallResultCode + // for when no action is taken instead of being overly specific to the "no + // app" case. + CompleteAndSelfDestruct(webapps::UninstallResultCode::kNoAppToUninstall); + return; + + case Action::kRemoveInstallSource: + // Install sources may block user uninstallation (e.g. policy), if one of + // these install sources is being removed then the ability to uninstall + // may need to be re-deployed into the OS. + MaybeRegisterOsUninstall( + app, install_source, lock_->os_integration_manager(), + base::BindOnce( + &RemoveInstallSourceJob::RemoveInstallSourceFromDatabase, + weak_ptr_factory_.GetWeakPtr())); + return; + + case Action::kRemoveApp: + sub_job_ = std::make_unique<RemoveWebAppJob>( + uninstall_source_, profile_.get(), app_id_, + /*is_initial_request=*/false); + sub_job_->Start( + *lock_, + base::BindOnce(&RemoveInstallSourceJob::CompleteAndSelfDestruct, + weak_ptr_factory_.GetWeakPtr())); + return; + } +} + +base::Value RemoveInstallSourceJob::ToDebugValue() const { + base::Value::Dict dict; + dict.Set("!job", "RemoveInstallSourceJob"); + dict.Set("app_id", app_id_); + dict.Set("install_source", base::ToString(install_source_)); + dict.Set("callback", callback_.is_null()); + dict.Set("active_sub_job", + sub_job_ ? sub_job_->ToDebugValue() : base::Value()); + dict.Set("completed_sub_job", completed_sub_job_debug_value_.Clone()); + return base::Value(std::move(dict)); +} + +webapps::WebappUninstallSource RemoveInstallSourceJob::uninstall_source() + const { + return uninstall_source_; +} + +void RemoveInstallSourceJob::RemoveInstallSourceFromDatabase( + OsHooksErrors os_hooks_errors) { + { + ScopedRegistryUpdate update(&lock_->sync_bridge()); + WebApp* app = update->UpdateApp(app_id_); + app->RemoveSource(install_source_); + if (install_source_ == WebAppManagement::kSubApp) { + app->SetParentAppId(absl::nullopt); + } + // TODO(crbug.com/1447308): Make sync uninstall not synchronously + // remove its sync install source even while a command has an app lock so + // that we can CHECK(app->HasAnySources()) here. + } + + lock_->install_manager().NotifyWebAppSourceRemoved(app_id_); + + CompleteAndSelfDestruct(webapps::UninstallResultCode::kSuccess); +} + +void RemoveInstallSourceJob::CompleteAndSelfDestruct( + webapps::UninstallResultCode code) { + CHECK(callback_); + + if (sub_job_) { + completed_sub_job_debug_value_ = sub_job_->ToDebugValue(); + sub_job_.reset(); + } + + std::move(callback_).Run(code); +} + +} // namespace web_app
diff --git a/chrome/browser/web_applications/uninstall/remove_install_source_job.h b/chrome/browser/web_applications/uninstall/remove_install_source_job.h new file mode 100644 index 0000000..3636841 --- /dev/null +++ b/chrome/browser/web_applications/uninstall/remove_install_source_job.h
@@ -0,0 +1,62 @@ +// 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_UNINSTALL_REMOVE_INSTALL_SOURCE_JOB_H_ +#define CHROME_BROWSER_WEB_APPLICATIONS_UNINSTALL_REMOVE_INSTALL_SOURCE_JOB_H_ + +#include "base/functional/callback.h" +#include "base/values.h" +#include "chrome/browser/web_applications/os_integration/os_integration_manager.h" +#include "chrome/browser/web_applications/uninstall/uninstall_job.h" +#include "chrome/browser/web_applications/web_app_constants.h" +#include "chrome/browser/web_applications/web_app_id.h" +#include "components/webapps/browser/installable/installable_metrics.h" + +namespace web_app { + +class RemoveWebAppJob; + +// Removes an install source from a given web app, will uninstall the web app if +// no install sources remain. +// May cause a web app to become user uninstallable, will deploy uninstall OS +// hooks in that case. +class RemoveInstallSourceJob : public UninstallJob { + public: + RemoveInstallSourceJob(webapps::WebappUninstallSource uninstall_source, + Profile& profile, + AppId app_id, + WebAppManagement::Type install_source); + ~RemoveInstallSourceJob() override; + + const AppId& app_id() const { return app_id_; } + + // UninstallJob: + void Start(AllAppsLock& lock, Callback callback) override; + base::Value ToDebugValue() const override; + webapps::WebappUninstallSource uninstall_source() const override; + + private: + void RemoveInstallSourceFromDatabase(OsHooksErrors os_hooks_errors); + void CompleteAndSelfDestruct(webapps::UninstallResultCode code); + + webapps::WebappUninstallSource uninstall_source_; + // `this` must be owned by `profile_`. + raw_ref<Profile> profile_; + AppId app_id_; + WebAppManagement::Type install_source_; + + // `this` must be started and run within the scope of a WebAppCommand's + // AllAppsLock. + raw_ptr<AllAppsLock> lock_; + Callback callback_; + + std::unique_ptr<RemoveWebAppJob> sub_job_; + base::Value completed_sub_job_debug_value_; + + base::WeakPtrFactory<RemoveInstallSourceJob> weak_ptr_factory_{this}; +}; + +} // namespace web_app + +#endif // CHROME_BROWSER_WEB_APPLICATIONS_UNINSTALL_REMOVE_INSTALL_SOURCE_JOB_H_
diff --git a/chrome/browser/web_applications/uninstall/remove_install_url_job.cc b/chrome/browser/web_applications/uninstall/remove_install_url_job.cc new file mode 100644 index 0000000..c50d3da --- /dev/null +++ b/chrome/browser/web_applications/uninstall/remove_install_url_job.cc
@@ -0,0 +1,105 @@ +// 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/uninstall/remove_install_url_job.h" + +#include "base/containers/contains.h" +#include "base/strings/to_string.h" +#include "base/values.h" +#include "chrome/browser/web_applications/locks/all_apps_lock.h" +#include "chrome/browser/web_applications/uninstall/remove_install_source_job.h" +#include "chrome/browser/web_applications/web_app.h" +#include "chrome/browser/web_applications/web_app_registrar.h" +#include "chrome/browser/web_applications/web_app_registry_update.h" +#include "chrome/browser/web_applications/web_app_sync_bridge.h" + +namespace web_app { + +RemoveInstallUrlJob::RemoveInstallUrlJob( + webapps::WebappUninstallSource uninstall_source, + Profile& profile, + WebAppManagement::Type install_source, + GURL install_url) + : uninstall_source_(uninstall_source), + profile_(profile), + install_source_(install_source), + install_url_(std::move(install_url)) {} + +RemoveInstallUrlJob::~RemoveInstallUrlJob() = default; + +void RemoveInstallUrlJob::Start(AllAppsLock& lock, Callback callback) { + lock_ = &lock; + callback_ = std::move(callback); + + const WebApp* app = nullptr; + bool is_only_install_url = false; + for (const WebApp& candidate_app : lock_->registrar().GetApps()) { + const WebApp::ExternalConfigMap& config_map = + candidate_app.management_to_external_config_map(); + auto it = config_map.find(install_source_); + if (it != config_map.end()) { + const WebApp::ExternalManagementConfig& config = it->second; + if (base::Contains(config.install_urls, install_url_)) { + app = &candidate_app; + is_only_install_url = config.install_urls.size() == 1u; + break; + } + } + } + + if (!app) { + CompleteAndSelfDestruct(webapps::UninstallResultCode::kNoAppToUninstall); + return; + } + + if (is_only_install_url) { + sub_job_ = std::make_unique<RemoveInstallSourceJob>( + uninstall_source_, profile_.get(), app->app_id(), install_source_); + sub_job_->Start( + *lock_, base::BindOnce(&RemoveInstallUrlJob::CompleteAndSelfDestruct, + weak_ptr_factory_.GetWeakPtr())); + return; + } + + { + ScopedRegistryUpdate update(&lock_->sync_bridge()); + CHECK(update->UpdateApp(app->app_id()) + ->RemoveInstallUrlForSource(install_source_, install_url_)); + + // This is no longer a valid pointer after the registry update, clear it for + // safety. + app = nullptr; + } + CompleteAndSelfDestruct(webapps::UninstallResultCode::kSuccess); +} + +base::Value RemoveInstallUrlJob::ToDebugValue() const { + base::Value::Dict dict; + dict.Set("job", "RemoveInstallUrlJob"); + dict.Set("install_source", base::ToString(install_source_)); + dict.Set("install_url", install_url_.spec()); + dict.Set("callback", callback_.is_null()); + dict.Set("active_sub_job", + sub_job_ ? sub_job_->ToDebugValue() : base::Value()); + dict.Set("completed_sub_job", completed_sub_job_debug_value_.Clone()); + return base::Value(std::move(dict)); +} + +webapps::WebappUninstallSource RemoveInstallUrlJob::uninstall_source() const { + return uninstall_source_; +} + +void RemoveInstallUrlJob::CompleteAndSelfDestruct( + webapps::UninstallResultCode code) { + CHECK(callback_); + + if (sub_job_) { + completed_sub_job_debug_value_ = sub_job_->ToDebugValue(); + sub_job_.reset(); + } + + std::move(callback_).Run(code); +} + +} // namespace web_app
diff --git a/chrome/browser/web_applications/uninstall/remove_install_url_job.h b/chrome/browser/web_applications/uninstall/remove_install_url_job.h new file mode 100644 index 0000000..eb16b6d --- /dev/null +++ b/chrome/browser/web_applications/uninstall/remove_install_url_job.h
@@ -0,0 +1,67 @@ +// 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_UNINSTALL_REMOVE_INSTALL_URL_JOB_H_ +#define CHROME_BROWSER_WEB_APPLICATIONS_UNINSTALL_REMOVE_INSTALL_URL_JOB_H_ + +#include <memory> + +#include "base/functional/callback.h" +#include "base/memory/raw_ptr.h" +#include "base/memory/raw_ref.h" +#include "base/memory/weak_ptr.h" +#include "base/values.h" +#include "chrome/browser/web_applications/uninstall/uninstall_job.h" +#include "chrome/browser/web_applications/web_app_constants.h" +#include "chrome/browser/web_applications/web_app_id.h" +#include "components/webapps/browser/installable/installable_metrics.h" +#include "components/webapps/browser/uninstall_result_code.h" +#include "url/gurl.h" + +class Profile; + +namespace web_app { + +class RemoveInstallSourceJob; + +// Removes an install source's install URL from the first matching web app. +// This will remove the install source if there are no remaining install URLs +// for that install source which in turn will remove the web app if there are no +// remaining install sources for the web app. +class RemoveInstallUrlJob : public UninstallJob { + public: + RemoveInstallUrlJob(webapps::WebappUninstallSource uninstall_source, + Profile& profile, + WebAppManagement::Type install_source, + GURL install_url); + ~RemoveInstallUrlJob() override; + + // UninstallJob: + void Start(AllAppsLock& lock, Callback callback) override; + base::Value ToDebugValue() const override; + webapps::WebappUninstallSource uninstall_source() const override; + + private: + void CompleteAndSelfDestruct(webapps::UninstallResultCode code); + + webapps::WebappUninstallSource uninstall_source_; + // `this` must be owned by `profile_`. + raw_ref<Profile> profile_; + WebAppManagement::Type install_source_; + GURL install_url_; + + // `this` must be started and run within the scope of a WebAppCommand's + // AllAppsLock. + raw_ptr<AllAppsLock> lock_; + Callback callback_; + + std::unique_ptr<RemoveInstallSourceJob> sub_job_; + base::Value completed_sub_job_debug_value_; + + base::WeakPtrFactory<RemoveInstallUrlJob> weak_ptr_factory_{this}; +}; + +} // namespace web_app + +#endif // CHROME_BROWSER_WEB_APPLICATIONS_UNINSTALL_REMOVE_INSTALL_URL_JOB_H_
diff --git a/chrome/browser/web_applications/uninstall/remove_web_app_job.cc b/chrome/browser/web_applications/uninstall/remove_web_app_job.cc new file mode 100644 index 0000000..9cb2c24f --- /dev/null +++ b/chrome/browser/web_applications/uninstall/remove_web_app_job.cc
@@ -0,0 +1,297 @@ +// 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/uninstall/remove_web_app_job.h" + +#include <memory> + +#include "base/functional/bind.h" +#include "base/functional/callback_helpers.h" +#include "base/memory/ptr_util.h" +#include "base/metrics/histogram_functions.h" +#include "base/strings/to_string.h" +#include "chrome/browser/web_applications/locks/all_apps_lock.h" +#include "chrome/browser/web_applications/os_integration/os_integration_manager.h" +#include "chrome/browser/web_applications/uninstall/remove_install_source_job.h" +#include "chrome/browser/web_applications/user_uninstalled_preinstalled_web_app_prefs.h" +#include "chrome/browser/web_applications/web_app.h" +#include "chrome/browser/web_applications/web_app_icon_manager.h" +#include "chrome/browser/web_applications/web_app_install_finalizer.h" +#include "chrome/browser/web_applications/web_app_install_manager.h" +#include "chrome/browser/web_applications/web_app_registrar.h" +#include "chrome/browser/web_applications/web_app_registry_update.h" +#include "chrome/browser/web_applications/web_app_sync_bridge.h" +#include "chrome/browser/web_applications/web_app_translation_manager.h" +#include "components/webapps/browser/uninstall_result_code.h" + +#if BUILDFLAG(IS_CHROMEOS_LACROS) +#include "base/feature_list.h" +#include "base/functional/callback_helpers.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/profiles/profile_attributes_storage.h" +#include "chrome/browser/profiles/profile_manager.h" +#include "chrome/browser/profiles/profile_metrics.h" +#include "chrome/browser/web_applications/web_app_utils.h" +#endif // BUILDFLAG(IS_CHROMEOS_LACROS) + +namespace web_app { + +namespace { + +bool CanUninstallAllManagementSources( + webapps::WebappUninstallSource uninstall_source) { + // Check that the source was from a known 'user' or allowed ones such + // as kMigration. + return uninstall_source == webapps::WebappUninstallSource::kUnknown || + uninstall_source == webapps::WebappUninstallSource::kAppMenu || + uninstall_source == webapps::WebappUninstallSource::kAppsPage || + uninstall_source == webapps::WebappUninstallSource::kOsSettings || + uninstall_source == webapps::WebappUninstallSource::kAppManagement || + uninstall_source == webapps::WebappUninstallSource::kMigration || + uninstall_source == webapps::WebappUninstallSource::kAppList || + uninstall_source == webapps::WebappUninstallSource::kShelf || + uninstall_source == webapps::WebappUninstallSource::kSync || + uninstall_source == webapps::WebappUninstallSource::kStartupCleanup || + uninstall_source == webapps::WebappUninstallSource::kTestCleanup; +} + +} // namespace + +RemoveWebAppJob::RemoveWebAppJob( + webapps::WebappUninstallSource uninstall_source, + Profile& profile, + AppId app_id, + bool is_initial_request) + : uninstall_source_(uninstall_source), + profile_(profile), + app_id_(app_id), + is_initial_request_(is_initial_request) { + if (is_initial_request_) { + CHECK(CanUninstallAllManagementSources(uninstall_source_)); + } +} + +RemoveWebAppJob::~RemoveWebAppJob() = default; + +void RemoveWebAppJob::Start(AllAppsLock& lock, Callback callback) { + lock_ = &lock; + callback_ = std::move(callback); + + const WebApp* app = lock_->registrar().GetAppById(app_id_); + if (!app) { + CompleteAndSelfDestruct(webapps::UninstallResultCode::kNoAppToUninstall); + return; + } + + if (is_initial_request_) { + // The following CHECK streamlines the user uninstall and sync uninstall + // flow, because for sync uninstalls, the web_app source is removed before + // being synced, so the first condition fails by the time an Uninstall is + // invoked. + // TODO(crbug.com/1447308): Checking kSync shouldn't be needed once + // this issue is resolved. + // TODO(crbug.com/1427340): Change this to be: + // if (uninstall_source is user initiated) { + // CHECK(user can uninstall); + // Add to user uninstalled prefs. + // } + CHECK(app->CanUserUninstallWebApp() || + uninstall_source_ == webapps::WebappUninstallSource::kSync); + + if (app->IsPreinstalledApp()) { + // Update the default uninstalled web_app prefs if it is a preinstalled + // app but being removed by user. + const WebApp::ExternalConfigMap& config_map = + app->management_to_external_config_map(); + auto it = config_map.find(WebAppManagement::kDefault); + if (it != config_map.end()) { + UserUninstalledPreinstalledWebAppPrefs(profile_->GetPrefs()) + .Add(app_id_, it->second.install_urls); + } else { + base::UmaHistogramBoolean( + "WebApp.Preinstalled.ExternalConfigMapAbsentDuringUninstall", true); + } + } + } + + sub_apps_pending_removal_ = lock_->registrar().GetAllSubAppIds(app_id_); + + lock_->install_manager().NotifyWebAppWillBeUninstalled(app_id_); + + { + ScopedRegistryUpdate update(&lock_->sync_bridge()); + WebApp* mutable_app = update->UpdateApp(app_id_); + CHECK(mutable_app); + mutable_app->SetIsUninstalling(true); + } + + auto synchronize_barrier = OsIntegrationManager::GetBarrierForSynchronize( + base::BindOnce(&RemoveWebAppJob::OnOsHooksUninstalled, + weak_ptr_factory_.GetWeakPtr())); + + // TODO(crbug.com/1401125): Remove UninstallAllOsHooks() once OS integration + // sub managers have been implemented. + lock_->os_integration_manager().UninstallAllOsHooks(app_id_, + synchronize_barrier); + lock_->os_integration_manager().Synchronize( + app_id_, base::BindOnce(synchronize_barrier, OsHooksErrors())); + + // While sometimes `Synchronize` needs to read icon data, for the uninstall + // case it never needs to be read. Thus, it is safe to schedule this now and + // not after the `Synchronize` call completes. + lock_->icon_manager().DeleteData( + app_id_, base::BindOnce(&RemoveWebAppJob::OnIconDataDeleted, + weak_ptr_factory_.GetWeakPtr())); + + lock_->translation_manager().DeleteTranslations( + app_id_, base::BindOnce(&RemoveWebAppJob::OnTranslationDataDeleted, + weak_ptr_factory_.GetWeakPtr())); + +#if BUILDFLAG(IS_CHROMEOS_LACROS) + if (ResolveExperimentalWebAppIsolationFeature() == + ExperimentalWebAppIsolationMode::kProfile) { + if (app->chromeos_data() && app->chromeos_data()->app_profile_path) { + const base::FilePath& app_profile_path = + app->chromeos_data()->app_profile_path.value(); + CHECK(Profile::IsWebAppProfilePath(app_profile_path)); + if (g_browser_process->profile_manager() + ->GetProfileAttributesStorage() + .GetProfileAttributesWithPath(app_profile_path)) { + pending_app_profile_deletion_ = true; + g_browser_process->profile_manager() + ->GetDeleteProfileHelper() + .MaybeScheduleProfileForDeletion( + app_profile_path, + base::BindOnce(&RemoveWebAppJob::OnWebAppProfileDeleted, + weak_ptr_factory_.GetWeakPtr()), + ProfileMetrics::ProfileDelete::DELETE_PROFILE_USER_MANAGER); + } else { + } + } + } +#endif // BUILDFLAG(IS_CHROMEOS_LACROS) +} + +base::Value RemoveWebAppJob::ToDebugValue() const { + base::Value::Dict dict; + dict.Set("!job", "RemoveWebAppJob"); + dict.Set("app_id", app_id_); + dict.Set("is_initial_request", is_initial_request_); + dict.Set("callback", callback_.is_null()); + dict.Set("app_data_deleted", app_data_deleted_); + dict.Set("translation_data_deleted", translation_data_deleted_); + dict.Set("hooks_uninstalled", hooks_uninstalled_); + dict.Set("pending_app_profile_deletion", pending_app_profile_deletion_); + dict.Set("errors", errors_); + dict.Set("primary_removal_result", + primary_removal_result_ + ? base::Value(base::ToString(primary_removal_result_.value())) + : base::Value()); + { + base::Value::List list; + for (const AppId& sub_app_id : sub_apps_pending_removal_) { + list.Append(sub_app_id); + } + dict.Set("sub_apps_pending_removal", std::move(list)); + } + dict.Set("active_sub_job", + sub_job_ ? sub_job_->ToDebugValue() : base::Value()); + dict.Set("completed_sub_jobs", completed_sub_job_debug_dict_.Clone()); + return base::Value(std::move(dict)); +} + +webapps::WebappUninstallSource RemoveWebAppJob::uninstall_source() const { + return uninstall_source_; +} + +void RemoveWebAppJob::OnOsHooksUninstalled(OsHooksErrors errors) { + CHECK(!primary_removal_result_.has_value()); + CHECK(!hooks_uninstalled_); + hooks_uninstalled_ = true; + base::UmaHistogramBoolean("WebApp.Uninstall.OsHookSuccess", errors.none()); + errors_ = errors_ || errors.any(); + MaybeFinishPrimaryRemoval(); +} + +void RemoveWebAppJob::OnIconDataDeleted(bool success) { + CHECK(!primary_removal_result_.has_value()); + CHECK(!app_data_deleted_); + app_data_deleted_ = true; + base::UmaHistogramBoolean("WebApp.Uninstall.IconDataSuccess", success); + errors_ = errors_ || !success; + MaybeFinishPrimaryRemoval(); +} + +void RemoveWebAppJob::OnTranslationDataDeleted(bool success) { + CHECK(!primary_removal_result_.has_value()); + CHECK(!translation_data_deleted_); + translation_data_deleted_ = true; + errors_ = errors_ || !success; + MaybeFinishPrimaryRemoval(); +} + +void RemoveWebAppJob::OnWebAppProfileDeleted(Profile* profile) { + CHECK(!primary_removal_result_.has_value()); + CHECK(pending_app_profile_deletion_); + // This must be an isolated web app profile rather than the WebAppProvider + // profile. + CHECK_NE(&profile_.get(), profile); + pending_app_profile_deletion_ = false; + MaybeFinishPrimaryRemoval(); +} + +void RemoveWebAppJob::MaybeFinishPrimaryRemoval() { + CHECK(!primary_removal_result_.has_value()); + if (!hooks_uninstalled_ || !app_data_deleted_ || !translation_data_deleted_ || + pending_app_profile_deletion_) { + return; + } + + { + CHECK_NE(lock_->registrar().GetAppById(app_id_), nullptr); + ScopedRegistryUpdate update(&lock_->sync_bridge()); + update->DeleteApp(app_id_); + } + + primary_removal_result_ = errors_ ? webapps::UninstallResultCode::kError + : webapps::UninstallResultCode::kSuccess; + base::UmaHistogramBoolean("WebApp.Uninstall.Result", !errors_); + lock_->install_manager().NotifyWebAppUninstalled(app_id_, uninstall_source_); + + ProcessSubAppsPendingRemovalOrComplete(); +} + +void RemoveWebAppJob::ProcessSubAppsPendingRemovalOrComplete() { + CHECK(primary_removal_result_.has_value()); + + if (sub_job_) { + completed_sub_job_debug_dict_.Set(sub_job_->app_id(), + sub_job_->ToDebugValue()); + sub_job_.reset(); + } + + if (sub_apps_pending_removal_.empty()) { + CompleteAndSelfDestruct(primary_removal_result_.value()); + return; + } + + AppId sub_app_id = std::move(sub_apps_pending_removal_.back()); + sub_apps_pending_removal_.pop_back(); + + sub_job_ = std::make_unique<RemoveInstallSourceJob>( + uninstall_source_, profile_.get(), sub_app_id, + WebAppManagement::Type::kSubApp); + sub_job_->Start(*lock_, + base::IgnoreArgs<webapps::UninstallResultCode>(base::BindOnce( + &RemoveWebAppJob::ProcessSubAppsPendingRemovalOrComplete, + weak_ptr_factory_.GetWeakPtr()))); +} + +void RemoveWebAppJob::CompleteAndSelfDestruct( + webapps::UninstallResultCode code) { + CHECK(callback_); + std::move(callback_).Run(code); +} + +} // namespace web_app
diff --git a/chrome/browser/web_applications/uninstall/remove_web_app_job.h b/chrome/browser/web_applications/uninstall/remove_web_app_job.h new file mode 100644 index 0000000..b09e672 --- /dev/null +++ b/chrome/browser/web_applications/uninstall/remove_web_app_job.h
@@ -0,0 +1,79 @@ +// 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_UNINSTALL_REMOVE_WEB_APP_JOB_H_ +#define CHROME_BROWSER_WEB_APPLICATIONS_UNINSTALL_REMOVE_WEB_APP_JOB_H_ + +#include "base/functional/callback.h" +#include "base/values.h" +#include "chrome/browser/web_applications/os_integration/os_integration_manager.h" +#include "chrome/browser/web_applications/uninstall/uninstall_job.h" +#include "chrome/browser/web_applications/web_app_id.h" +#include "components/webapps/browser/installable/installable_metrics.h" +#include "third_party/abseil-cpp/absl/types/optional.h" + +class Profile; + +namespace web_app { + +class RemoveInstallSourceJob; + +// Removes a web app from the database and cleans up all assets and OS +// integrations. Disconnects it from any of its sub apps and uninstalls them too +// if they have no other install sources. +// Adds it to `UserUninstalledPreinstalledWebAppPrefs` if it was default +// installed and the removal was user initiated. +class RemoveWebAppJob : public UninstallJob { + public: + // `is_initial_request` indicates that this operation is not a byproduct of + // removing the last install source from a web app via external management and + // will be treated as a user uninstall. + RemoveWebAppJob(webapps::WebappUninstallSource uninstall_source, + Profile& profile, + AppId app_id, + bool is_initial_request = true); + ~RemoveWebAppJob() override; + + // UninstallJob: + void Start(AllAppsLock& lock, Callback callback) override; + base::Value ToDebugValue() const override; + webapps::WebappUninstallSource uninstall_source() const override; + + private: + void OnOsHooksUninstalled(OsHooksErrors errors); + void OnIconDataDeleted(bool success); + void OnTranslationDataDeleted(bool success); + void OnWebAppProfileDeleted(Profile* profile); + void MaybeFinishPrimaryRemoval(); + void ProcessSubAppsPendingRemovalOrComplete(); + void CompleteAndSelfDestruct(webapps::UninstallResultCode code); + + webapps::WebappUninstallSource uninstall_source_; + // `this` must be owned by `profile_`. + raw_ref<Profile> profile_; + AppId app_id_; + bool is_initial_request_; + + // `this` must be started and run within the scope of a WebAppCommand's + // AllAppsLock. + raw_ptr<AllAppsLock> lock_; + Callback callback_; + + bool app_data_deleted_ = false; + bool translation_data_deleted_ = false; + bool hooks_uninstalled_ = false; + bool pending_app_profile_deletion_ = false; + bool errors_ = false; + absl::optional<webapps::UninstallResultCode> primary_removal_result_; + + std::vector<AppId> sub_apps_pending_removal_; + std::unique_ptr<RemoveInstallSourceJob> sub_job_; + base::Value::Dict completed_sub_job_debug_dict_; + + base::WeakPtrFactory<RemoveWebAppJob> weak_ptr_factory_{this}; +}; + +} // namespace web_app + +#endif // CHROME_BROWSER_WEB_APPLICATIONS_UNINSTALL_REMOVE_WEB_APP_JOB_H_
diff --git a/chrome/browser/web_applications/uninstall/uninstall_job.cc b/chrome/browser/web_applications/uninstall/uninstall_job.cc new file mode 100644 index 0000000..4c41dc7 --- /dev/null +++ b/chrome/browser/web_applications/uninstall/uninstall_job.cc
@@ -0,0 +1,11 @@ +// 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/uninstall/uninstall_job.h" + +namespace web_app { + +UninstallJob::~UninstallJob() = default; + +} // namespace web_app
diff --git a/chrome/browser/web_applications/uninstall/uninstall_job.h b/chrome/browser/web_applications/uninstall/uninstall_job.h new file mode 100644 index 0000000..f57cc81 --- /dev/null +++ b/chrome/browser/web_applications/uninstall/uninstall_job.h
@@ -0,0 +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. + +#ifndef CHROME_BROWSER_WEB_APPLICATIONS_UNINSTALL_UNINSTALL_JOB_H_ +#define CHROME_BROWSER_WEB_APPLICATIONS_UNINSTALL_UNINSTALL_JOB_H_ + +#include "base/functional/callback.h" +#include "components/webapps/browser/installable/installable_metrics.h" +#include "components/webapps/browser/uninstall_result_code.h" + +namespace base { +class Value; +} + +namespace web_app { + +class AllAppsLock; + +// Common interface for uninstall related jobs used by WebAppUninstallCommand. +class UninstallJob { + public: + using Callback = base::OnceCallback<void(webapps::UninstallResultCode)>; + + virtual ~UninstallJob(); + + virtual void Start(AllAppsLock& lock, Callback) = 0; + virtual base::Value ToDebugValue() const = 0; + virtual webapps::WebappUninstallSource uninstall_source() const = 0; +}; + +} // namespace web_app + +#endif // CHROME_BROWSER_WEB_APPLICATIONS_UNINSTALL_UNINSTALL_JOB_H_
diff --git a/chrome/browser/web_applications/web_app_command_scheduler.cc b/chrome/browser/web_applications/web_app_command_scheduler.cc index 3a538b28..82d31ff 100644 --- a/chrome/browser/web_applications/web_app_command_scheduler.cc +++ b/chrome/browser/web_applications/web_app_command_scheduler.cc
@@ -44,6 +44,8 @@ #include "chrome/browser/web_applications/locks/shared_web_contents_lock.h" #include "chrome/browser/web_applications/locks/shared_web_contents_with_app_lock.h" #include "chrome/browser/web_applications/os_integration/os_integration_sub_manager.h" +#include "chrome/browser/web_applications/uninstall/remove_install_source_job.h" +#include "chrome/browser/web_applications/uninstall/remove_web_app_job.h" #include "chrome/browser/web_applications/web_app_command_manager.h" #include "chrome/browser/web_applications/web_app_constants.h" #include "chrome/browser/web_applications/web_app_provider.h" @@ -438,7 +440,7 @@ const AppId& app_id, absl::optional<WebAppManagement::Type> external_install_source, webapps::WebappUninstallSource uninstall_source, - WebAppUninstallCommand::UninstallWebAppCallback callback, + UninstallJob::Callback callback, const base::Location& location) { if (IsShuttingDown()) { base::SequencedTaskRunner::GetCurrentDefault()->PostTask( @@ -446,10 +448,17 @@ webapps::UninstallResultCode::kCancelled)); return; } + std::unique_ptr<UninstallJob> job; + if (external_install_source.has_value()) { + job = std::make_unique<RemoveInstallSourceJob>( + uninstall_source, *profile_, app_id, external_install_source.value()); + } else { + job = + std::make_unique<RemoveWebAppJob>(uninstall_source, *profile_, app_id); + } provider_->command_manager().ScheduleCommand( - std::make_unique<WebAppUninstallCommand>( - app_id, external_install_source, uninstall_source, - std::move(callback), profile_.get()), + std::make_unique<WebAppUninstallCommand>(std::move(job), + std::move(callback)), location); }
diff --git a/chrome/browser/web_applications/web_app_command_scheduler.h b/chrome/browser/web_applications/web_app_command_scheduler.h index dba56415..44924e1 100644 --- a/chrome/browser/web_applications/web_app_command_scheduler.h +++ b/chrome/browser/web_applications/web_app_command_scheduler.h
@@ -21,6 +21,7 @@ #include "chrome/browser/web_applications/commands/navigate_and_trigger_install_dialog_command.h" #include "chrome/browser/web_applications/external_install_options.h" #include "chrome/browser/web_applications/isolated_web_apps/install_isolated_web_app_command.h" +#include "chrome/browser/web_applications/uninstall/uninstall_job.h" #include "chrome/browser/web_applications/web_app_install_params.h" #include "chrome/browser/web_applications/web_app_ui_manager.h" #include "components/webapps/browser/installable/installable_metrics.h" @@ -211,11 +212,18 @@ OnceInstallCallback callback, const base::Location& location = FROM_HERE); - // Schedules a command that uninstalls a web app. + // Schedules a command that, if `external_install_source` is set, removes the + // install source from a web app, otherwise uninstalls the web app. If the + // last install source of a web app is removed the web app will be + // uninstalled. If the uninstalled web app has sub apps their parent install + // source will be removed, uninstalling them too if they no longer have any + // install sources, this process will repeat as many times as needed. + // TODO(crbug.com/1427340): Expose this as separate RemoveInstallUrl(), + // RemoveInstallSource() and UninstallWebApp() methods. void Uninstall(const AppId& app_id, absl::optional<WebAppManagement::Type> external_install_source, webapps::WebappUninstallSource uninstall_source, - WebAppInstallFinalizer::UninstallWebAppCallback callback, + UninstallJob::Callback callback, const base::Location& location = FROM_HERE); // Schedules a command that updates run on os login to provided `login_mode`
diff --git a/chrome/browser/web_applications/web_app_install_finalizer.cc b/chrome/browser/web_applications/web_app_install_finalizer.cc index 090d577..33aec3e0 100644 --- a/chrome/browser/web_applications/web_app_install_finalizer.cc +++ b/chrome/browser/web_applications/web_app_install_finalizer.cc
@@ -29,6 +29,9 @@ #include "chrome/browser/web_applications/os_integration/os_integration_manager.h" #include "chrome/browser/web_applications/os_integration/web_app_shortcuts_menu.h" #include "chrome/browser/web_applications/policy/web_app_policy_manager.h" +#include "chrome/browser/web_applications/uninstall/remove_install_source_job.h" +#include "chrome/browser/web_applications/uninstall/remove_install_url_job.h" +#include "chrome/browser/web_applications/uninstall/remove_web_app_job.h" #include "chrome/browser/web_applications/web_app.h" #include "chrome/browser/web_applications/web_app_command_manager.h" #include "chrome/browser/web_applications/web_app_helpers.h" @@ -102,6 +105,25 @@ } } +bool IsExternalInstallSource(WebAppManagement::Type install_source) { + switch (install_source) { + case WebAppManagement::Type::kSystem: + case WebAppManagement::Type::kKiosk: + case WebAppManagement::Type::kPolicy: + case WebAppManagement::Type::kSubApp: + case WebAppManagement::Type::kWebAppStore: + case WebAppManagement::Type::kDefault: + return true; + case WebAppManagement::Type::kSync: + // TODO(crbug.com/1427340): These are classified incorrectly, this check + // isn't really useful and should be removed. + case WebAppManagement::Type::kOneDriveIntegration: + case WebAppManagement::Type::kCommandLine: + case WebAppManagement::Type::kOem: + return false; + } +} + } // namespace WebAppInstallFinalizer::FinalizeOptions::FinalizeOptions( @@ -279,13 +301,7 @@ webapps::WebappUninstallSource uninstall_source, UninstallWebAppCallback callback) { DCHECK(started_); - - DCHECK(external_install_source == WebAppManagement::Type::kSystem || - external_install_source == WebAppManagement::Type::kKiosk || - external_install_source == WebAppManagement::Type::kPolicy || - external_install_source == WebAppManagement::Type::kSubApp || - external_install_source == WebAppManagement::Type::kWebAppStore || - external_install_source == WebAppManagement::Type::kDefault); + DCHECK(IsExternalInstallSource(external_install_source)); ScheduleUninstallCommand(app_id, external_install_source, uninstall_source, std::move(callback)); @@ -296,20 +312,11 @@ WebAppManagement::Type external_install_source, webapps::WebappUninstallSource uninstall_source, UninstallWebAppCallback callback) { - absl::optional<AppId> app_id = - GetWebAppRegistrar().LookupExternalAppId(app_url); - if (!app_id.has_value()) { - LOG(WARNING) << "Couldn't uninstall web app with url " << app_url - << "; No corresponding web app for url."; - base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( - FROM_HERE, - base::BindOnce(std::move(callback), - webapps::UninstallResultCode::kNoAppToUninstall)); - return; - } - - UninstallExternalWebApp(app_id.value(), external_install_source, - uninstall_source, std::move(callback)); + DCHECK(IsExternalInstallSource(external_install_source)); + command_manager_->ScheduleCommand(std::make_unique<WebAppUninstallCommand>( + std::make_unique<RemoveInstallUrlJob>(uninstall_source, *profile_, + external_install_source, app_url), + std::move(callback))); } void WebAppInstallFinalizer::UninstallWebApp( @@ -707,16 +714,24 @@ } } +// TODO(crbug.com/1427340): Remove this interface in favour of calling into the +// WebAppCommandScheduler directly. void WebAppInstallFinalizer::ScheduleUninstallCommand( const AppId& app_id, absl::optional<WebAppManagement::Type> external_install_source, webapps::WebappUninstallSource uninstall_source, UninstallWebAppCallback callback) { - auto uninstall_command = std::make_unique<WebAppUninstallCommand>( - app_id, external_install_source, uninstall_source, std::move(callback), - *profile_); + std::unique_ptr<UninstallJob> job; + if (external_install_source.has_value()) { + job = std::make_unique<RemoveInstallSourceJob>( + uninstall_source, *profile_, app_id, external_install_source.value()); + } else { + job = + std::make_unique<RemoveWebAppJob>(uninstall_source, *profile_, app_id); + } - command_manager_->ScheduleCommand(std::move(uninstall_command)); + command_manager_->ScheduleCommand(std::make_unique<WebAppUninstallCommand>( + std::move(job), std::move(callback))); } FileHandlerUpdateAction WebAppInstallFinalizer::GetFileHandlerUpdateAction(
diff --git a/chrome/browser/web_applications/web_app_sync_bridge.cc b/chrome/browser/web_applications/web_app_sync_bridge.cc index 3d34fea..413b6dd 100644 --- a/chrome/browser/web_applications/web_app_sync_bridge.cc +++ b/chrome/browser/web_applications/web_app_sync_bridge.cc
@@ -512,7 +512,7 @@ const AppId& app, webapps::UninstallResultCode code) { base::UmaHistogramBoolean("Webapp.SyncInitiatedUninstallResult", - code == webapps::UninstallResultCode::kSuccess); + UninstallSucceeded(code)); } void WebAppSyncBridge::ReportErrorToChangeProcessor(
diff --git a/chrome/build/lacros64.pgo.txt b/chrome/build/lacros64.pgo.txt index 6419ea8..59c7850d3 100644 --- a/chrome/build/lacros64.pgo.txt +++ b/chrome/build/lacros64.pgo.txt
@@ -1 +1 @@ -chrome-chromeos-amd64-generic-main-1686569992-cadbff87684e467b60f416db70f7174d4f771626.profdata +chrome-chromeos-amd64-generic-main-1686614843-fb023098bd54d5f9232a1aab9a5addc0eb0e66f9.profdata
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt index d20cd10..141c0f6 100644 --- a/chrome/build/linux.pgo.txt +++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@ -chrome-linux-main-1686592783-12f8170d67690f1acad6573f0402eca64644f8f6.profdata +chrome-linux-main-1686614344-b40512faafcbf1a450705d568f696240d79af67e.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt index 1e1f242..0923d41 100644 --- a/chrome/build/mac-arm.pgo.txt +++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@ -chrome-mac-arm-main-1686607171-743d6a79a755c8a4c4616fa1ab322ae584b6b424.profdata +chrome-mac-arm-main-1686628682-4adcbdf54b11aa11df116454d7dff7e825f3eb43.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt index 3ad3e79..fbdb8c2c 100644 --- a/chrome/build/mac.pgo.txt +++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@ -chrome-mac-main-1686592783-1607a28f8d7d28e7ba5762ed24afa975b3d88500.profdata +chrome-mac-main-1686614344-808ac7995b1cf6853fa7f0128c09cb3b69189308.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt index 8835530..205e901 100644 --- a/chrome/build/win32.pgo.txt +++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@ -chrome-win32-main-1686603569-e7868c60e5a1da1934d0615259b23d04fd0aedfc.profdata +chrome-win32-main-1686625113-10f7c4ee5c417dcac022725baa02c44e7cda1edf.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt index 925c3c9d..9ce230c5 100644 --- a/chrome/build/win64.pgo.txt +++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@ -chrome-win64-main-1686603569-c33ab0a6a9068249df3039b1848349c92b813cf7.profdata +chrome-win64-main-1686625113-76fa6f71e60b16f08a61c19af03c00697b955c34.profdata
diff --git a/chrome/common/extensions/api/file_manager_private.idl b/chrome/common/extensions/api/file_manager_private.idl index 7749b59e..c9d8967 100644 --- a/chrome/common/extensions/api/file_manager_private.idl +++ b/chrome/common/extensions/api/file_manager_private.idl
@@ -388,13 +388,15 @@ }; // Describes the stage the bulk pinning manager is in. This enum should be kept -// in sync with chromeos/ash/components/drivefs/drivefs_pin_manager.h +// in sync with chromeos/ash/components/drivefs/mojom/pin_manager_types.mojom. enum BulkPinStage { // Initial stage. stopped, // Paused because of unfavorable network conditions. - paused, + paused_offline, + // Paused due to battery saver mode active. + paused_battery_saver, // In-progress stages. getting_free_space,
diff --git a/chrome/common/extensions/extension_constants.cc b/chrome/common/extensions/extension_constants.cc index a14ac1b..27579fd 100644 --- a/chrome/common/extensions/extension_constants.cc +++ b/chrome/common/extensions/extension_constants.cc
@@ -93,6 +93,8 @@ "accessibility_common_manifest.json"; const char kAccessibilityCommonGuestManifestFilename[] = "accessibility_common_manifest_guest.json"; +const char kAutotestPrivateTestExtensionId[] = + "ddammdhioacbehjngdmkjcjbnfginlla"; const char kChromeVoxExtensionPath[] = "chromeos/accessibility"; const char kChromeVoxManifestFilename[] = "chromevox_manifest.json"; const char kChromeVoxGuestManifestFilename[] = "chromevox_manifest_guest.json";
diff --git a/chrome/common/extensions/extension_constants.h b/chrome/common/extensions/extension_constants.h index 61d38ef8..0ad5613bc 100644 --- a/chrome/common/extensions/extension_constants.h +++ b/chrome/common/extensions/extension_constants.h
@@ -184,6 +184,8 @@ extern const char kAccessibilityCommonManifestFilename[]; // The guest manifest filename of the Accessibility Common extension. extern const char kAccessibilityCommonGuestManifestFilename[]; +// Extension ID of the autotest_private test extension. +extern const char kAutotestPrivateTestExtensionId[]; // Path to preinstalled ChromeVox screen reader extension (relative to // |chrome::DIR_RESOURCES|). extern const char kChromeVoxExtensionPath[];
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 98cfff5b..345c267 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -3883,6 +3883,7 @@ "../browser/ash/app_list/app_list_sort_browsertest.cc", "../browser/ash/app_list/app_service/app_service_app_item_browsertest.cc", "../browser/ash/app_list/app_service/app_service_context_menu_browsertest.cc", + "../browser/ash/app_list/app_service/app_service_promise_app_item_browsertest.cc", "../browser/ash/app_list/arc/arc_usb_host_permission_browsertest.cc", "../browser/ash/app_list/chrome_app_list_item_browsertest.cc", "../browser/ash/app_list/chrome_app_list_model_updater_browsertest.cc",
diff --git a/chrome/test/data/extensions/api_test/autotest_private/test.js b/chrome/test/data/extensions/api_test/autotest_private/test.js index 7b0ee69..c619ea96 100644 --- a/chrome/test/data/extensions/api_test/autotest_private/test.js +++ b/chrome/test/data/extensions/api_test/autotest_private/test.js
@@ -1612,9 +1612,9 @@ chrome.autotestPrivate.getLacrosInfo( chrome.test.callbackPass(function(lacrosInfo) { chrome.test.assertEq('Unavailable', lacrosInfo['state']); - chrome.test.assertTrue(!lacrosInfo['isKeepAlive']); + chrome.test.assertTrue(lacrosInfo['isKeepAlive']); chrome.test.assertEq('', lacrosInfo['lacrosPath']); - chrome.test.assertEq('SideBySide', lacrosInfo['mode']); + chrome.test.assertEq('Only', lacrosInfo['mode']); })); }, ]
diff --git a/chromeos/ash/components/drivefs/BUILD.gn b/chromeos/ash/components/drivefs/BUILD.gn index 3847c05..1aa9b202 100644 --- a/chromeos/ash/components/drivefs/BUILD.gn +++ b/chromeos/ash/components/drivefs/BUILD.gn
@@ -46,6 +46,8 @@ "//chromeos/ash/components/drivefs/mojom:pin_manager_types", "//chromeos/ash/components/network", "//chromeos/components/mojo_bootstrap", + "//chromeos/dbus/power:power", + "//chromeos/dbus/power:power_manager_proto", "//components/account_id", "//components/drive", "//components/signin/public/identity_manager", @@ -102,6 +104,8 @@ "//chromeos/ash/components/drivefs/mojom", "//chromeos/ash/components/drivefs/mojom:pin_manager_types", "//chromeos/components/mojo_bootstrap", + "//chromeos/dbus/power", + "//chromeos/dbus/power:power_manager_proto", "//components/account_id", "//components/drive", "//components/invalidation/impl:test_support",
diff --git a/chromeos/ash/components/drivefs/drivefs_pin_manager.cc b/chromeos/ash/components/drivefs/drivefs_pin_manager.cc index 90d5113..992cca84 100644 --- a/chromeos/ash/components/drivefs/drivefs_pin_manager.cc +++ b/chromeos/ash/components/drivefs/drivefs_pin_manager.cc
@@ -20,6 +20,7 @@ #include "base/strings/stringprintf.h" #include "base/task/sequenced_task_runner.h" #include "chromeos/ash/components/drivefs/mojom/drivefs.mojom.h" +#include "chromeos/dbus/power/power_manager_client.h" #include "components/drive/file_errors.h" #include "third_party/cros_system_api/constants/cryptohome.h" @@ -299,7 +300,8 @@ case Stage::kGettingFreeSpace: case Stage::kListingFiles: - case Stage::kPaused: + case Stage::kPausedOffline: + case Stage::kPausedBatterySaver: case Stage::kSuccess: case Stage::kSyncing: case Stage::kStopped: @@ -317,7 +319,29 @@ return true; case Stage::kStopped: - case Stage::kPaused: + case Stage::kPausedOffline: + case Stage::kPausedBatterySaver: + case Stage::kSuccess: + case Stage::kCannotGetFreeSpace: + case Stage::kCannotListFiles: + case Stage::kNotEnoughSpace: + case Stage::kCannotEnableDocsOffline: + return false; + } + + NOTREACHED_NORETURN() << "Unexpected Stage " << Quote(stage); +} + +bool IsPaused(const Stage stage) { + switch (stage) { + case Stage::kPausedOffline: + case Stage::kPausedBatterySaver: + return true; + + case Stage::kGettingFreeSpace: + case Stage::kListingFiles: + case Stage::kSyncing: + case Stage::kStopped: case Stage::kSuccess: case Stage::kCannotGetFreeSpace: case Stage::kCannotListFiles: @@ -583,6 +607,9 @@ space_getter_(base::BindRepeating(&GetFreeSpace)) { DCHECK(drivefs_); ash::UserDataAuthClient::Get()->AddObserver(this); + chromeos::PowerManagerClient::Get()->AddObserver(this); + chromeos::PowerManagerClient::Get()->GetBatterySaverModeState(base::BindOnce( + &PinManager::OnGotBatterySaverState, weak_ptr_factory_.GetWeakPtr())); } PinManager::~PinManager() { @@ -590,6 +617,7 @@ StopMonitoringSpace(); ash::UserDataAuthClient::Get()->RemoveObserver(this); + chromeos::PowerManagerClient::Get()->RemoveObserver(this); DCHECK(!InProgress(progress_.stage)) << "Pin manager is " << Quote(progress_.stage); @@ -617,7 +645,12 @@ if (!is_online_) { LOG(WARNING) << "Device is currently offline"; - return Complete(Stage::kPaused); + return Complete(Stage::kPausedOffline); + } + + if (!is_battery_ok_) { + LOG(WARNING) << "Device is currently in battery saver mode"; + return Complete(Stage::kPausedBatterySaver); } VLOG(2) << "Getting free space"; @@ -708,6 +741,30 @@ } } +void PinManager::OnGotBatterySaverState( + absl::optional<power_manager::BatterySaverModeState> state) { + if (state) { + BatterySaverModeStateChanged(*state); + } +} + +void PinManager::BatterySaverModeStateChanged( + const power_manager::BatterySaverModeState& state) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + is_battery_ok_ = !state.enabled(); + VLOG(2) << "Battery saver mode changed, online=" << is_online_ + << ", battery=" << is_battery_ok_; + if (!is_battery_ok_ && InProgress(progress_.stage)) { + VLOG(1) << "Pausing for battery saver"; + return Complete(Stage::kPausedBatterySaver); + } + + if (is_online_ && is_battery_ok_ && IsPaused(progress_.stage)) { + VLOG(1) << "Restarting from battery saver"; + Start(); + } +} + void PinManager::ListItems(const Id dir_id, Path dir_path) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); VLOG(1) << "Visiting " << dir_id << " " << Quote(dir_path); @@ -949,8 +1006,12 @@ VLOG(1) << "Finished with success"; break; - case Stage::kPaused: - VLOG(1) << "Paused"; + case Stage::kPausedOffline: + VLOG(1) << "Paused offline"; + break; + + case Stage::kPausedBatterySaver: + VLOG(1) << "Paused battery saver"; break; case Stage::kStopped: @@ -1481,18 +1542,18 @@ } void PinManager::SetOnline(const bool online) { - VLOG(2) << "Online: " << online; DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + VLOG(2) << "Online: " << online << ", battery: " << is_battery_ok_; is_online_ = online; - if (!is_online_ && InProgress(progress_.stage)) { + if (InProgress(progress_.stage)) { VLOG(1) << "Going offline"; - return Complete(Stage::kPaused); + return Complete(Stage::kPausedOffline); } - if (is_online_ && progress_.stage == Stage::kPaused) { - VLOG(1) << "Coming back online"; - return Start(); + if (is_online_ && is_battery_ok_ && IsPaused(progress_.stage)) { + VLOG(1) << "Restarting from battery saver"; + Start(); } }
diff --git a/chromeos/ash/components/drivefs/drivefs_pin_manager.h b/chromeos/ash/components/drivefs/drivefs_pin_manager.h index a791030..7084f63 100644 --- a/chromeos/ash/components/drivefs/drivefs_pin_manager.h +++ b/chromeos/ash/components/drivefs/drivefs_pin_manager.h
@@ -29,6 +29,7 @@ #include "chromeos/ash/components/drivefs/drivefs_host_observer.h" #include "chromeos/ash/components/drivefs/mojom/drivefs.mojom.h" #include "chromeos/ash/components/drivefs/mojom/pin_manager_types.mojom.h" +#include "chromeos/dbus/power/power_manager_client.h" #include "components/drive/file_errors.h" #include "mojo/public/cpp/bindings/remote.h" #include "third_party/abseil-cpp/absl/types/optional.h" @@ -149,7 +150,8 @@ class COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_DRIVEFS) PinManager : public DriveFsHostObserver, ash::UserDataAuthClient::Observer, - ash::SpacedClient::Observer { + ash::SpacedClient::Observer, + chromeos::PowerManagerClient::Observer { public: using Path = base::FilePath; @@ -387,6 +389,15 @@ // ash::SpacedClient::Observer void OnSpaceUpdate(const SpaceEvent& event) override; + // chromeos::PowerManagerClient::Observer + void BatterySaverModeStateChanged( + const power_manager::BatterySaverModeState& state) override; + + // Callback used to query battery saver state from PowerManagerClient on + // startup. + void OnGotBatterySaverState( + absl::optional<power_manager::BatterySaverModeState> state); + // Starts and stops monitoring space using the SpacedClient::Observer. bool StartMonitoringSpace(); void StopMonitoringSpace(); @@ -416,6 +427,9 @@ // tests. bool is_online_ GUARDED_BY_CONTEXT(sequence_checker_) = true; + // Is the device battery ok for doing sync (e.g. not in battery saver mode). + bool is_battery_ok_ GUARDED_BY_CONTEXT(sequence_checker_) = true; + // Should the feature actually pin files, or should it stop after checking the // space requirements? bool should_pin_ GUARDED_BY_CONTEXT(sequence_checker_) = true; @@ -473,7 +487,7 @@ FRIEND_TEST_ALL_PREFIXES(DriveFsPinManagerTest, NotEnoughSpace3); FRIEND_TEST_ALL_PREFIXES(DriveFsPinManagerTest, OnSpaceUpdate); FRIEND_TEST_ALL_PREFIXES(DriveFsPinManagerTest, StartMonitoringSpace); - FRIEND_TEST_ALL_PREFIXES(DriveFsPinManagerTest, SetOnline); + FRIEND_TEST_ALL_PREFIXES(DriveFsPinManagerTest, SetOnlineAndBatteryOk); FRIEND_TEST_ALL_PREFIXES(DriveFsPinManagerTest, OnTransientError); FRIEND_TEST_ALL_PREFIXES(DriveFsPinManagerTest, OnError); FRIEND_TEST_ALL_PREFIXES(DriveFsPinManagerTest, StartWhenInProgress);
diff --git a/chromeos/ash/components/drivefs/drivefs_pin_manager_unittest.cc b/chromeos/ash/components/drivefs/drivefs_pin_manager_unittest.cc index 207ca50..92e1366a 100644 --- a/chromeos/ash/components/drivefs/drivefs_pin_manager_unittest.cc +++ b/chromeos/ash/components/drivefs/drivefs_pin_manager_unittest.cc
@@ -30,6 +30,7 @@ #include "chromeos/ash/components/dbus/userdataauth/userdataauth_client.h" #include "chromeos/ash/components/drivefs/mojom/drivefs.mojom-test-utils.h" #include "chromeos/ash/components/drivefs/mojom/drivefs.mojom.h" +#include "chromeos/dbus/power/power_manager_client.h" #include "components/drive/file_errors.h" #include "mojo/public/cpp/bindings/receiver.h" #include "testing/gmock/include/gmock/gmock.h" @@ -215,11 +216,13 @@ void SetUp() override { UserDataAuthClient::InitializeFake(); SpacedClient::InitializeFake(); + chromeos::PowerManagerClient::InitializeFake(); } void TearDown() override { UserDataAuthClient::Shutdown(); SpacedClient::Shutdown(); + chromeos::PowerManagerClient::Shutdown(); } PinManager::SpaceGetter GetSpaceGetter() { @@ -242,7 +245,8 @@ std::unordered_set<std::string> labels; for (const Stage stage : { Stage::kStopped, - Stage::kPaused, + Stage::kPausedOffline, + Stage::kPausedBatterySaver, Stage::kGettingFreeSpace, Stage::kListingFiles, Stage::kSyncing, @@ -274,7 +278,8 @@ for (const Stage stage : { Stage::kStopped, - Stage::kPaused, + Stage::kPausedOffline, + Stage::kPausedBatterySaver, Stage::kGettingFreeSpace, Stage::kListingFiles, Stage::kSyncing, @@ -2389,13 +2394,14 @@ } // Tests PinManager::SetOnline(). -TEST_F(DriveFsPinManagerTest, SetOnline) { +TEST_F(DriveFsPinManagerTest, SetOnlineAndBatteryOk) { PinManager manager(profile_path_, mount_path_, &drivefs_); manager.SetSpaceGetter(GetSpaceGetter()); DCHECK_CALLED_ON_VALID_SEQUENCE(manager.sequence_checker_); EXPECT_EQ(manager.progress_.stage, Stage::kStopped); EXPECT_TRUE(manager.is_online_); + EXPECT_TRUE(manager.is_battery_ok_); manager.SetOnline(false); EXPECT_EQ(manager.progress_.stage, Stage::kStopped); @@ -2409,8 +2415,50 @@ EXPECT_EQ(manager.progress_.stage, Stage::kStopped); EXPECT_FALSE(manager.is_online_); + power_manager::BatterySaverModeState state; + state.set_enabled(true); + manager.BatterySaverModeStateChanged(state); + EXPECT_EQ(manager.progress_.stage, Stage::kStopped); + EXPECT_FALSE(manager.is_battery_ok_); + + state.set_enabled(false); + manager.BatterySaverModeStateChanged(state); + EXPECT_EQ(manager.progress_.stage, Stage::kStopped); + EXPECT_TRUE(manager.is_battery_ok_); + + manager.SetOnline(false); + state.set_enabled(true); + manager.BatterySaverModeStateChanged(state); + EXPECT_FALSE(manager.is_online_); + EXPECT_FALSE(manager.is_battery_ok_); + manager.Start(); - EXPECT_EQ(manager.progress_.stage, Stage::kPaused); + EXPECT_EQ(manager.progress_.stage, Stage::kPausedOffline); + EXPECT_FALSE(manager.is_online_); + EXPECT_FALSE(manager.is_battery_ok_); + + manager.SetOnline(true); + EXPECT_EQ(manager.progress_.stage, Stage::kPausedOffline); + EXPECT_CALL(space_getter_, GetFreeSpace(gcache_dir_, _)).Times(1); + state.set_enabled(false); + manager.BatterySaverModeStateChanged(state); + EXPECT_EQ(manager.progress_.stage, Stage::kGettingFreeSpace); + state.set_enabled(true); + manager.BatterySaverModeStateChanged(state); + EXPECT_EQ(manager.progress_.stage, Stage::kPausedBatterySaver); + + manager.SetOnline(false); + state.set_enabled(false); + manager.BatterySaverModeStateChanged(state); + EXPECT_EQ(manager.progress_.stage, Stage::kPausedBatterySaver); + + EXPECT_CALL(space_getter_, GetFreeSpace(gcache_dir_, _)).Times(1); + manager.SetOnline(true); + EXPECT_EQ(manager.progress_.stage, Stage::kGettingFreeSpace); + EXPECT_TRUE(manager.is_online_); + + manager.SetOnline(false); + EXPECT_EQ(manager.progress_.stage, Stage::kPausedOffline); EXPECT_FALSE(manager.is_online_); EXPECT_CALL(space_getter_, GetFreeSpace(gcache_dir_, _)).Times(1); @@ -2419,16 +2467,7 @@ EXPECT_TRUE(manager.is_online_); manager.SetOnline(false); - EXPECT_EQ(manager.progress_.stage, Stage::kPaused); - EXPECT_FALSE(manager.is_online_); - - EXPECT_CALL(space_getter_, GetFreeSpace(gcache_dir_, _)).Times(1); - manager.SetOnline(true); - EXPECT_EQ(manager.progress_.stage, Stage::kGettingFreeSpace); - EXPECT_TRUE(manager.is_online_); - - manager.SetOnline(false); - EXPECT_EQ(manager.progress_.stage, Stage::kPaused); + EXPECT_EQ(manager.progress_.stage, Stage::kPausedOffline); EXPECT_FALSE(manager.is_online_); manager.Stop();
diff --git a/chromeos/ash/components/drivefs/mojom/pin_manager_types.mojom b/chromeos/ash/components/drivefs/mojom/pin_manager_types.mojom index f301a0a..911bd98 100644 --- a/chromeos/ash/components/drivefs/mojom/pin_manager_types.mojom +++ b/chromeos/ash/components/drivefs/mojom/pin_manager_types.mojom
@@ -14,19 +14,20 @@ kStopped = 0, // Paused because of unfavorable network conditions. - kPaused = 1, + kPausedOffline = 1, + kPausedBatterySaver = 2, // In-progress stages. - kGettingFreeSpace = 2, - kListingFiles = 3, - kSyncing = 4, + kGettingFreeSpace = 3, + kListingFiles = 4, + kSyncing = 5, // Final success stage. - kSuccess = 5, + kSuccess = 6, // Final error stages. - kCannotGetFreeSpace = 6, - kCannotListFiles = 7, - kNotEnoughSpace = 8, - kCannotEnableDocsOffline = 9, + kCannotGetFreeSpace = 7, + kCannotListFiles = 8, + kNotEnoughSpace = 9, + kCannotEnableDocsOffline = 10, };
diff --git a/chromeos/ash/services/assistant/DEPS b/chromeos/ash/services/assistant/DEPS index 9e86a36..b20d3c13 100644 --- a/chromeos/ash/services/assistant/DEPS +++ b/chromeos/ash/services/assistant/DEPS
@@ -12,7 +12,6 @@ "+services/device/public", "+services/media_session/public", "+services/network/public", - "+ui/accessibility/accessibility_switches.h", "+ui/accessibility/ax_assistant_structure.h", "+ui/accessibility/mojom", "+ui/base",
diff --git a/chromeos/crosapi/mojom/web_app_types.mojom b/chromeos/crosapi/mojom/web_app_types.mojom index 9c430115..5df0347d 100644 --- a/chromeos/crosapi/mojom/web_app_types.mojom +++ b/chromeos/crosapi/mojom/web_app_types.mojom
@@ -48,7 +48,8 @@ kSuccess, kNoAppToUninstall, kCancelled, - kError, + [Default] kError, + [MinVersion=1] kShutdown, }; // A subset of |WebAppInstallInfo| necessary to install a web app originated in
diff --git a/chromeos/crosapi/mojom/web_app_types_mojom_traits.cc b/chromeos/crosapi/mojom/web_app_types_mojom_traits.cc index 466a938..91eede00 100644 --- a/chromeos/crosapi/mojom/web_app_types_mojom_traits.cc +++ b/chromeos/crosapi/mojom/web_app_types_mojom_traits.cc
@@ -192,6 +192,8 @@ return crosapi::mojom::WebAppUninstallResultCode::kCancelled; case webapps::UninstallResultCode::kError: return crosapi::mojom::WebAppUninstallResultCode::kError; + case webapps::UninstallResultCode::kShutdown: + return crosapi::mojom::WebAppUninstallResultCode::kShutdown; }; } @@ -212,6 +214,9 @@ case crosapi::mojom::WebAppUninstallResultCode::kError: *output = webapps::UninstallResultCode::kError; return true; + case crosapi::mojom::WebAppUninstallResultCode::kShutdown: + *output = webapps::UninstallResultCode::kShutdown; + return true; }; NOTREACHED();
diff --git a/components/exo/buffer_unittest.cc b/components/exo/buffer_unittest.cc index b45c219..c46831a3 100644 --- a/components/exo/buffer_unittest.cc +++ b/components/exo/buffer_unittest.cc
@@ -7,6 +7,7 @@ #include <GLES2/gl2extchromium.h> #include "base/barrier_closure.h" +#include "base/functional/callback_helpers.h" #include "base/run_loop.h" #include "base/test/bind.h" #include "base/test/scoped_feature_list.h" @@ -82,6 +83,29 @@ ri->VerifySyncTokensCHROMIUM(sync_tokens.data(), sync_tokens.size()); } +viz::CompositorFrame CreateCompositorFrame( + SurfaceTreeHost* surface_tree_host, + const gfx::Rect& output_rect, + const gfx::Rect& damage_rect, + std::vector<viz::TransferableResource> resources) { + viz::CompositorFrame frame; + frame.metadata.begin_frame_ack.frame_id = + viz::BeginFrameId(viz::BeginFrameArgs::kManualSourceId, + viz::BeginFrameArgs::kStartingFrameNumber); + frame.metadata.begin_frame_ack.has_damage = true; + frame.metadata.frame_token = surface_tree_host->GenerateNextFrameToken(); + frame.metadata.device_scale_factor = 1; + auto pass = viz::CompositorRenderPass::Create(); + pass->SetNew(viz::CompositorRenderPassId{1}, output_rect, damage_rect, + gfx::Transform()); + frame.render_pass_list.push_back(std::move(pass)); + frame.resource_list = std::move(resources); + if (!frame.resource_list.empty()) { + VerifySyncTokensInCompositorFrame(&frame); + } + return frame; +} + // Instantiate the values of disabling/enabling reactive frame submission in the // parameterized tests. INSTANTIATE_TEST_SUITE_P(All, BufferTest, testing::Values(false, true)); @@ -311,24 +335,10 @@ ASSERT_TRUE(rv); // Submit frame with resource. - { - viz::CompositorFrame frame; - frame.metadata.begin_frame_ack.frame_id.source_id = - viz::BeginFrameArgs::kManualSourceId; - frame.metadata.begin_frame_ack.frame_id.sequence_number = - viz::BeginFrameArgs::kStartingFrameNumber; - frame.metadata.begin_frame_ack.has_damage = true; - frame.metadata.frame_token = shell_surface->GenerateNextFrameToken(); - frame.metadata.device_scale_factor = 1; - auto pass = viz::CompositorRenderPass::Create(); - pass->SetNew(viz::CompositorRenderPassId{1}, gfx::Rect(buffer_size), - gfx::Rect(buffer_size), gfx::Transform()); - frame.render_pass_list.push_back(std::move(pass)); - frame.resource_list.push_back(resource); - VerifySyncTokensInCompositorFrame(&frame); - shell_surface->SubmitCompositorFrameForTesting(std::move(frame)); - test::WaitForLastFrameAck(shell_surface.get()); - } + shell_surface->SubmitCompositorFrameForTesting( + CreateCompositorFrame(shell_surface.get(), gfx::Rect(buffer_size), + gfx::Rect(buffer_size), {resource})); + test::WaitForLastFrameAck(shell_surface.get()); buffer->OnDetach(); @@ -386,20 +396,9 @@ // Submit frame with resource. { - viz::CompositorFrame frame; - frame.metadata.begin_frame_ack.frame_id = - viz::BeginFrameId(viz::BeginFrameArgs::kManualSourceId, - viz::BeginFrameArgs::kStartingFrameNumber); - frame.metadata.begin_frame_ack.has_damage = true; - frame.metadata.frame_token = shell_surface->GenerateNextFrameToken(); - frame.metadata.device_scale_factor = 1; - auto pass = viz::CompositorRenderPass::Create(); - pass->SetNew(viz::CompositorRenderPassId{1}, gfx::Rect(buffer_size), - gfx::Rect(buffer_size), gfx::Transform()); - frame.render_pass_list.push_back(std::move(pass)); - frame.resource_list.push_back(resource); - VerifySyncTokensInCompositorFrame(&frame); - shell_surface->SubmitCompositorFrameForTesting(std::move(frame)); + shell_surface->SubmitCompositorFrameForTesting( + CreateCompositorFrame(shell_surface.get(), gfx::Rect(buffer_size), + gfx::Rect(buffer_size), {resource})); test::WaitForLastFrameAck(shell_surface.get()); // Try to release buffer in last frame. This can happen during a resize @@ -423,20 +422,8 @@ ASSERT_EQ(release_resource_count, 0); // Submit frame without resource. This should cause buffer to be released. - { - viz::CompositorFrame frame; - frame.metadata.begin_frame_ack.frame_id = - viz::BeginFrameId(viz::BeginFrameArgs::kManualSourceId, - viz::BeginFrameArgs::kStartingFrameNumber); - frame.metadata.begin_frame_ack.has_damage = true; - frame.metadata.frame_token = shell_surface->GenerateNextFrameToken(); - frame.metadata.device_scale_factor = 1; - auto pass = viz::CompositorRenderPass::Create(); - pass->SetNew(viz::CompositorRenderPassId{1}, gfx::Rect(buffer_size), - gfx::Rect(buffer_size), gfx::Transform()); - frame.render_pass_list.push_back(std::move(pass)); - shell_surface->SubmitCompositorFrameForTesting(std::move(frame)); - } + shell_surface->SubmitCompositorFrameForTesting(CreateCompositorFrame( + shell_surface.get(), gfx::Rect(buffer_size), gfx::Rect(buffer_size), {})); run_loop.Run(); // Release() should have been called exactly once. @@ -444,5 +431,321 @@ ASSERT_EQ(release_resource_count, 1); } +// Tests that only apply if ExoReactiveFrameSubmission is enabled. +class ReactiveFrameSubmissionBufferTest : public test::ExoTestBase { + public: + ReactiveFrameSubmissionBufferTest() + : test::ExoTestBase(base::test::TaskEnvironment::TimeSource::MOCK_TIME) { + feature_list_.InitAndEnableFeature(kExoReactiveFrameSubmission); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + +class TestLayerTreeFrameSinkHolder : public LayerTreeFrameSinkHolder { + public: + TestLayerTreeFrameSinkHolder( + SurfaceTreeHost* surface_tree_host, + std::unique_ptr<cc::LayerTreeFrameSink> frame_sink) + : LayerTreeFrameSinkHolder(surface_tree_host, std::move(frame_sink)) {} + ~TestLayerTreeFrameSinkHolder() override = default; + + using PreReclaimCallback = + base::RepeatingCallback<void(const std::vector<viz::ReturnedResource>&)>; + void set_pre_reclaim_callback(PreReclaimCallback callback) { + pre_reclaim_callback_ = std::move(callback); + } + + void set_post_reclaim_callback(base::RepeatingClosure callback) { + post_reclaim_callback_ = std::move(callback); + } + + void ReclaimResources(std::vector<viz::ReturnedResource> resources) override { + if (pre_reclaim_callback_) { + pre_reclaim_callback_.Run(resources); + } + + LayerTreeFrameSinkHolder::ReclaimResources(std::move(resources)); + + if (post_reclaim_callback_) { + post_reclaim_callback_.Run(); + } + } + + private: + PreReclaimCallback pre_reclaim_callback_; + base::RepeatingClosure post_reclaim_callback_; +}; + +TEST_F(ReactiveFrameSubmissionBufferTest, + SurfaceTreeHostNotReclaimCachedFrameResources) { + gfx::Size buffer_size(256, 256); + + auto shell_surface = + test::ShellSurfaceBuilder(buffer_size).SetNoCommit().BuildShellSurface(); + test::SetLayerTreeFrameSinkHolderFactory<TestLayerTreeFrameSinkHolder>( + shell_surface.get()); + shell_surface->root_surface()->Commit(); + test::WaitForLastFrameAck(shell_surface.get()); + + TestLayerTreeFrameSinkHolder* frame_sink_holder = + static_cast<TestLayerTreeFrameSinkHolder*>( + shell_surface->layer_tree_frame_sink_holder()); + + auto buffer = std::make_unique<Buffer>( + exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)); + + // Remove wait time for efficiency. + buffer->set_wait_for_release_delay_for_testing(base::TimeDelta()); + + int release_call_count = 0; + + base::RunLoop run_loop1; + auto combined_quit_closure = BarrierClosure(2, run_loop1.QuitClosure()); + + buffer->set_release_callback( + CreateReleaseBufferClosure(&release_call_count, combined_quit_closure)); + + buffer->OnAttach(); + viz::TransferableResource resource; + // Produce a transferable resource for the contents of the buffer. + int release_resource_count = 0; + bool rv = buffer->ProduceTransferableResource( + frame_sink_holder->resource_manager(), nullptr, false, &resource, + gfx::ColorSpace::CreateSRGB(), nullptr, + CreateExplicitReleaseCallback(&release_resource_count, + combined_quit_closure)); + ASSERT_TRUE(rv); + + // Submit frame with `resource`. + shell_surface->SubmitCompositorFrameForTesting( + CreateCompositorFrame(shell_surface.get(), gfx::Rect(buffer_size), + gfx::Rect(buffer_size), {resource})); + test::WaitForLastFrameAck(shell_surface.get()); + + base::RunLoop run_loop2; + // Set a callback that will be called when the remote side notify + // ReclaimResources for `resource`. + frame_sink_holder->set_pre_reclaim_callback(base::BindLambdaForTesting( + [&](const std::vector<viz::ReturnedResource>& resources) { + // Skip if it is not a notification for reclaiming `resource`. + if (!base::Contains( + resources, resource.id, + [](const viz::ReturnedResource& r) { return r.id; })) { + return; + } + + run_loop2.Quit(); + // Make sure that this callback is only used once. + frame_sink_holder->set_pre_reclaim_callback({}); + + frame_sink_holder->ClearPendingBeginFramesForTesting(); + // Cause a frame with `resource` is cached. This should hold off + // reclaming `resource`. + shell_surface->SubmitCompositorFrameForTesting( + CreateCompositorFrame(shell_surface.get(), gfx::Rect(buffer_size), + gfx::Rect(buffer_size), {resource})); + })); + + // Submit a new frame without resource to cause the remote side to stop using + // `resource` and notify ReclaimResources. The callback set by + // set_pre_reclaim_callback() above should be run as a result. + shell_surface->SubmitCompositorFrameForTesting(CreateCompositorFrame( + shell_surface.get(), gfx::Rect(buffer_size), gfx::Rect(buffer_size), {})); + run_loop2.Run(); + + // Ensure the cached frame is submitted. + test::WaitForLastFrameAck(shell_surface.get()); + + // We expect that Release() is not called, no matter whether we have a wait + // here or how long the wait is. An arbitrary time period is added here so + // that if the event mistakenly happens, it is more likely to find out. + task_environment()->FastForwardBy(base::Seconds(1)); + + // Release() should not have been called. + ASSERT_EQ(release_call_count, 0); + ASSERT_EQ(release_resource_count, 0); + + buffer->OnDetach(); + + // Submit a new frame without resource. This will cause buffer to be released. + shell_surface->SubmitCompositorFrameForTesting(CreateCompositorFrame( + shell_surface.get(), gfx::Rect(buffer_size), gfx::Rect(buffer_size), {})); + + run_loop1.Run(); + // Release() should have been called exactly once. + ASSERT_EQ(release_call_count, 1); + ASSERT_EQ(release_resource_count, 1); +} + +TEST_F(ReactiveFrameSubmissionBufferTest, + SurfaceTreeHostDiscardFrameNotReclaimNewFrameResources) { + gfx::Size buffer_size(256, 256); + + auto shell_surface = + test::ShellSurfaceBuilder(buffer_size).BuildShellSurface(); + test::WaitForLastFrameAck(shell_surface.get()); + + LayerTreeFrameSinkHolder* frame_sink_holder = + shell_surface->layer_tree_frame_sink_holder(); + + auto buffer = std::make_unique<Buffer>( + exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)); + + // Remove wait time for efficiency. + buffer->set_wait_for_release_delay_for_testing(base::TimeDelta()); + + int release_call_count = 0; + + base::RunLoop run_loop; + auto combined_quit_closure = BarrierClosure(2, run_loop.QuitClosure()); + + buffer->set_release_callback( + CreateReleaseBufferClosure(&release_call_count, combined_quit_closure)); + + buffer->OnAttach(); + viz::TransferableResource resource; + // Produce a transferable resource for the contents of the buffer. + int release_resource_count = 0; + bool rv = buffer->ProduceTransferableResource( + frame_sink_holder->resource_manager(), nullptr, false, &resource, + gfx::ColorSpace::CreateSRGB(), nullptr, + CreateExplicitReleaseCallback(&release_resource_count, + combined_quit_closure)); + ASSERT_TRUE(rv); + + frame_sink_holder->ClearPendingBeginFramesForTesting(); + + // Submit a frame with `resource`, which will be cached. + shell_surface->SubmitCompositorFrameForTesting( + CreateCompositorFrame(shell_surface.get(), gfx::Rect(buffer_size), + gfx::Rect(buffer_size), {resource})); + + // Submit another frame with `resource`. It will cause the previously cached + // frame to be evicted. + shell_surface->SubmitCompositorFrameForTesting( + CreateCompositorFrame(shell_surface.get(), gfx::Rect(buffer_size), + gfx::Rect(buffer_size), {resource})); + + buffer->OnDetach(); + + // Ensure the cached frame is submitted. + test::WaitForLastFrameAck(shell_surface.get()); + + // We expect that Release() is not called, no matter whether we have a wait + // here or how long the wait is. An arbitrary time period is added here so + // that if the event mistakenly happens, it is more likely to find out. + task_environment()->FastForwardBy(base::Seconds(1)); + + // Release() should not have been called. + ASSERT_EQ(release_call_count, 0); + ASSERT_EQ(release_resource_count, 0); + + // Submit another frame without resource. + shell_surface->SubmitCompositorFrameForTesting(CreateCompositorFrame( + shell_surface.get(), gfx::Rect(buffer_size), gfx::Rect(buffer_size), {})); + test::WaitForLastFrameAck(shell_surface.get()); + + run_loop.Run(); + + // Release() should have been called exactly once. + ASSERT_EQ(release_call_count, 1); + ASSERT_EQ(release_resource_count, 1); +} + +TEST_F(ReactiveFrameSubmissionBufferTest, + SurfaceTreeHostDiscardFrameNotReclaimInUseResources) { + gfx::Size buffer_size(256, 256); + + auto shell_surface = + test::ShellSurfaceBuilder(buffer_size).SetNoCommit().BuildShellSurface(); + test::SetLayerTreeFrameSinkHolderFactory<TestLayerTreeFrameSinkHolder>( + shell_surface.get()); + shell_surface->root_surface()->Commit(); + test::WaitForLastFrameAck(shell_surface.get()); + + TestLayerTreeFrameSinkHolder* frame_sink_holder = + static_cast<TestLayerTreeFrameSinkHolder*>( + shell_surface->layer_tree_frame_sink_holder()); + + auto buffer = std::make_unique<Buffer>( + exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)); + + // Remove wait time for efficiency. + buffer->set_wait_for_release_delay_for_testing(base::TimeDelta()); + + int release_call_count = 0; + + base::RunLoop run_loop1; + auto combined_quit_closure = BarrierClosure(2, run_loop1.QuitClosure()); + + buffer->set_release_callback( + CreateReleaseBufferClosure(&release_call_count, combined_quit_closure)); + + buffer->OnAttach(); + viz::TransferableResource resource; + // Produce a transferable resource for the contents of the buffer. + int release_resource_count = 0; + bool rv = buffer->ProduceTransferableResource( + frame_sink_holder->resource_manager(), nullptr, false, &resource, + gfx::ColorSpace::CreateSRGB(), nullptr, + CreateExplicitReleaseCallback(&release_resource_count, + combined_quit_closure)); + ASSERT_TRUE(rv); + + // Submit frame with `resource`. + shell_surface->SubmitCompositorFrameForTesting( + CreateCompositorFrame(shell_surface.get(), gfx::Rect(buffer_size), + gfx::Rect(buffer_size), {resource})); + test::WaitForLastFrameAck(shell_surface.get()); + + base::RunLoop run_loop2; + // Set a callback that will be called when the remote side notify + // ReclaimResources for `resource`. + frame_sink_holder->set_pre_reclaim_callback(base::BindLambdaForTesting( + [&](const std::vector<viz::ReturnedResource>& resources) { + // Skip if it is not a notification for reclaiming `resource`. + if (!base::Contains( + resources, resource.id, + [](const viz::ReturnedResource& r) { return r.id; })) { + return; + } + + run_loop2.Quit(); + // Make sure that this callback is only used once. + frame_sink_holder->set_pre_reclaim_callback({}); + + // The evicted cached frame with `resource` shouldn't have caused + // Release() to be called. + ASSERT_EQ(release_call_count, 0); + ASSERT_EQ(release_resource_count, 0); + })); + + frame_sink_holder->ClearPendingBeginFramesForTesting(); + + // Cause a frame with `resource` is cached. + shell_surface->SubmitCompositorFrameForTesting( + CreateCompositorFrame(shell_surface.get(), gfx::Rect(buffer_size), + gfx::Rect(buffer_size), {resource})); + + buffer->OnDetach(); + + // Submit a new frame without resource to evict the previously cached frame. + // It shouldn't cause `resource` to be reclaimed because it is still in use at + // the remote side. + shell_surface->SubmitCompositorFrameForTesting(CreateCompositorFrame( + shell_surface.get(), gfx::Rect(buffer_size), gfx::Rect(buffer_size), {})); + + // Wait for the remote site to notify ReclaimResources for `resource`. + run_loop2.Run(); + + run_loop1.Run(); + + // Release() should have been called exactly once. + ASSERT_EQ(release_call_count, 1); + ASSERT_EQ(release_resource_count, 1); +} + } // namespace } // namespace exo
diff --git a/components/exo/layer_tree_frame_sink_holder.cc b/components/exo/layer_tree_frame_sink_holder.cc index 40a2cc2..cea0bf6 100644 --- a/components/exo/layer_tree_frame_sink_holder.cc +++ b/components/exo/layer_tree_frame_sink_holder.cc
@@ -36,7 +36,7 @@ } LayerTreeFrameSinkHolder::~LayerTreeFrameSinkHolder() { - DiscardCachedFrame(); + DiscardCachedFrame(nullptr); if (frame_sink_) frame_sink_->DetachFromClient(); @@ -103,7 +103,7 @@ frame_timing_history_->MayRecordDidNotProduceToFrameArrvial(/*valid=*/true); - DiscardCachedFrame(); + DiscardCachedFrame(&frame); if (!ShouldSubmitFrameNow()) { cached_frame_ = std::move(frame); @@ -148,6 +148,17 @@ if (base::Contains(last_frame_resources_, resource.id)) { continue; } + in_use_resources_.erase(resource.id); + + // Skip resources that are also in the cached frame. + if (cached_frame_ && + base::Contains(cached_frame_->resource_list, resource.id, + [](const viz::TransferableResource& resource) { + return resource.id; + })) { + continue; + } + resource_manager_.ReclaimResource(std::move(resource)); } @@ -204,6 +215,7 @@ StopProcessingPendingFrames(); last_frame_resources_.clear(); + in_use_resources_.clear(); resource_manager_.ClearAllCallbacks(); is_lost_ = true; @@ -211,6 +223,12 @@ ScheduleDelete(); } +void LayerTreeFrameSinkHolder::ClearPendingBeginFramesForTesting() { + while (!pending_begin_frames_.empty()) { + OnSendDeadlineExpired(/*update_timer=*/false); + }; +} + //////////////////////////////////////////////////////////////////////////////// // LayerTreeFrameSinkHolder, private: @@ -281,6 +299,7 @@ last_frame_resources_.clear(); for (auto& resource : frame->resource_list) { last_frame_resources_.push_back(resource.id); + in_use_resources_.insert(resource.id); } frame_sink_->SubmitCompositorFrame(std::move(*frame), /*hit_test_data_changed=*/true); @@ -288,7 +307,8 @@ pending_submit_frames_++; } -void LayerTreeFrameSinkHolder::DiscardCachedFrame() { +void LayerTreeFrameSinkHolder::DiscardCachedFrame( + const viz::CompositorFrame* new_frame) { if (!cached_frame_) { return; } @@ -296,6 +316,19 @@ DCHECK(reactive_frame_submission_); for (const auto& resource : cached_frame_->resource_list) { + // Skip if the resource is still in use by the remote side. + if (in_use_resources_.contains(resource.id)) { + continue; + } + + // Skip if the resource is also in `new_frame`. + if (new_frame && + base::Contains(new_frame->resource_list, resource.id, + [](const viz::TransferableResource& resource) { + return resource.id; + })) { + continue; + } resource_manager_.ReclaimResource(resource.ToReturnedResource()); } @@ -328,7 +361,7 @@ } void LayerTreeFrameSinkHolder::StopProcessingPendingFrames() { - DiscardCachedFrame(); + DiscardCachedFrame(nullptr); pending_begin_frames_ = {}; UpdateSubmitFrameTimer(); }
diff --git a/components/exo/layer_tree_frame_sink_holder.h b/components/exo/layer_tree_frame_sink_holder.h index 829279d..d4dc50c 100644 --- a/components/exo/layer_tree_frame_sink_holder.h +++ b/components/exo/layer_tree_frame_sink_holder.h
@@ -89,6 +89,8 @@ const gfx::Rect& viewport_rect, const gfx::Transform& transform) override {} + void ClearPendingBeginFramesForTesting(); + private: struct PendingBeginFrame { viz::BeginFrameAck begin_frame_ack; @@ -108,7 +110,7 @@ // Discards `cached_frame_`, reclaims resources and returns failure // presentation feedback. - void DiscardCachedFrame(); + void DiscardCachedFrame(const viz::CompositorFrame* new_frame); void SendDiscardedFrameNotifications(uint32_t frame_token); void StopProcessingPendingFrames(); @@ -134,6 +136,9 @@ absl::optional<viz::CompositorFrame> cached_frame_; + // Resources that are submitted and still in use by the remote side. + std::set<viz::ResourceId> in_use_resources_; + bool is_lost_ = false; bool delete_pending_ = false;
diff --git a/components/exo/surface_tree_host.cc b/components/exo/surface_tree_host.cc index dcfbffdd..6359e44 100644 --- a/components/exo/surface_tree_host.cc +++ b/components/exo/surface_tree_host.cc
@@ -103,7 +103,10 @@ SurfaceTreeHost::SurfaceTreeHost(const std::string& window_name) : host_window_( std::make_unique<aura::Window>(nullptr, - aura::client::WINDOW_TYPE_CONTROL)) { + aura::client::WINDOW_TYPE_CONTROL)), + frame_sink_holder_factory_( + base::BindRepeating(&SurfaceTreeHost::CreateLayerTreeFrameSinkHolder, + base::Unretained(this))) { InitHostWindow(window_name); context_provider_ = aura::Env::GetInstance() ->context_factory() @@ -208,6 +211,14 @@ InitHostWindow(window_name); } +void SurfaceTreeHost::SetLayerTreeFrameSinkHolderFactoryForTesting( + LayerTreeFrameSinkHolderFactory frame_sink_holder_factory) { + DCHECK(frame_callbacks_.empty() && active_presentation_callbacks_.empty()); + + frame_sink_holder_factory_ = std::move(frame_sink_holder_factory); + layer_tree_frame_sink_holder_ = frame_sink_holder_factory_.Run(); +} + //////////////////////////////////////////////////////////////////////////////// // SurfaceDelegate overrides: @@ -423,8 +434,7 @@ host_window_->SetEventTargetingPolicy( aura::EventTargetingPolicy::kDescendantsOnly); host_window_->SetEventTargeter(std::make_unique<CustomWindowTargeter>(this)); - layer_tree_frame_sink_holder_ = std::make_unique<LayerTreeFrameSinkHolder>( - this, host_window_->CreateLayerTreeFrameSink()); + layer_tree_frame_sink_holder_ = frame_sink_holder_factory_.Run(); } viz::CompositorFrame SurfaceTreeHost::PrepareToSubmitCompositorFrame() { @@ -433,8 +443,7 @@ if (layer_tree_frame_sink_holder_->is_lost()) { // We can immediately delete the old LayerTreeFrameSinkHolder because all of // it's resources are lost anyways. - layer_tree_frame_sink_holder_ = std::make_unique<LayerTreeFrameSinkHolder>( - this, host_window_->CreateLayerTreeFrameSink()); + layer_tree_frame_sink_holder_ = frame_sink_holder_factory_.Run(); CleanUpCallbacks(); } @@ -526,4 +535,10 @@ active_presentation_callbacks_.clear(); } +std::unique_ptr<LayerTreeFrameSinkHolder> +SurfaceTreeHost::CreateLayerTreeFrameSinkHolder() { + return std::make_unique<LayerTreeFrameSinkHolder>( + this, host_window_->CreateLayerTreeFrameSink()); +} + } // namespace exo
diff --git a/components/exo/surface_tree_host.h b/components/exo/surface_tree_host.h index 3fd1035..be6b6635 100644 --- a/components/exo/surface_tree_host.h +++ b/components/exo/surface_tree_host.h
@@ -147,6 +147,14 @@ void SetHostWindowForTesting(std::unique_ptr<aura::Window> test_host_window, const std::string& window_name); + using LayerTreeFrameSinkHolderFactory = + base::RepeatingCallback<std::unique_ptr<LayerTreeFrameSinkHolder>()>; + + // It should only be used at initialization time before any frames are + // submitted. + void SetLayerTreeFrameSinkHolderFactoryForTesting( + LayerTreeFrameSinkHolderFactory frame_sink_holder_factory); + protected: void UpdateDisplayOnTree(); @@ -189,6 +197,8 @@ void CleanUpCallbacks(); + std::unique_ptr<LayerTreeFrameSinkHolder> CreateLayerTreeFrameSinkHolder(); + raw_ptr<Surface, ExperimentalAsh> root_surface_ = nullptr; // Position of root surface relative to topmost, leftmost sub-surface. The @@ -197,6 +207,7 @@ std::unique_ptr<aura::Window> host_window_; std::unique_ptr<LayerTreeFrameSinkHolder> layer_tree_frame_sink_holder_; + LayerTreeFrameSinkHolderFactory frame_sink_holder_factory_; // This queue contains lists the callbacks to notify the client when it is a // good time to start producing a new frame. Each list corresponds to a
diff --git a/components/exo/surface_unittest.cc b/components/exo/surface_unittest.cc index e7f0b63..43ab364 100644 --- a/components/exo/surface_unittest.cc +++ b/components/exo/surface_unittest.cc
@@ -1822,10 +1822,8 @@ surface->Attach(buffer.get()); - // This commit will ensure that if there is already a pending BeginFrame - // request, it is responded and cleared. - surface->Damage(gfx::Rect(0, 0, 10, 10)); - surface->Commit(); + shell_surface->layer_tree_frame_sink_holder() + ->ClearPendingBeginFramesForTesting(); // This will result in a cached frame in LayerTreeFrameSinkHolder. surface->Damage(gfx::Rect(10, 10, 10, 10));
diff --git a/components/exo/test/surface_tree_host_test_util.h b/components/exo/test/surface_tree_host_test_util.h index 90a8ca14..f888508 100644 --- a/components/exo/test/surface_tree_host_test_util.h +++ b/components/exo/test/surface_tree_host_test_util.h
@@ -5,6 +5,7 @@ #ifndef COMPONENTS_EXO_TEST_SURFACE_TREE_HOST_TEST_UTIL_H_ #define COMPONENTS_EXO_TEST_SURFACE_TREE_HOST_TEST_UTIL_H_ +#include "base/test/bind.h" #include "components/exo/surface_tree_host.h" namespace exo::test { @@ -17,6 +18,17 @@ // presented. void WaitForLastFramePresentation(SurfaceTreeHost* surface_tree_host); +template <class LayerTreeFrameSinkHolderType> +void SetLayerTreeFrameSinkHolderFactory(SurfaceTreeHost* surface_tree_host) { + surface_tree_host->SetLayerTreeFrameSinkHolderFactoryForTesting( + base::BindLambdaForTesting( + [surface_tree_host]() -> std::unique_ptr<LayerTreeFrameSinkHolder> { + return std::make_unique<LayerTreeFrameSinkHolderType>( + surface_tree_host, + surface_tree_host->host_window()->CreateLayerTreeFrameSink()); + })); +} + } // namespace exo::test #endif // COMPONENTS_EXO_TEST_SURFACE_TREE_HOST_TEST_UTIL_H_
diff --git a/components/optimization_guide/core/model_util.cc b/components/optimization_guide/core/model_util.cc index a5489bc..f805170 100644 --- a/components/optimization_guide/core/model_util.cc +++ b/components/optimization_guide/core/model_util.cc
@@ -96,6 +96,8 @@ return "SegmentationAdaptiveToolbar"; case proto::OPTIMIZATION_TARGET_SEGMENTATION_TABLET_PRODUCTIVITY_USER: return "SegmentationTabletProductivityUser"; + case proto::OPTIMIZATION_TARGET_CLIENT_SIDE_PHISHING_IMAGE_EMBEDDER: + return "ClientSidePhishingImageEmbedder"; case proto:: OPTIMIZATION_TARGET_NEW_TAB_PAGE_HISTORY_CLUSTERS_MODULE_RANKING: return "NewTabPageHistoryClustersModuleRanking";
diff --git a/components/optimization_guide/core/prediction_manager.cc b/components/optimization_guide/core/prediction_manager.cc index daeabf6..38dfdad 100644 --- a/components/optimization_guide/core/prediction_manager.cc +++ b/components/optimization_guide/core/prediction_manager.cc
@@ -171,7 +171,11 @@ model_metadata.type_url() == "type.googleapis.com/" "google.privacy.webpermissionpredictions.v1." - "WebPermissionPredictionsModelMetadata"; + "WebPermissionPredictionsModelMetadata" || + model_metadata.type_url() == + "type.googleapis.com/" + "google.internal.chrome.optimizationguide.v1." + "ClientSidePhishingModelMetadata"; } void RecordModelAvailableAtRegistration(
diff --git a/components/optimization_guide/proto/BUILD.gn b/components/optimization_guide/proto/BUILD.gn index 2eb2d11..a77dbeb 100644 --- a/components/optimization_guide/proto/BUILD.gn +++ b/components/optimization_guide/proto/BUILD.gn
@@ -12,6 +12,7 @@ proto_in_dir = "//" sources = [ "autocomplete_scoring_model_metadata.proto", + "client_side_phishing_model_metadata.proto", "common_types.proto", "hint_cache.proto", "hints.proto",
diff --git a/components/optimization_guide/proto/client_side_phishing_model_metadata.proto b/components/optimization_guide/proto/client_side_phishing_model_metadata.proto new file mode 100644 index 0000000..c20a5bf --- /dev/null +++ b/components/optimization_guide/proto/client_side_phishing_model_metadata.proto
@@ -0,0 +1,17 @@ +// 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. + +syntax = "proto3"; + +option optimize_for = LITE_RUNTIME; +option java_package = "org.chromium.components.optimization_guide.proto"; +option java_outer_classname = "ClientSidePhishingModelMetadataProto"; + +package optimization_guide.proto; + +// The message contains an integer to pair with a client side phishing image +// embedding model which will also have an integer to match. +message ClientSidePhishingModelMetadata { + optional int32 image_embedding_model_version = 1; +}
diff --git a/components/optimization_guide/proto/models.proto b/components/optimization_guide/proto/models.proto index 0036d8e2..7b469171 100644 --- a/components/optimization_guide/proto/models.proto +++ b/components/optimization_guide/proto/models.proto
@@ -122,7 +122,7 @@ // The scenarios for which the optimization guide has models for. enum OptimizationTarget { - reserved 14, 30; + reserved 14; OPTIMIZATION_TARGET_UNKNOWN = 0; // Should only be applied when the page load is predicted to be painful. @@ -183,6 +183,8 @@ OPTIMIZATION_TARGET_SEGMENTATION_ADAPTIVE_TOOLBAR = 28; // Target for segmentation: Determine users who are tabletproductivity users. OPTIMIZATION_TARGET_SEGMENTATION_TABLET_PRODUCTIVITY_USER = 29; + // Target for client side phishing image embedding model. + OPTIMIZATION_TARGET_CLIENT_SIDE_PHISHING_IMAGE_EMBEDDER = 30; // Target for ranking clusters that have passed minimal filtering for the New // Tab Page History Clusters module. OPTIMIZATION_TARGET_NEW_TAB_PAGE_HISTORY_CLUSTERS_MODULE_RANKING = 31;
diff --git a/components/safe_browsing/content/browser/client_side_detection_service.cc b/components/safe_browsing/content/browser/client_side_detection_service.cc index 89abbe4..5b276342 100644 --- a/components/safe_browsing/content/browser/client_side_detection_service.cc +++ b/components/safe_browsing/content/browser/client_side_detection_service.cc
@@ -158,6 +158,16 @@ base::BindRepeating( &ClientSideDetectionService::SendModelToRenderers, weak_factory_.GetWeakPtr())); + if (base::FeatureList::IsEnabled( + kClientSideDetectionModelImageEmbedder)) { + if (IsEnhancedProtectionEnabled(*delegate_->GetPrefs())) { + client_side_phishing_model_optimization_guide_ + ->SubscribeToImageEmbedderOptimizationGuide(); + send_image_embedding_model_to_renderer_ = true; + } else { + send_image_embedding_model_to_renderer_ = false; + } + } } } } else { @@ -509,6 +519,24 @@ return ClientSidePhishingModel::GetInstance()->GetVisualTfLiteModel(); } +const base::File& ClientSideDetectionService::GetImageEmbeddingModel() { + // At launch, we will only deploy the Image Embedding Model through + // OptimizationGuide + return client_side_phishing_model_optimization_guide_ + ->GetImageEmbeddingModel(); +} + +bool ClientSideDetectionService::HasImageEmbeddingModel() { + return client_side_phishing_model_optimization_guide_ + ->HasImageEmbeddingModel(); +} + +bool ClientSideDetectionService:: + IsModelMetadataImageEmbeddingVersionMatching() { + return client_side_phishing_model_optimization_guide_ + ->IsModelMetadataImageEmbeddingVersionMatching(); +} + void ClientSideDetectionService::SetURLLoaderFactoryForTesting( scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) { url_loader_factory_ = url_loader_factory; @@ -533,8 +561,28 @@ GetVisualTfLiteModel().Duplicate()); return; case CSDModelType::kFlatbuffer: - model_setter->SetPhishingFlatBufferModel( - GetModelSharedMemoryRegion(), GetVisualTfLiteModel().Duplicate()); + if (delegate_ && delegate_->GetPrefs() && + IsEnhancedProtectionEnabled(*delegate_->GetPrefs()) && + base::FeatureList::IsEnabled( + kClientSideDetectionModelImageEmbedder) && + ShouldSendImageEmbeddingModelToRenderer() && + HasImageEmbeddingModel()) { + if (IsModelMetadataImageEmbeddingVersionMatching()) { + base::UmaHistogramBoolean( + "SBClientPhishing.ImageEmbeddingModelVersionMatch", true); + model_setter->SetImageEmbeddingAndPhishingFlatBufferModel( + GetModelSharedMemoryRegion(), GetVisualTfLiteModel().Duplicate(), + GetImageEmbeddingModel().Duplicate()); + } else { + base::UmaHistogramBoolean( + "SBClientPhishing.ImageEmbeddingModelVersionMatch", false); + model_setter->SetPhishingFlatBufferModel( + GetModelSharedMemoryRegion(), GetVisualTfLiteModel().Duplicate()); + } + } else { + model_setter->SetPhishingFlatBufferModel( + GetModelSharedMemoryRegion(), GetVisualTfLiteModel().Duplicate()); + } return; } } @@ -629,6 +677,21 @@ } } +bool ClientSideDetectionService::IsSubscribedToImageEmbeddingModelUpdates() { + if (base::FeatureList::IsEnabled( + kClientSideDetectionModelOptimizationGuide) && + base::FeatureList::IsEnabled(kClientSideDetectionModelImageEmbedder)) { + return client_side_phishing_model_optimization_guide_ && + client_side_phishing_model_optimization_guide_ + ->IsSubscribedToImageEmbeddingModelUpdates(); + } + return false; +} + +bool ClientSideDetectionService::ShouldSendImageEmbeddingModelToRenderer() { + return send_image_embedding_model_to_renderer_; +} + // IN-TEST void ClientSideDetectionService::SetModelAndVisualTfLiteForTesting( const base::FilePath& model,
diff --git a/components/safe_browsing/content/browser/client_side_detection_service.h b/components/safe_browsing/content/browser/client_side_detection_service.h index 8afba77..1be0276 100644 --- a/components/safe_browsing/content/browser/client_side_detection_service.h +++ b/components/safe_browsing/content/browser/client_side_detection_service.h
@@ -163,6 +163,14 @@ // override it. virtual const base::File& GetVisualTfLiteModel(); + // Returns the Image Embedding model file. Virtual so that mock implementation + // can override it. + virtual const base::File& GetImageEmbeddingModel(); + + virtual bool HasImageEmbeddingModel(); + + virtual bool IsModelMetadataImageEmbeddingVersionMatching(); + // Returns the visual TFLite model thresholds from the model class virtual const base::flat_map<std::string, TfLiteModelMetadata::Threshold>& GetVisualTfLiteModelThresholds(); @@ -182,10 +190,13 @@ bool IsModelAvailable(); - // For testing the model in browser test + // For testing the model in browser test. void SetModelAndVisualTfLiteForTesting(const base::FilePath& model, const base::FilePath& visual_tf_lite); + bool IsSubscribedToImageEmbeddingModelUpdates(); + bool ShouldSendImageEmbeddingModelToRenderer(); + private: friend class ClientSideDetectionServiceTest; FRIEND_TEST_ALL_PREFIXES(ClientSideDetectionServiceTest, @@ -298,6 +309,16 @@ SEQUENCE_CHECKER(sequence_checker_); + // Used to note whether the model update should follow with sending the image + // embedding model to renderer, because removing the observer from + // OptimizationGuide service does not remove the observer instantaneously, + // making a user quick resubscription scenario fail a DCHECK in their service. + // We will always update the model on the disc if the user has subscribed to + // image embedding model once in their current session, but the state of this + // boolean value indicate whether the model updates will be sent to the + // renderer or not. + bool send_image_embedding_model_to_renderer_ = false; + // Used to asynchronously call the callbacks for // SendClientReportPhishingRequest. base::WeakPtrFactory<ClientSideDetectionService> weak_factory_{this};
diff --git a/components/safe_browsing/content/browser/client_side_phishing_model_optimization_guide.cc b/components/safe_browsing/content/browser/client_side_phishing_model_optimization_guide.cc index 5e513958..97d6ca0 100644 --- a/components/safe_browsing/content/browser/client_side_phishing_model_optimization_guide.cc +++ b/components/safe_browsing/content/browser/client_side_phishing_model_optimization_guide.cc
@@ -21,6 +21,8 @@ #include "base/task/thread_pool.h" #include "build/build_config.h" #include "components/optimization_guide/core/optimization_guide_model_provider.h" +#include "components/optimization_guide/core/optimization_guide_util.h" +#include "components/optimization_guide/proto/client_side_phishing_model_metadata.pb.h" #include "components/optimization_guide/proto/models.pb.h" #include "components/safe_browsing/core/common/fbs/client_model_generated.h" #include "components/safe_browsing/core/common/features.h" @@ -28,6 +30,7 @@ #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "services/network/public/cpp/shared_url_loader_factory.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace safe_browsing { @@ -70,6 +73,32 @@ std::make_pair(contents, std::move(tflite_model)))); } +base::File LoadImageEmbeddingModelFile(const base::FilePath& model_file_path) { + if (!base::PathExists(model_file_path)) { + VLOG(0) + << "Model path does not exist. Returning empty file. Given path is: " + << model_file_path; + return base::File(); + } + + base::File image_embedding_model_file( + model_file_path, base::File::FLAG_OPEN | base::File::FLAG_READ); + + bool image_embedding_model_valid = image_embedding_model_file.IsValid(); + + base::UmaHistogramBoolean( + "SBClientPhishing.ModelDynamicUpdateSuccess.ImageEmbedding", + image_embedding_model_valid); + + if (!image_embedding_model_valid) { + VLOG(2) + << "Failed to receive image embedding model file. File is not valid"; + return base::File(); + } + + return image_embedding_model_file; +} + // Load the model file at the provided file path. std::pair<std::string, base::File> LoadModelAndVisualTfLiteFile( const base::FilePath& model_file_path, @@ -144,20 +173,56 @@ const optimization_guide::ModelInfo& model_info) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (optimization_target != - optimization_guide::proto::OPTIMIZATION_TARGET_CLIENT_SIDE_PHISHING) { + optimization_guide::proto::OPTIMIZATION_TARGET_CLIENT_SIDE_PHISHING && + optimization_target != + optimization_guide::proto:: + OPTIMIZATION_TARGET_CLIENT_SIDE_PHISHING_IMAGE_EMBEDDER) { return; } - background_task_runner_->PostTaskAndReplyWithResult( - FROM_HERE, - base::BindOnce(&LoadModelAndVisualTfLiteFile, - model_info.GetModelFilePath(), - model_info.GetAdditionalFiles()), - base::BindOnce(&ClientSidePhishingModelOptimizationGuide:: - OnModelAndVisualTfLiteFileLoaded, - weak_ptr_factory_.GetWeakPtr())); + + if (optimization_target == + optimization_guide::proto::OPTIMIZATION_TARGET_CLIENT_SIDE_PHISHING) { + background_task_runner_->PostTaskAndReplyWithResult( + FROM_HERE, + base::BindOnce(&LoadModelAndVisualTfLiteFile, + model_info.GetModelFilePath(), + model_info.GetAdditionalFiles()), + base::BindOnce(&ClientSidePhishingModelOptimizationGuide:: + OnModelAndVisualTfLiteFileLoaded, + weak_ptr_factory_.GetWeakPtr(), + model_info.GetModelMetadata())); + } else if (optimization_target == + optimization_guide::proto:: + OPTIMIZATION_TARGET_CLIENT_SIDE_PHISHING_IMAGE_EMBEDDER) { + background_task_runner_->PostTaskAndReplyWithResult( + FROM_HERE, + base::BindOnce(&LoadImageEmbeddingModelFile, + model_info.GetModelFilePath()), + base::BindOnce(&ClientSidePhishingModelOptimizationGuide:: + OnImageEmbeddingModelLoaded, + weak_ptr_factory_.GetWeakPtr(), + model_info.GetModelMetadata())); + } +} + +void ClientSidePhishingModelOptimizationGuide:: + SubscribeToImageEmbedderOptimizationGuide() { + if (!subscribed_to_image_embedder_ && opt_guide_) { + subscribed_to_image_embedder_ = true; + opt_guide_->AddObserverForOptimizationTargetModel( + optimization_guide::proto:: + OPTIMIZATION_TARGET_CLIENT_SIDE_PHISHING_IMAGE_EMBEDDER, + /*model_metadata=*/absl::nullopt, this); + } +} + +bool ClientSidePhishingModelOptimizationGuide:: + IsSubscribedToImageEmbeddingModelUpdates() { + return subscribed_to_image_embedder_; } void ClientSidePhishingModelOptimizationGuide::OnModelAndVisualTfLiteFileLoaded( + absl::optional<optimization_guide::proto::Any> model_metadata, std::pair<std::string, base::File> model_and_tflite) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); @@ -243,6 +308,25 @@ base::UmaHistogramMediumTimes( "SBClientPhishing.OptimizationGuide.ModelFetchTime", base::TimeTicks::Now() - beginning_time_); + + absl::optional<optimization_guide::proto::ClientSidePhishingModelMetadata> + client_side_phishing_model_metadata = absl::nullopt; + + if (model_metadata.has_value()) { + client_side_phishing_model_metadata = + optimization_guide::ParsedAnyMetadata< + optimization_guide::proto::ClientSidePhishingModelMetadata>( + model_metadata.value()); + } + + if (client_side_phishing_model_metadata.has_value()) { + trigger_model_version_ = + client_side_phishing_model_metadata->image_embedding_model_version(); + } else { + VLOG(1) << "Client side phishing model metadata is missing an image " + "embedding model version value"; + } + content::GetUIThreadTaskRunner({})->PostTask( FROM_HERE, base::BindOnce( @@ -251,6 +335,47 @@ } } +void ClientSidePhishingModelOptimizationGuide::OnImageEmbeddingModelLoaded( + absl::optional<optimization_guide::proto::Any> model_metadata, + base::File image_embedding_model) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + image_embedding_model_ = std::move(image_embedding_model); + + absl::optional<optimization_guide::proto::ClientSidePhishingModelMetadata> + image_embedding_model_metadata = absl::nullopt; + + if (model_metadata.has_value()) { + image_embedding_model_metadata = optimization_guide::ParsedAnyMetadata< + optimization_guide::proto::ClientSidePhishingModelMetadata>( + model_metadata.value()); + } + + if (image_embedding_model_metadata.has_value()) { + embedding_model_version_ = + image_embedding_model_metadata->image_embedding_model_version(); + } else { + VLOG(1) << "Image embedding model metadata is missing a version value"; + } + + // There is no use of the image embedding model if the visual trigger model is + // not present, so we will only send to the renderer when that is the case. + if (visual_tflite_model_ && image_embedding_model_) { + content::GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, + base::BindOnce( + &ClientSidePhishingModelOptimizationGuide::NotifyCallbacksOnUI, + weak_ptr_factory_.GetWeakPtr())); + } +} + +bool ClientSidePhishingModelOptimizationGuide:: + IsModelMetadataImageEmbeddingVersionMatching() { + return trigger_model_version_.has_value() && + embedding_model_version_.has_value() && + trigger_model_version_.value() == embedding_model_version_.value(); +} + ClientSidePhishingModelOptimizationGuide:: ~ClientSidePhishingModelOptimizationGuide() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); @@ -258,13 +383,27 @@ opt_guide_->RemoveObserverForOptimizationTargetModel( optimization_guide::proto::OPTIMIZATION_TARGET_CLIENT_SIDE_PHISHING, this); - opt_guide_ = nullptr; + + if (subscribed_to_image_embedder_) { + opt_guide_->RemoveObserverForOptimizationTargetModel( + optimization_guide::proto:: + OPTIMIZATION_TARGET_CLIENT_SIDE_PHISHING_IMAGE_EMBEDDER, + this); + } if (visual_tflite_model_) { background_task_runner_->PostTask( FROM_HERE, base::BindOnce(&CloseModelFile, std::move(*visual_tflite_model_))); } + + if (image_embedding_model_) { + background_task_runner_->PostTask( + FROM_HERE, + base::BindOnce(&CloseModelFile, std::move(*image_embedding_model_))); + } + + opt_guide_ = nullptr; } base::CallbackListSubscription @@ -363,6 +502,18 @@ return *visual_tflite_model_; } +const base::File& +ClientSidePhishingModelOptimizationGuide::GetImageEmbeddingModel() const { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK(image_embedding_model_ && image_embedding_model_->IsValid()); + return *image_embedding_model_; +} + +bool ClientSidePhishingModelOptimizationGuide::HasImageEmbeddingModel() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + return !!image_embedding_model_; +} + CSDModelTypeOptimizationGuide ClientSidePhishingModelOptimizationGuide::GetModelType() const { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); @@ -590,7 +741,7 @@ additional_files), base::BindOnce(&ClientSidePhishingModelOptimizationGuide:: OnModelAndVisualTfLiteFileLoaded, - weak_ptr_factory_.GetWeakPtr())); + weak_ptr_factory_.GetWeakPtr(), absl::nullopt)); } } // namespace safe_browsing
diff --git a/components/safe_browsing/content/browser/client_side_phishing_model_optimization_guide.h b/components/safe_browsing/content/browser/client_side_phishing_model_optimization_guide.h index f2abfa4..055008d5 100644 --- a/components/safe_browsing/content/browser/client_side_phishing_model_optimization_guide.h +++ b/components/safe_browsing/content/browser/client_side_phishing_model_optimization_guide.h
@@ -59,6 +59,12 @@ optimization_guide::proto::OptimizationTarget optimization_target, const optimization_guide::ModelInfo& model_info) override; + // Enhanced Safe Browsing users receive an additional image embedding model to + // be attached to CSD-Phishing ping to better train the models. + void SubscribeToImageEmbedderOptimizationGuide(); + + void UnsubscribeToImageEmbedderOptimizationGuide(); + // Register a callback to be notified whenever the model changes. All // notifications will occur on the UI thread. base::CallbackListSubscription RegisterCallback( @@ -81,6 +87,12 @@ const base::File& GetVisualTfLiteModel() const; + const base::File& GetImageEmbeddingModel() const; + + bool HasImageEmbeddingModel(); + + bool IsModelMetadataImageEmbeddingVersionMatching(); + // Overrides the model string for use in tests. void SetModelStrForTesting(const std::string& model_str); void SetVisualTfLiteModelForTesting(base::File file); @@ -101,8 +113,13 @@ void MaybeOverrideModel(); void OnModelAndVisualTfLiteFileLoaded( + absl::optional<optimization_guide::proto::Any> model_metadata, std::pair<std::string, base::File> model_and_tflite); + void OnImageEmbeddingModelLoaded( + absl::optional<optimization_guide::proto::Any> model_metadata, + base::File image_embedding_model_data); + void SetModelAndVisualTfLiteForTesting( const base::FilePath& model_file_path, const base::FilePath& visual_tf_lite_model_path); @@ -112,6 +129,8 @@ void SetModelStringForTesting(const std::string& model_str, base::File visual_tflite_model); + bool IsSubscribedToImageEmbeddingModelUpdates(); + private: static const int kInitialClientModelFetchDelayMs; @@ -135,6 +154,10 @@ absl::optional<base::File> visual_tflite_model_ GUARDED_BY_CONTEXT(sequence_checker_); + // Image Embedding TfLite model file. Guarded by sequence_checker_. + absl::optional<base::File> image_embedding_model_ + GUARDED_BY_CONTEXT(sequence_checker_); + // Thresholds in visual TFLite model file to be used for comparison after // visual classification base::flat_map<std::string, TfLiteModelMetadata::Threshold> thresholds_; @@ -156,8 +179,24 @@ // BrowserContextKeyedServiceFactory and should not be used after Shutdown raw_ptr<optimization_guide::OptimizationGuideModelProvider> opt_guide_; + // These two integer values will be set from reading the metadata specified + // under each optimization target. These two are used to match the model + // pairings properly. If the two values match, then the image embedding model + // will be sent to the renderer process along with the trigger models. + absl::optional<int> trigger_model_version_; + absl::optional<int> embedding_model_version_; + scoped_refptr<base::SequencedTaskRunner> background_task_runner_; + // If the users subscribe to ESB, the code will add an observer to the + // OptimizationGuide service for the image embedder model. We can choose to + // remove the observer, but it will be on the list to be removed, and not + // removed instantly. Therefore, if the user subscribes, unsubscribes, and + // re-subscribes again in very quick succession, the code will crash because + // the DCHECK fails, indicating that the observer is added already. Therefore, + // this will be a one time use flag. + bool subscribed_to_image_embedder_ = false; + SEQUENCE_CHECKER(sequence_checker_); base::TimeTicks beginning_time_;
diff --git a/components/safe_browsing/content/browser/client_side_phishing_model_unittest.cc b/components/safe_browsing/content/browser/client_side_phishing_model_unittest.cc index fc873f83..ec7901a 100644 --- a/components/safe_browsing/content/browser/client_side_phishing_model_unittest.cc +++ b/components/safe_browsing/content/browser/client_side_phishing_model_unittest.cc
@@ -75,6 +75,13 @@ .SetAdditionalFiles(additional_files_path) .Build(); model_observer_->OnModelUpdated(optimization_target, *model_metadata); + } else if (optimization_target == + optimization_guide::proto:: + OPTIMIZATION_TARGET_CLIENT_SIDE_PHISHING_IMAGE_EMBEDDER) { + auto model_metadata = optimization_guide::TestModelInfoBuilder() + .SetModelFilePath(model_file_path) + .Build(); + model_observer_->OnModelUpdated(optimization_target, *model_metadata); } } @@ -84,14 +91,21 @@ raw_ptr<optimization_guide::OptimizationTargetModelObserver> model_observer_; }; -class ClientSidePhishingModelTest : public content::RenderViewHostTestHarness, - public testing::WithParamInterface<bool> { +class ClientSidePhishingModelTest + : public content::RenderViewHostTestHarness, + public testing::WithParamInterface<std::tuple<bool, bool>> { public: ClientSidePhishingModelTest() { + std::vector<base::test::FeatureRef> enabled_features = {}; if (ShouldEnableCacao()) { - feature_list_.InitAndEnableFeature( - kClientSideDetectionModelOptimizationGuide); + enabled_features.push_back(kClientSideDetectionModelOptimizationGuide); } + + if (ShouldEnableImageEmbedder()) { + enabled_features.push_back(kClientSideDetectionModelImageEmbedder); + } + + feature_list_.InitWithFeatures(enabled_features, {}); } void SetUp() override { @@ -125,13 +139,24 @@ task_environment()->RunUntilIdle(); } + void ValidateImageEmbeddingModel( + const base::FilePath& image_embedding_model_file_path) { + model_observer_tracker_->NotifyModelFileUpdate( + optimization_guide::proto:: + OPTIMIZATION_TARGET_CLIENT_SIDE_PHISHING_IMAGE_EMBEDDER, + image_embedding_model_file_path, {}); + task_environment()->RunUntilIdle(); + } + ClientSidePhishingModelOptimizationGuide* service() { return client_side_phishing_model_.get(); } base::HistogramTester& histogram_tester() { return histogram_tester_; } - bool ShouldEnableCacao() { return GetParam(); } + bool ShouldEnableCacao() { return get<0>(GetParam()); } + + bool ShouldEnableImageEmbedder() { return get<1>(GetParam()); } protected: base::test::ScopedFeatureList feature_list_; @@ -168,7 +193,9 @@ } // namespace -INSTANTIATE_TEST_SUITE_P(All, ClientSidePhishingModelTest, testing::Bool()); +INSTANTIATE_TEST_SUITE_P(All, + ClientSidePhishingModelTest, + testing::Combine(testing::Bool(), testing::Bool())); TEST_P(ClientSidePhishingModelTest, ValidModel) { if (!base::FeatureList::IsEnabled( @@ -203,6 +230,20 @@ histogram_tester().ExpectUniqueSample( "SBClientPhishing.ModelDynamicUpdateSuccess", true, 1); EXPECT_TRUE(service()->IsEnabled()); + if (base::FeatureList::IsEnabled(kClientSideDetectionModelImageEmbedder)) { + base::FilePath image_embedding_model_file_path; + base::PathService::Get(base::DIR_SOURCE_ROOT, + &image_embedding_model_file_path); + image_embedding_model_file_path = + image_embedding_model_file_path.AppendASCII("components") + .AppendASCII("test") + .AppendASCII("data") + .AppendASCII("safe_browsing") + .AppendASCII("image_embedding.tflite"); + ValidateImageEmbeddingModel(image_embedding_model_file_path); + histogram_tester().ExpectUniqueSample( + "SBClientPhishing.ModelDynamicUpdateSuccess.ImageEmbedding", true, 1); + } } TEST_P(ClientSidePhishingModelTest, InvalidModelDueToInvalidPath) {
diff --git a/components/safe_browsing/content/browser/web_ui/safe_browsing_ui.cc b/components/safe_browsing/content/browser/web_ui/safe_browsing_ui.cc index 585ea4e..a8b105d4 100644 --- a/components/safe_browsing/content/browser/web_ui/safe_browsing_ui.cc +++ b/components/safe_browsing/content/browser/web_ui/safe_browsing_ui.cc
@@ -642,6 +642,19 @@ return "UNKNOWN_ENUM_SPECIFIED"; } +base::Value::Dict SerializeImageFeatureEmbedding( + ImageFeatureEmbedding image_feature_embedding) { + base::Value::Dict dict; + base::Value::List embedding_values; + for (const auto& value : image_feature_embedding.embedding_value()) { + embedding_values.Append(value); + } + dict.Set("embedding_model_version", + image_feature_embedding.embedding_model_version()); + dict.Set("embedding_value", std::move(embedding_values)); + return dict; +} + base::Value::Dict SerializeChromeUserPopulation( const ChromeUserPopulation& population) { base::Value::Dict population_dict; @@ -1082,6 +1095,11 @@ SerializeClientSideDetectionType(cpr.client_side_detection_type())); } + if (cpr.has_image_feature_embedding()) { + dict.Set("image_feature_embedding", + SerializeImageFeatureEmbedding(cpr.image_feature_embedding())); + } + base::Value::List features; for (const auto& feature : cpr.feature_map()) { base::Value::Dict dict_features;
diff --git a/components/safe_browsing/content/common/safe_browsing.mojom b/components/safe_browsing/content/common/safe_browsing.mojom index 5a783c7..94871774 100644 --- a/components/safe_browsing/content/common/safe_browsing.mojom +++ b/components/safe_browsing/content/common/safe_browsing.mojom
@@ -142,6 +142,20 @@ // Interface for setting a phishing model. This is scoped to an entire // RenderProcess. interface PhishingModelSetter { + // A classification model for client-side phishing detection in addition to + // the image embedding model. This call sends the model and the image + // embedding model from browser process to the renderer process. The image + // embedding model is converted from a TfLite file to a string in the browser + // process to be used to create an ImageEmbedder in the renderer process. This + // function call should only be called for Enhanced Safe Browsing enabled + // users who will allow the ImageEmbedding output as part of the CSD-Phishing + // ping to be sent to CSPP for better model training. All else is the same as + // the SetPhishingFlatBufferModel function. + SetImageEmbeddingAndPhishingFlatBufferModel( + mojo_base.mojom.ReadOnlySharedMemoryRegion region, + mojo_base.mojom.ReadOnlyFile? tflite_model, + mojo_base.mojom.ReadOnlyFile? + image_embedding_model_); // A classification model for client-side phishing detection. // The string is an encoded safe_browsing::ClientSideModel protocol buffer, or // empty to disable client-side phishing detection for this renderer. The
diff --git a/components/safe_browsing/content/renderer/phishing_classifier/flatbuffer_scorer.cc b/components/safe_browsing/content/renderer/phishing_classifier/flatbuffer_scorer.cc index fa62e46..06961435 100644 --- a/components/safe_browsing/content/renderer/phishing_classifier/flatbuffer_scorer.cc +++ b/components/safe_browsing/content/renderer/phishing_classifier/flatbuffer_scorer.cc
@@ -93,6 +93,26 @@ return scorer; } +std::unique_ptr<FlatBufferModelScorer> +FlatBufferModelScorer::CreateFlatBufferModelWithImageEmbeddingScorer( + base::ReadOnlySharedMemoryRegion region, + base::File visual_tflite_model, + base::File image_embedding_model) { + std::unique_ptr<FlatBufferModelScorer> scorer = + Create(std::move(region), std::move(visual_tflite_model)); + + if (image_embedding_model.IsValid()) { + if (scorer && !scorer->image_embedding_model_.Initialize( + std::move(image_embedding_model))) { + RecordScorerCreationStatus( + SCORER_FAIL_FLATBUFFER_INVALID_IMAGE_EMBEDDING_TFLITE_MODEL); + return nullptr; + } + } + + return scorer; +} + double FlatBufferModelScorer::ComputeRuleScore( const flat::ClientSideModel_::Rule* rule, const FeatureMap& features) const {
diff --git a/components/safe_browsing/content/renderer/phishing_classifier/flatbuffer_scorer.h b/components/safe_browsing/content/renderer/phishing_classifier/flatbuffer_scorer.h index 5a76abba..1f88fde 100644 --- a/components/safe_browsing/content/renderer/phishing_classifier/flatbuffer_scorer.h +++ b/components/safe_browsing/content/renderer/phishing_classifier/flatbuffer_scorer.h
@@ -47,6 +47,12 @@ base::ReadOnlySharedMemoryRegion region, base::File visual_tflite_model); + static std::unique_ptr<FlatBufferModelScorer> + CreateFlatBufferModelWithImageEmbeddingScorer( + base::ReadOnlySharedMemoryRegion region, + base::File visual_tflite_model, + base::File image_embedding_model); + double ComputeScore(const FeatureMap& features) const override; #if BUILDFLAG(BUILD_WITH_TFLITE_LIB) @@ -87,6 +93,7 @@ base::ReadOnlySharedMemoryMapping flatbuffer_mapping_; google::protobuf::RepeatedPtrField<TfLiteModelMetadata::Threshold> thresholds_; + base::MemoryMappedFile image_embedding_model_; }; } // namespace safe_browsing
diff --git a/components/safe_browsing/content/renderer/phishing_classifier/phishing_model_setter_impl.cc b/components/safe_browsing/content/renderer/phishing_classifier/phishing_model_setter_impl.cc index 2da039412..146517af 100644 --- a/components/safe_browsing/content/renderer/phishing_classifier/phishing_model_setter_impl.cc +++ b/components/safe_browsing/content/renderer/phishing_classifier/phishing_model_setter_impl.cc
@@ -11,6 +11,34 @@ namespace safe_browsing { +std::unique_ptr<FlatBufferModelScorer> CreateFlatBufferModelScorer( + base::ReadOnlySharedMemoryRegion flatbuffer_region, + base::File tflite_visual_model) { + std::unique_ptr<FlatBufferModelScorer> scorer; + // An invalid region means we should disable client-side phishing detection. + if (flatbuffer_region.IsValid()) { + scorer = safe_browsing::FlatBufferModelScorer::Create( + std::move(flatbuffer_region), std::move(tflite_visual_model)); + } + return scorer; +} + +std::unique_ptr<FlatBufferModelScorer> +CreateFlatBufferModelWithImageEmbeddingScorer( + base::ReadOnlySharedMemoryRegion flatbuffer_region, + base::File tflite_visual_model, + base::File image_embedding_model) { + std::unique_ptr<FlatBufferModelScorer> scorer; + // An invalid region means we should disable client-side phishing detection. + if (flatbuffer_region.IsValid()) { + scorer = safe_browsing::FlatBufferModelScorer:: + CreateFlatBufferModelWithImageEmbeddingScorer( + std::move(flatbuffer_region), std::move(tflite_visual_model), + std::move(image_embedding_model)); + } + return scorer; +} + PhishingModelSetterImpl::PhishingModelSetterImpl() = default; PhishingModelSetterImpl::~PhishingModelSetterImpl() = default; @@ -26,6 +54,27 @@ associated_interfaces->RemoveInterface(mojom::PhishingModelSetter::Name_); } +void PhishingModelSetterImpl::SetImageEmbeddingAndPhishingFlatBufferModel( + base::ReadOnlySharedMemoryRegion flatbuffer_region, + base::File tflite_visual_model, + base::File image_embedding_model) { + std::unique_ptr<FlatBufferModelScorer> scorer = + CreateFlatBufferModelWithImageEmbeddingScorer( + std::move(flatbuffer_region), std::move(tflite_visual_model), + std::move(image_embedding_model)); + + if (!scorer) { + // Log here that the image embedder creation has failed. + return; + } + + ScorerStorage::GetInstance()->SetScorer(std::move(scorer)); + + if (observer_for_testing_.is_bound()) { + observer_for_testing_->PhishingModelUpdated(); + } +} + void PhishingModelSetterImpl::SetPhishingModel(const std::string& model, base::File tflite_visual_model) { std::unique_ptr<Scorer> scorer; @@ -48,13 +97,10 @@ void PhishingModelSetterImpl::SetPhishingFlatBufferModel( base::ReadOnlySharedMemoryRegion flatbuffer_region, base::File tflite_visual_model) { - std::unique_ptr<Scorer> scorer; - // An invalid region means we should disable client-side phishing detection. - if (flatbuffer_region.IsValid()) { - scorer = safe_browsing::FlatBufferModelScorer::Create( - std::move(flatbuffer_region), std::move(tflite_visual_model)); - if (!scorer) - return; + std::unique_ptr<Scorer> scorer = CreateFlatBufferModelScorer( + std::move(flatbuffer_region), std::move(tflite_visual_model)); + if (!scorer) { + return; } ScorerStorage::GetInstance()->SetScorer(std::move(scorer));
diff --git a/components/safe_browsing/content/renderer/phishing_classifier/phishing_model_setter_impl.h b/components/safe_browsing/content/renderer/phishing_classifier/phishing_model_setter_impl.h index 77a93c8..32ace65 100644 --- a/components/safe_browsing/content/renderer/phishing_classifier/phishing_model_setter_impl.h +++ b/components/safe_browsing/content/renderer/phishing_classifier/phishing_model_setter_impl.h
@@ -30,6 +30,10 @@ blink::AssociatedInterfaceRegistry* associated_interfaces) override; // mojom::PhishingModelSetter overrides: + void SetImageEmbeddingAndPhishingFlatBufferModel( + base::ReadOnlySharedMemoryRegion flatbuffer_region, + base::File tflite_visual_model, + base::File image_embedding_model_data) override; void SetPhishingModel(const std::string& model, base::File tflite_visual_model) override; void SetPhishingFlatBufferModel(
diff --git a/components/safe_browsing/content/renderer/phishing_classifier/scorer.h b/components/safe_browsing/content/renderer/phishing_classifier/scorer.h index 2f950a1..5eeb34c 100644 --- a/components/safe_browsing/content/renderer/phishing_classifier/scorer.h +++ b/components/safe_browsing/content/renderer/phishing_classifier/scorer.h
@@ -53,6 +53,7 @@ SCORER_FAIL_FLATBUFFER_INVALID_MAPPING = 8, SCORER_FAIL_FLATBUFFER_FAILED_VERIFY = 9, SCORER_FAIL_FLATBUFFER_BAD_INDICES_OR_FIELDS = 10, // Not used anymore + SCORER_FAIL_FLATBUFFER_INVALID_IMAGE_EMBEDDING_TFLITE_MODEL = 11, SCORER_STATUS_MAX // Always add new values before this one. };
diff --git a/components/safe_browsing/core/common/fbs/client_model.fbs b/components/safe_browsing/core/common/fbs/client_model.fbs index 813f132..0a2a675 100644 --- a/components/safe_browsing/core/common/fbs/client_model.fbs +++ b/components/safe_browsing/core/common/fbs/client_model.fbs
@@ -39,6 +39,7 @@ tflite_model_input_width: int (deprecated); tflite_model_input_height: int (deprecated); tflite_metadata:safe_browsing.flat.TfLiteModelMetadata; + img_embedding_metadata:safe_browsing.flat.TfLiteModelMetadata; dom_model_version:int; }
diff --git a/components/safe_browsing/core/common/features.cc b/components/safe_browsing/core/common/features.cc index 558342a2..fb5ebed 100644 --- a/components/safe_browsing/core/common/features.cc +++ b/components/safe_browsing/core/common/features.cc
@@ -299,6 +299,10 @@ "ClientSideDetectionModelOptimizationGuide", base::FEATURE_DISABLED_BY_DEFAULT); +BASE_FEATURE(kClientSideDetectionModelImageEmbedder, + "ClientSideDetectionModelImageEmbedder", + base::FEATURE_DISABLED_BY_DEFAULT); + BASE_FEATURE(kSafeBrowsingPhishingClassificationESBThreshold, "SafeBrowsingPhishingClassificationESBThreshold", base::FEATURE_ENABLED_BY_DEFAULT);
diff --git a/components/safe_browsing/core/common/features.h b/components/safe_browsing/core/common/features.h index e5114ce..512a1c6c 100644 --- a/components/safe_browsing/core/common/features.h +++ b/components/safe_browsing/core/common/features.h
@@ -325,5 +325,7 @@ // Specifies the CSD-Phishing daily reports limit for ESB users extern const base::FeatureParam<int> kSafeBrowsingDailyPhishingReportsLimitESB; +BASE_DECLARE_FEATURE(kClientSideDetectionModelImageEmbedder); + } // namespace safe_browsing #endif // COMPONENTS_SAFE_BROWSING_CORE_COMMON_FEATURES_H_
diff --git a/components/safe_browsing/core/common/proto/client_model.proto b/components/safe_browsing/core/common/proto/client_model.proto index 81e94e1c..9b9e58af 100644 --- a/components/safe_browsing/core/common/proto/client_model.proto +++ b/components/safe_browsing/core/common/proto/client_model.proto
@@ -109,7 +109,9 @@ optional TfLiteModelMetadata tflite_metadata = 17; - // next available tag number: 19 + optional TfLiteModelMetadata img_embedding_metadata = 19; + + // next available tag number: 20 } message TfLiteModelMetadata {
diff --git a/components/safe_browsing/core/common/proto/csd.proto b/components/safe_browsing/core/common/proto/csd.proto index a3bd0b2..1c98f0e 100644 --- a/components/safe_browsing/core/common/proto/csd.proto +++ b/components/safe_browsing/core/common/proto/csd.proto
@@ -131,6 +131,14 @@ optional bool is_signed_in = 18; } +message ImageFeatureEmbedding { + // Tracking embedding-model's version from iteration to iteration + optional int32 embedding_model_version = 1; + + // Raw tensor output of the embedding layer. + repeated float embedding_value = 2; +} + message ClientPhishingRequest { // URL that the client visited. The CGI parameters are stripped by the // client. @@ -242,7 +250,10 @@ // where the scoring from protego requested this request. optional ClientSideDetectionType client_side_detection_type = 28; - // next available tag number: 29. + // Image embedding from model output tensor + optional ImageFeatureEmbedding image_feature_embedding = 29; + + // next available tag number: 30. } message ClientPhishingResponse {
diff --git a/components/test/data/safe_browsing/image_embedding.tflite b/components/test/data/safe_browsing/image_embedding.tflite new file mode 100644 index 0000000..fe0d15c5 --- /dev/null +++ b/components/test/data/safe_browsing/image_embedding.tflite Binary files differ
diff --git a/components/viz/service/display/renderer_pixeltest.cc b/components/viz/service/display/renderer_pixeltest.cc index d70a812..ee17fa9 100644 --- a/components/viz/service/display/renderer_pixeltest.cc +++ b/components/viz/service/display/renderer_pixeltest.cc
@@ -1749,14 +1749,12 @@ constexpr int kMaxResourceSize = 10000; video_resource_updater_ = std::make_unique<media::VideoResourceUpdater>( - nullptr, - /*raster_context_provider=*/this->child_context_provider_.get(), - nullptr, this->child_resource_provider_.get(), kUseStreamVideoDrawQuad, + this->child_context_provider_.get(), nullptr, + this->child_resource_provider_.get(), kUseStreamVideoDrawQuad, kUseGpuMemoryBufferResources, kUseR16Texture, kMaxResourceSize); video_resource_updater2_ = std::make_unique<media::VideoResourceUpdater>( - nullptr, - /*raster_context_provider=*/this->child_context_provider_.get(), - nullptr, this->child_resource_provider_.get(), kUseStreamVideoDrawQuad, + this->child_context_provider_.get(), nullptr, + this->child_resource_provider_.get(), kUseStreamVideoDrawQuad, kUseGpuMemoryBufferResources, kUseR16Texture, kMaxResourceSize); } @@ -2166,9 +2164,9 @@ constexpr bool kUseR16Texture = false; constexpr int kMaxResourceSize = 10000; video_resource_updater_ = std::make_unique<media::VideoResourceUpdater>( - nullptr, child_context_provider_.get(), nullptr, - child_resource_provider_.get(), kUseStreamVideoDrawQuad, - kUseGpuMemoryBufferResources, kUseR16Texture, kMaxResourceSize); + child_context_provider_.get(), nullptr, child_resource_provider_.get(), + kUseStreamVideoDrawQuad, kUseGpuMemoryBufferResources, kUseR16Texture, + kMaxResourceSize); } void TearDown() override {
diff --git a/components/webapps/browser/uninstall_result_code.cc b/components/webapps/browser/uninstall_result_code.cc index 19dcc30e..fa6f2c3 100644 --- a/components/webapps/browser/uninstall_result_code.cc +++ b/components/webapps/browser/uninstall_result_code.cc
@@ -8,6 +8,18 @@ namespace webapps { +bool UninstallSucceeded(UninstallResultCode code) { + switch (code) { + case UninstallResultCode::kSuccess: + case UninstallResultCode::kNoAppToUninstall: + return true; + case UninstallResultCode::kCancelled: + case UninstallResultCode::kError: + case UninstallResultCode::kShutdown: + return false; + } +} + std::string ConvertUninstallResultCodeToString(UninstallResultCode code) { switch (code) { case UninstallResultCode::kSuccess: @@ -18,6 +30,8 @@ return "Uninstall cancelled"; case UninstallResultCode::kError: return "Error"; + case UninstallResultCode::kShutdown: + return "Shutdown"; } }
diff --git a/components/webapps/browser/uninstall_result_code.h b/components/webapps/browser/uninstall_result_code.h index 635a555..2a8b81d 100644 --- a/components/webapps/browser/uninstall_result_code.h +++ b/components/webapps/browser/uninstall_result_code.h
@@ -14,8 +14,11 @@ kNoAppToUninstall, kCancelled, kError, + kShutdown, }; +bool UninstallSucceeded(UninstallResultCode code); + std::string ConvertUninstallResultCodeToString(UninstallResultCode code); } // namespace webapps
diff --git a/content/browser/browser_interface_binders.cc b/content/browser/browser_interface_binders.cc index f84c373..bab129df 100644 --- a/content/browser/browser_interface_binders.cc +++ b/content/browser/browser_interface_binders.cc
@@ -90,7 +90,9 @@ #include "media/mojo/mojom/media_player.mojom.h" #include "media/mojo/mojom/remoting.mojom.h" #include "media/mojo/mojom/video_decode_perf_history.mojom.h" +#include "media/mojo/mojom/video_encoder_metrics_provider.mojom.h" #include "media/mojo/mojom/webrtc_video_perf.mojom.h" +#include "media/mojo/services/video_encoder_metrics_provider.h" #include "media/mojo/services/webrtc_video_perf_recorder.h" #include "mojo/public/cpp/bindings/message.h" #include "services/device/public/mojom/battery_monitor.mojom.h" @@ -988,6 +990,10 @@ &RenderFrameHostImpl::BindMediaMetricsProviderReceiver, base::Unretained(host))); + map->Add<media::mojom::VideoEncoderMetricsProvider>(base::BindRepeating( + &RenderFrameHostImpl::BindVideoEncoderMetricsProviderReceiver, + base::Unretained(host))); + map->Add<media::mojom::WebrtcVideoPerfRecorder>(base::BindRepeating( [](RenderFrameHostImpl* host, mojo::PendingReceiver<media::mojom::WebrtcVideoPerfRecorder>
diff --git a/content/browser/geolocation/geolocation_service_impl.cc b/content/browser/geolocation/geolocation_service_impl.cc index e0fc994f..033ab0b 100644 --- a/content/browser/geolocation/geolocation_service_impl.cc +++ b/content/browser/geolocation/geolocation_service_impl.cc
@@ -64,7 +64,7 @@ device::GeolocationManager::GetInstance(); geolocation_manager) { // One call here is enough as the calls are grouped by app name - geolocation_manager->AppCeasesToUseGeolocation(); + geolocation_manager->TrackGeolocationRelinquished(); } } @@ -75,7 +75,7 @@ if (device::GeolocationManager* geolocation_manager = device::GeolocationManager::GetInstance(); geolocation_manager) { - geolocation_manager->AppAttemptsToUseGeolocation(); + geolocation_manager->TrackGeolocationAttempted(); } }
diff --git a/content/browser/loader/navigation_early_hints_browsertest.cc b/content/browser/loader/navigation_early_hints_browsertest.cc index 21f4950..25963881 100644 --- a/content/browser/loader/navigation_early_hints_browsertest.cc +++ b/content/browser/loader/navigation_early_hints_browsertest.cc
@@ -5,6 +5,7 @@ #include "base/memory/weak_ptr.h" #include "base/run_loop.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/task/sequenced_task_runner.h" @@ -962,4 +963,87 @@ nullptr); } +namespace { + +const char kHttp1EarlyHintsPath[] = "/early-hints"; + +class Http1EarlyHintsResponse : public net::test_server::HttpResponse { + public: + Http1EarlyHintsResponse() = default; + ~Http1EarlyHintsResponse() override = default; + + void SendResponse( + base::WeakPtr<net::test_server::HttpResponseDelegate> delegate) override { + base::StringPairs early_hints_headers = { + {"Link", "</cacheable.js>; rel=preload; as=script"}}; + delegate->SendResponseHeaders(net::HTTP_EARLY_HINTS, "Early Hints", + early_hints_headers); + + base::StringPairs final_response_headers = { + {"Content-Type", "text/html"}, + {"Link", "</cacheable.js>; rel=preload; as=script"}}; + delegate->SendResponseHeaders(net::HTTP_OK, "OK", final_response_headers); + + delegate->SendContentsAndFinish("<script src=\"cacheable.js\"></script>"); + } +}; + +std::unique_ptr<net::test_server::HttpResponse> HandleHttpEarlyHintsRequest( + const net::test_server::HttpRequest& request) { + const GURL relative_url = request.base_url.Resolve(request.relative_url); + if (relative_url.path() == kHttp1EarlyHintsPath) { + return std::make_unique<Http1EarlyHintsResponse>(); + } + return nullptr; +} + +} // namespace + +class NavigationEarlyHintsHttp1Test : public ContentBrowserTest, + public testing::WithParamInterface<bool> { + public: + NavigationEarlyHintsHttp1Test() { + if (EnableEarlyHintsForHttp1()) { + scoped_feature_list_.InitAndEnableFeature( + net::features::kEnableEarlyHintsOnHttp11); + } else { + scoped_feature_list_.InitAndDisableFeature( + net::features::kEnableEarlyHintsOnHttp11); + } + } + + void SetUpOnMainThread() override { + ContentBrowserTest::SetUpOnMainThread(); + host_resolver()->AddRule("*", "127.0.0.1"); + embedded_test_server()->AddDefaultHandlers(); + embedded_test_server()->RegisterRequestHandler( + base::BindRepeating(&HandleHttpEarlyHintsRequest)); + ASSERT_TRUE(embedded_test_server()->Start()); + } + + bool EnableEarlyHintsForHttp1() { return GetParam(); } + + private: + base::test::ScopedFeatureList scoped_feature_list_; +}; + +INSTANTIATE_TEST_SUITE_P(All, NavigationEarlyHintsHttp1Test, testing::Bool()); + +// Tests that Early Hints are allowed or disallowed on HTTP/1.1 based on a +// feature flag. +IN_PROC_BROWSER_TEST_P(NavigationEarlyHintsHttp1Test, AllowEarlyHints) { + const GURL url = embedded_test_server()->GetURL(kHttp1EarlyHintsPath); + ASSERT_TRUE(NavigateToURL(shell(), url)); + + NavigationEarlyHintsManager* early_hints_manager = + static_cast<RenderFrameHostImpl*>( + shell()->web_contents()->GetPrimaryMainFrame()) + ->early_hints_manager(); + if (EnableEarlyHintsForHttp1()) { + ASSERT_TRUE(early_hints_manager->WasResourceHintsReceived()); + } else { + ASSERT_TRUE(early_hints_manager == nullptr); + } +} + } // namespace content
diff --git a/content/browser/preloading/prerender/prerender_browsertest.cc b/content/browser/preloading/prerender/prerender_browsertest.cc index 364c497..fd6b2c7 100644 --- a/content/browser/preloading/prerender/prerender_browsertest.cc +++ b/content/browser/preloading/prerender/prerender_browsertest.cc
@@ -230,7 +230,10 @@ &PrerenderBrowserTest::web_contents, base::Unretained(this))); feature_list_.InitWithFeatures( {blink::features::kPrerender2InNewTab, - blink::features::kPrerender2MainFrameNavigation}, + blink::features::kPrerender2MainFrameNavigation, + + // To enable Content-Security-Policy navigate-to support. + features::kExperimentalContentSecurityPolicyFeatures}, {}); } ~PrerenderBrowserTest() override = default; @@ -467,9 +470,6 @@ } void SetUpCommandLine(base::CommandLine* command_line) override { - // Useful for testing CSP:prefetch-src - base::CommandLine::ForCurrentProcess()->AppendSwitch( - switches::kEnableExperimentalWebPlatformFeatures); // The viewport meta tag is only enabled on Android. #if BUILDFLAG(IS_ANDROID) command_line->AppendSwitchASCII(switches::kEnableBlinkFeatures, @@ -9049,6 +9049,41 @@ ExpectFinalStatusForSpeculationRule(PrerenderFinalStatus::kMixedContent); } +IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, PrerenderBlockedByCspNavigateTo) { + const GURL initial_url = GetUrl("/empty.html"); + ASSERT_TRUE(NavigateToURL(shell(), initial_url)); + + // Add a Content-Security-Policy meta tag that restricts prerendering + // navigation URLs. + EXPECT_TRUE(ExecJs(current_frame_host(), R"( + const meta = document.createElement('meta'); + meta.httpEquiv = "Content-Security-Policy"; + meta.content = "navigate-to https://a.test:*/empty.html"; + document.getElementsByTagName('head')[0].appendChild(meta); + )")); + + const char* console_pattern = + "Refused to navigate to 'https://a.test:*/title1.html' because it " + "violates the following Content Security Policy directive: \"navigate-to " + "https://a.test:*/empty.html\".\n"; + + // Prerender a URL that will be blocked by the navigate-to. As navigation + // fails, AddPrerender() doesn't finish. We need to wait its failure by + // monitoring a console error for the navigation blocking. + WebContentsConsoleObserver console_observer(web_contents()); + console_observer.SetPattern(console_pattern); + const GURL disallowed_url = GetUrl("/title1.html"); + AddPrerenderAsync(disallowed_url); + ASSERT_TRUE(console_observer.Wait()); + + EXPECT_FALSE( + web_contents_impl()->GetPrerenderHostRegistry()->FindHostByUrlForTesting( + disallowed_url)); + ASSERT_EQ(1u, console_observer.messages().size()); + // Just in case, no server access should be observed. + EXPECT_EQ(GetRequestCount(disallowed_url), 0); +} + // Check that the Content-Security-Policy set via HTTP header applies after the // activation. This test verifies that that the web sandbox flags value is none. IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest,
diff --git a/content/browser/preloading/prerender/prerender_host.cc b/content/browser/preloading/prerender/prerender_host.cc index 10f655c..a708334 100644 --- a/content/browser/preloading/prerender/prerender_host.cc +++ b/content/browser/preloading/prerender/prerender_host.cc
@@ -4,6 +4,7 @@ #include "content/browser/preloading/prerender/prerender_host.h" +#include "base/debug/alias.h" #include "base/feature_list.h" #include "base/notreached.h" #include "base/observer_list.h" @@ -353,6 +354,17 @@ // `begin_params_` and `common_params_` is null here, but it doesn't matter // as this branch is reached only when the initial navigation fails, // so this PrerenderHost can't be activated. + + // Original code assumes the case CSP prefetch-src blocks prerendering, but + // prefetch-src was already deprecated, but this code path seems still + // reachable. To be clarify the actual scenario, let's have the dump code. + // We may eventually return false for this code path to make things simple. + // TODO(https://crbug.com/1394486): Monitor reports and decide if we + // continue to have the `is_ready_for_activation_` check in + // AreInitialPrerenderNavigationParamsCompatibleWithNavigation(). + net::Error net_error = created_navigation_handle->GetNetErrorCode(); + base::debug::Alias(&net_error); + base::debug::DumpWithoutCrashing(); } NavigationRequest* navigation_request = @@ -624,6 +636,12 @@ // defence-in-depth measure. CHECK(navigation_request.IsInPrimaryMainFrame()); + // Check `common_params_` and `begin_params_` here as these can be nullptr + // if LoadURLWithParams failed without running PrerenderNavigationThrottle. + if (!common_params_ || !begin_params_) { + return false; + } + // Compare BeginNavigationParams. ActivationNavigationParamsMatch result = AreBeginNavigationParamsCompatibleWithNavigation(
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc index f205062..b8fe56a 100644 --- a/content/browser/renderer_host/render_frame_host_impl.cc +++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -11293,6 +11293,12 @@ std::move(is_shutting_down_cb), std::move(receiver)); } +void RenderFrameHostImpl::BindVideoEncoderMetricsProviderReceiver( + mojo::PendingReceiver<media::mojom::VideoEncoderMetricsProvider> receiver) { + media::VideoEncoderMetricsProvider::Create(GetPageUkmSourceId(), + std::move(receiver)); +} + #if BUILDFLAG(ENABLE_MEDIA_REMOTING) void RenderFrameHostImpl::BindMediaRemoterFactoryReceiver( mojo::PendingReceiver<media::mojom::RemoterFactory> receiver) {
diff --git a/content/browser/renderer_host/render_frame_host_impl.h b/content/browser/renderer_host/render_frame_host_impl.h index 09ddb217..2a287fb 100644 --- a/content/browser/renderer_host/render_frame_host_impl.h +++ b/content/browser/renderer_host/render_frame_host_impl.h
@@ -89,7 +89,9 @@ #include "media/mojo/mojom/interface_factory.mojom-forward.h" #include "media/mojo/mojom/media_metrics_provider.mojom-forward.h" #include "media/mojo/mojom/media_player.mojom-forward.h" +#include "media/mojo/mojom/video_encoder_metrics_provider.mojom-forward.h" #include "media/mojo/services/media_metrics_provider.h" +#include "media/mojo/services/video_encoder_metrics_provider.h" #include "mojo/public/cpp/bindings/associated_receiver.h" #include "mojo/public/cpp/bindings/associated_remote.h" #include "mojo/public/cpp/bindings/pending_associated_remote.h" @@ -2077,6 +2079,10 @@ void BindMediaMetricsProviderReceiver( mojo::PendingReceiver<media::mojom::MediaMetricsProvider> receiver); + void BindVideoEncoderMetricsProviderReceiver( + mojo::PendingReceiver<media::mojom::VideoEncoderMetricsProvider> + receiver); + #if BUILDFLAG(ENABLE_MEDIA_REMOTING) void BindMediaRemoterFactoryReceiver( mojo::PendingReceiver<media::mojom::RemoterFactory> receiver);
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc index a122bd21..0e521106 100644 --- a/content/browser/renderer_host/render_widget_host_view_aura.cc +++ b/content/browser/renderer_host/render_widget_host_view_aura.cc
@@ -59,7 +59,6 @@ #include "third_party/blink/public/common/input/web_input_event.h" #include "third_party/blink/public/mojom/input/input_handler.mojom-forward.h" #include "third_party/blink/public/mojom/widget/record_content_to_visible_time_request.mojom.h" -#include "ui/accessibility/accessibility_switches.h" #include "ui/accessibility/aura/aura_window_properties.h" #include "ui/accessibility/platform/ax_platform_node.h" #include "ui/aura/client/aura_constants.h"
diff --git a/content/browser/service_worker/service_worker_registry.cc b/content/browser/service_worker/service_worker_registry.cc index 4a23cee..788b5dea 100644 --- a/content/browser/service_worker/service_worker_registry.cc +++ b/content/browser/service_worker/service_worker_registry.cc
@@ -572,6 +572,9 @@ for (const blink::mojom::WebFeature feature : version->used_features()) data->used_features.push_back(feature); data->ancestor_frame_type = registration->ancestor_frame_type(); + if (version->router_evaluator()) { + data->router_rules = version->router_evaluator()->rules(); + } // The ServiceWorkerVersion's policy container host might be null if it is // stored before loading the main script. This happens in many unittests. @@ -1101,6 +1104,11 @@ base::MakeRefCounted<PolicyContainerHost>( PolicyContainerPolicies(*data.policy_container_policies))); } + if (data.router_rules) { + bool status = version->SetupRouterEvaluator(*data.router_rules); + DCHECK(status) << "Failed to setup RouterEvaluator from the provided " + << "rules. Possibly the database is corrupted."; + } } version->set_script_response_time_for_devtools(data.script_response_time);
diff --git a/content/browser/service_worker/service_worker_version.cc b/content/browser/service_worker/service_worker_version.cc index db4223ca..5945fb8c 100644 --- a/content/browser/service_worker/service_worker_version.cc +++ b/content/browser/service_worker/service_worker_version.cc
@@ -1813,6 +1813,25 @@ registration->ActivateWaitingVersionWhenReady(); } +void ServiceWorkerVersion::RegisterRouter( + const blink::ServiceWorkerRouterRules& rules, + RegisterRouterCallback callback) { + if (router_evaluator()) { + // The renderer should have denied calling this twice. + receiver_.ReportBadMessage("The ServiceWorker router rules are set twice."); + return; + } + if (!SetupRouterEvaluator(rules)) { + // The renderer should have denied calling this method while the setup + // fails. + // TODO(crbug.com/1371756): revisit this to confirm no case for this error. + receiver_.ReportBadMessage( + "Failed to configure a router. Possibly a syntax error"); + return; + } + std::move(callback).Run(); +} + void ServiceWorkerVersion::OnSetCachedMetadataFinished(int64_t callback_id, size_t size, int result) {
diff --git a/content/browser/service_worker/service_worker_version.h b/content/browser/service_worker/service_worker_version.h index 7c749bbb..3fca259 100644 --- a/content/browser/service_worker/service_worker_version.h +++ b/content/browser/service_worker/service_worker_version.h
@@ -915,6 +915,8 @@ const GURL& url, NavigateClientCallback callback) override; void SkipWaiting(SkipWaitingCallback callback) override; + void RegisterRouter(const blink::ServiceWorkerRouterRules& rules, + RegisterRouterCallback callback) override; void OnSetCachedMetadataFinished(int64_t callback_id, size_t size,
diff --git a/content/child/runtime_features.cc b/content/child/runtime_features.cc index 611f926..65b930f 100644 --- a/content/child/runtime_features.cc +++ b/content/child/runtime_features.cc
@@ -323,6 +323,8 @@ raw_ref(features::kRemoveMobileViewportDoubleTap)}, {wf::EnableServiceWorkerBypassFetchHandler, raw_ref(features::kServiceWorkerBypassFetchHandler)}, + {wf::EnableServiceWorkerStaticRouter, + raw_ref(features::kServiceWorkerStaticRouter)}, }; for (const auto& mapping : blinkFeatureToBaseFeatureMapping) { SetRuntimeFeatureFromChromiumFeature(
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc index 40ec406..2f63633 100644 --- a/content/public/common/content_features.cc +++ b/content/public/common/content_features.cc
@@ -1096,6 +1096,12 @@ 0, }; +// Enables ServiceWorker static routing API. +// https://github.com/yoshisatoyanagisawa/service-worker-static-routing-api +BASE_FEATURE(kServiceWorkerStaticRouter, + "ServiceWorkerStaticRouter", + base::FEATURE_DISABLED_BY_DEFAULT); + // Run video capture service in the Browser process as opposed to a dedicated // utility process BASE_FEATURE(kRunVideoCaptureServiceInBrowserProcess,
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h index ca4b212..e03e8dd 100644 --- a/content/public/common/content_features.h +++ b/content/public/common/content_features.h
@@ -281,6 +281,7 @@ kAsyncStartServiceWorkerForEmptyFetchHandler; CONTENT_EXPORT extern const base::FeatureParam<int> kAsyncStartServiceWorkerForEmptyFetchHandlerDurationInMs; +CONTENT_EXPORT BASE_DECLARE_FEATURE(kServiceWorkerStaticRouter); CONTENT_EXPORT BASE_DECLARE_FEATURE(kUserMediaCaptureOnFocus); CONTENT_EXPORT BASE_DECLARE_FEATURE(kWebLockScreenApi); CONTENT_EXPORT BASE_DECLARE_FEATURE(kWebOTP);
diff --git a/gpu/command_buffer/service/abstract_texture.h b/gpu/command_buffer/service/abstract_texture.h index fd85cb9..d5bc607f 100644 --- a/gpu/command_buffer/service/abstract_texture.h +++ b/gpu/command_buffer/service/abstract_texture.h
@@ -67,11 +67,6 @@ virtual void SetBoundImage(gl::GLImage* image) = 0; #endif -#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) - // Return the image, if any, for testing purposes. - virtual gl::GLImage* GetImageForTesting() const = 0; -#endif - // Marks the texture as cleared, to help prevent sending an uninitialized // texture to the (untrusted) renderer. One should call this only when one // has actually initialized the texture.
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc index 889310f..390eb6b 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
@@ -329,18 +329,11 @@ // Binding an image should make the texture renderable. EXPECT_EQ(texture->SafeToRenderFrom(), true); -#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) - EXPECT_EQ(abstract_texture->GetImageForTesting(), image.get()); - EXPECT_EQ(texture->GetLevelImage(target, 0), image.get()); -#endif // Unbinding should make it not renderable. abstract_texture->SetBoundImage(nullptr); EXPECT_EQ(texture->SafeToRenderFrom(), false); -#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) - EXPECT_EQ(abstract_texture->GetImageForTesting(), nullptr); -#endif // Deleting |abstract_texture| should delete the platform texture as well, // since we haven't make a copy of the TextureRef. Also make sure that the
diff --git a/gpu/command_buffer/service/passthrough_abstract_texture_impl.cc b/gpu/command_buffer/service/passthrough_abstract_texture_impl.cc index 06ba0ab..db84e5b 100644 --- a/gpu/command_buffer/service/passthrough_abstract_texture_impl.cc +++ b/gpu/command_buffer/service/passthrough_abstract_texture_impl.cc
@@ -58,17 +58,6 @@ } #endif -#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) -gl::GLImage* PassthroughAbstractTextureImpl::GetImageForTesting() const { - if (!texture_passthrough_) - return nullptr; - - const GLint level = 0; - return texture_passthrough_->GetLevelImage(texture_passthrough_->target(), - level); -} -#endif - void PassthroughAbstractTextureImpl::SetCleared() { // The passthrough decoder has no notion of 'cleared', so do nothing. }
diff --git a/gpu/command_buffer/service/passthrough_abstract_texture_impl.h b/gpu/command_buffer/service/passthrough_abstract_texture_impl.h index 4128283..edc6e7e 100644 --- a/gpu/command_buffer/service/passthrough_abstract_texture_impl.h +++ b/gpu/command_buffer/service/passthrough_abstract_texture_impl.h
@@ -35,9 +35,6 @@ void SetBoundImage(gl::GLImage* image) override; #endif -#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) - gl::GLImage* GetImageForTesting() const override; -#endif void SetCleared() override; void SetCleanupCallback(CleanupCallback cb) override; void NotifyOnContextLost() override;
diff --git a/gpu/command_buffer/service/texture_manager.cc b/gpu/command_buffer/service/texture_manager.cc index f7552a3..eada05e6 100644 --- a/gpu/command_buffer/service/texture_manager.cc +++ b/gpu/command_buffer/service/texture_manager.cc
@@ -572,22 +572,6 @@ SetLevelImageInternal(target, level, image, owned_service_id_); } #endif - -#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) -gl::GLImage* TexturePassthrough::GetLevelImage(GLenum target, - GLint level) const { -#if BUILDFLAG(IS_APPLE) - return nullptr; -#else - size_t face_idx = 0; - if (!LevelInfoExists(target, level, &face_idx)) { - return nullptr; - } - - return level_images_[face_idx][level].image.get(); -#endif -} -#endif #endif #if BUILDFLAG(IS_ANDROID) @@ -1930,16 +1914,6 @@ return nullptr; } -#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) -gl::GLImage* Texture::GetLevelImage(GLint target, GLint level) const { - const LevelInfo* info = GetLevelInfo(target, level); - if (!info) - return nullptr; - - return info->image.get(); -} -#endif - void Texture::DumpLevelMemory(base::trace_event::ProcessMemoryDump* pmd, uint64_t client_tracing_id, const std::string& dump_name) const {
diff --git a/gpu/command_buffer/service/texture_manager.h b/gpu/command_buffer/service/texture_manager.h index 8d7c3c92..96eb5d2 100644 --- a/gpu/command_buffer/service/texture_manager.h +++ b/gpu/command_buffer/service/texture_manager.h
@@ -79,14 +79,9 @@ // native GL texture in the destructor void MarkContextLost(); -#if !BUILDFLAG(IS_ANDROID) -#if !BUILDFLAG(IS_APPLE) +#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_APPLE) void SetLevelImage(GLenum target, GLint level, gl::GLImage* image); #endif -#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) - gl::GLImage* GetLevelImage(GLenum target, GLint level) const; -#endif -#endif #if BUILDFLAG(IS_ANDROID) void BindToServiceId(GLuint service_id); @@ -332,12 +327,6 @@ GLenum type, const SamplerState& sampler_state) const; -#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) - // Get the image associated with a particular level. Returns NULL if level - // does not exist. - gl::GLImage* GetLevelImage(GLint target, GLint level) const; -#endif - bool HasImages() const { return has_images_; }
diff --git a/gpu/command_buffer/service/texture_manager_unittest.cc b/gpu/command_buffer/service/texture_manager_unittest.cc index dce0cae..afe61b9 100644 --- a/gpu/command_buffer/service/texture_manager_unittest.cc +++ b/gpu/command_buffer/service/texture_manager_unittest.cc
@@ -1679,32 +1679,6 @@ texture_ref = nullptr; } -#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) -TEST_F(TextureTest, GetLevelImage) { - manager_->SetTarget(texture_ref_.get(), GL_TEXTURE_2D); - manager_->SetLevelInfo(texture_ref_.get(), GL_TEXTURE_2D, 1, GL_RGBA, 2, 2, 1, - 0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect(2, 2)); - Texture* texture = texture_ref_->texture(); - EXPECT_TRUE(texture->GetLevelImage(GL_TEXTURE_2D, 1) == nullptr); - // Set image. - scoped_refptr<gl::GLImage> image(new GLImageStub); - manager_->SetBoundLevelImage(texture_ref_.get(), GL_TEXTURE_2D, 1, - image.get()); - EXPECT_FALSE(texture->GetLevelImage(GL_TEXTURE_2D, 1) == nullptr); - // Remove it. - manager_->UnsetLevelImage(texture_ref_.get(), GL_TEXTURE_2D, 1); - EXPECT_TRUE(texture->GetLevelImage(GL_TEXTURE_2D, 1) == nullptr); - - // Re-add it, and check that it's reset when SetLevelInfo is called. - manager_->SetBoundLevelImage(texture_ref_.get(), GL_TEXTURE_2D, 1, - image.get()); - manager_->SetLevelInfo(texture_ref_.get(), GL_TEXTURE_2D, 1, GL_RGBA, 2, 2, 1, - 0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect(2, 2)); - EXPECT_TRUE(texture->GetLevelImage(GL_TEXTURE_2D, 1) == nullptr); -} - -#endif - #if BUILDFLAG(IS_ANDROID) TEST_F(TextureTest, SetStreamTextureImageServiceID) { manager_->SetTarget(texture_ref_.get(), GL_TEXTURE_EXTERNAL_OES); @@ -2098,9 +2072,6 @@ scoped_refptr<TextureRef> restored_texture = manager_->GetTexture(client_id); EXPECT_EQ(produced_texture, restored_texture->texture()); EXPECT_EQ(service_id, restored_texture->service_id()); -#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) - EXPECT_EQ(image.get(), restored_texture->texture()->GetLevelImage(target, 0)); -#endif } static const GLenum kTextureTargets[] = {GL_TEXTURE_2D, GL_TEXTURE_EXTERNAL_OES,
diff --git a/gpu/command_buffer/service/validating_abstract_texture_impl.cc b/gpu/command_buffer/service/validating_abstract_texture_impl.cc index 5e15cdf..2a63d2f 100644 --- a/gpu/command_buffer/service/validating_abstract_texture_impl.cc +++ b/gpu/command_buffer/service/validating_abstract_texture_impl.cc
@@ -73,17 +73,6 @@ } #endif -#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) -gl::GLImage* ValidatingAbstractTextureImpl::GetImageForTesting() const { - if (!texture_ref_) - return nullptr; - - const GLuint target = texture_ref_->texture()->target(); - const GLint level = 0; - return texture_ref_->texture()->GetLevelImage(target, level); -} -#endif - void ValidatingAbstractTextureImpl::SetCleared() { if (!texture_ref_) return;
diff --git a/gpu/command_buffer/service/validating_abstract_texture_impl.h b/gpu/command_buffer/service/validating_abstract_texture_impl.h index a17abdc21..dd2732c4 100644 --- a/gpu/command_buffer/service/validating_abstract_texture_impl.h +++ b/gpu/command_buffer/service/validating_abstract_texture_impl.h
@@ -40,9 +40,6 @@ void SetBoundImage(gl::GLImage* image) override; #endif -#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) - gl::GLImage* GetImageForTesting() const override; -#endif void SetCleared() override; void SetCleanupCallback(CleanupCallback cb) override; void NotifyOnContextLost() override;
diff --git a/infra/config/generated/luci/cr-buildbucket.cfg b/infra/config/generated/luci/cr-buildbucket.cfg index 1c347b1..bc997a26 100644 --- a/infra/config/generated/luci/cr-buildbucket.cfg +++ b/infra/config/generated/luci/cr-buildbucket.cfg
@@ -608,7 +608,7 @@ dimensions: "cores:8" dimensions: "cpu:x86-64" dimensions: "free_space:standard" - dimensions: "os:Ubuntu-18.04" + dimensions: "os:Ubuntu-22.04" dimensions: "pool:luci.chromium.ci" dimensions: "ssd:0" exe { @@ -3106,7 +3106,7 @@ dimensions: "cores:8" dimensions: "cpu:x86-64" dimensions: "free_space:standard" - dimensions: "os:Ubuntu-18.04" + dimensions: "os:Ubuntu-22.04" dimensions: "pool:luci.chromium.ci" dimensions: "ssd:0" exe { @@ -11113,7 +11113,7 @@ dimensions: "cores:8" dimensions: "cpu:x86-64" dimensions: "free_space:standard" - dimensions: "os:Ubuntu-18.04" + dimensions: "os:Ubuntu-22.04" dimensions: "pool:luci.chromium.ci" dimensions: "ssd:0" exe { @@ -11833,7 +11833,7 @@ dimensions: "cores:8" dimensions: "cpu:x86-64" dimensions: "free_space:standard" - dimensions: "os:Ubuntu-18.04" + dimensions: "os:Ubuntu-22.04" dimensions: "pool:luci.chromium.ci" dimensions: "ssd:0" exe { @@ -14001,7 +14001,7 @@ dimensions: "cores:8" dimensions: "cpu:x86-64" dimensions: "free_space:standard" - dimensions: "os:Ubuntu-18.04" + dimensions: "os:Ubuntu-22.04" dimensions: "pool:luci.chromium.ci" dimensions: "ssd:0" exe { @@ -17004,7 +17004,7 @@ dimensions: "cores:8" dimensions: "cpu:x86-64" dimensions: "free_space:standard" - dimensions: "os:Ubuntu-18.04" + dimensions: "os:Ubuntu-22.04" dimensions: "pool:luci.chromium.ci" dimensions: "ssd:0" exe { @@ -17178,7 +17178,7 @@ dimensions: "cores:8" dimensions: "cpu:x86-64" dimensions: "free_space:standard" - dimensions: "os:Ubuntu-18.04" + dimensions: "os:Ubuntu-22.04" dimensions: "pool:luci.chromium.ci" dimensions: "ssd:0" exe { @@ -17781,7 +17781,7 @@ dimensions: "cores:8" dimensions: "cpu:x86-64" dimensions: "free_space:standard" - dimensions: "os:Ubuntu-18.04" + dimensions: "os:Ubuntu-22.04" dimensions: "pool:luci.chromium.ci" dimensions: "ssd:0" exe { @@ -21215,7 +21215,7 @@ dimensions: "cores:8" dimensions: "cpu:x86-64" dimensions: "free_space:standard" - dimensions: "os:Ubuntu-18.04" + dimensions: "os:Ubuntu-22.04" dimensions: "pool:luci.chromium.ci" dimensions: "ssd:0" exe { @@ -25128,7 +25128,7 @@ dimensions: "cores:8" dimensions: "cpu:x86-64" dimensions: "free_space:standard" - dimensions: "os:Ubuntu-18.04" + dimensions: "os:Ubuntu-22.04" dimensions: "pool:luci.chromium.ci" dimensions: "ssd:0" exe { @@ -25558,7 +25558,7 @@ dimensions: "cores:8" dimensions: "cpu:x86-64" dimensions: "free_space:standard" - dimensions: "os:Ubuntu-18.04" + dimensions: "os:Ubuntu-22.04" dimensions: "pool:luci.chromium.ci" dimensions: "ssd:0" exe { @@ -26035,7 +26035,7 @@ dimensions: "cores:8" dimensions: "cpu:x86-64" dimensions: "free_space:standard" - dimensions: "os:Ubuntu-18.04" + dimensions: "os:Ubuntu-22.04" dimensions: "pool:luci.chromium.ci" dimensions: "ssd:0" exe { @@ -26710,7 +26710,7 @@ dimensions: "cores:8" dimensions: "cpu:x86-64" dimensions: "free_space:standard" - dimensions: "os:Ubuntu-18.04" + dimensions: "os:Ubuntu-22.04" dimensions: "pool:luci.chromium.ci" dimensions: "ssd:0" exe { @@ -26951,7 +26951,7 @@ dimensions: "cores:8" dimensions: "cpu:x86-64" dimensions: "free_space:standard" - dimensions: "os:Ubuntu-18.04" + dimensions: "os:Ubuntu-22.04" dimensions: "pool:luci.chromium.ci" dimensions: "ssd:0" exe { @@ -27203,7 +27203,7 @@ dimensions: "cores:8" dimensions: "cpu:x86-64" dimensions: "free_space:standard" - dimensions: "os:Ubuntu-18.04" + dimensions: "os:Ubuntu-22.04" dimensions: "pool:luci.chromium.ci" dimensions: "ssd:0" exe { @@ -27287,7 +27287,7 @@ dimensions: "cores:8" dimensions: "cpu:x86-64" dimensions: "free_space:standard" - dimensions: "os:Ubuntu-18.04" + dimensions: "os:Ubuntu-22.04" dimensions: "pool:luci.chromium.ci" dimensions: "ssd:0" exe { @@ -27539,7 +27539,7 @@ dimensions: "cores:8" dimensions: "cpu:x86-64" dimensions: "free_space:standard" - dimensions: "os:Ubuntu-18.04" + dimensions: "os:Ubuntu-22.04" dimensions: "pool:luci.chromium.ci" dimensions: "ssd:0" exe { @@ -27803,7 +27803,7 @@ dimensions: "cores:8" dimensions: "cpu:x86-64" dimensions: "free_space:standard" - dimensions: "os:Ubuntu-18.04" + dimensions: "os:Ubuntu-22.04" dimensions: "pool:luci.chromium.ci" dimensions: "ssd:0" exe { @@ -28234,7 +28234,7 @@ dimensions: "cores:8" dimensions: "cpu:x86-64" dimensions: "free_space:standard" - dimensions: "os:Ubuntu-18.04" + dimensions: "os:Ubuntu-22.04" dimensions: "pool:luci.chromium.ci" dimensions: "ssd:0" exe { @@ -28490,7 +28490,7 @@ dimensions: "cores:8" dimensions: "cpu:x86-64" dimensions: "free_space:standard" - dimensions: "os:Ubuntu-18.04" + dimensions: "os:Ubuntu-22.04" dimensions: "pool:luci.chromium.ci" dimensions: "ssd:0" exe { @@ -28574,7 +28574,7 @@ dimensions: "cores:8" dimensions: "cpu:x86-64" dimensions: "free_space:standard" - dimensions: "os:Ubuntu-18.04" + dimensions: "os:Ubuntu-22.04" dimensions: "pool:luci.chromium.ci" dimensions: "ssd:0" exe { @@ -28658,7 +28658,7 @@ dimensions: "cores:8" dimensions: "cpu:x86-64" dimensions: "free_space:standard" - dimensions: "os:Ubuntu-18.04" + dimensions: "os:Ubuntu-22.04" dimensions: "pool:luci.chromium.ci" dimensions: "ssd:0" exe { @@ -29047,7 +29047,7 @@ dimensions: "cores:8" dimensions: "cpu:x86-64" dimensions: "free_space:standard" - dimensions: "os:Ubuntu-18.04" + dimensions: "os:Ubuntu-22.04" dimensions: "pool:luci.chromium.ci" dimensions: "ssd:0" exe { @@ -31823,7 +31823,7 @@ dimensions: "cores:8" dimensions: "cpu:x86-64" dimensions: "free_space:standard" - dimensions: "os:Ubuntu-18.04" + dimensions: "os:Ubuntu-22.04" dimensions: "pool:luci.chromium.ci" dimensions: "ssd:0" exe { @@ -32163,7 +32163,7 @@ dimensions: "cores:8" dimensions: "cpu:x86-64" dimensions: "free_space:standard" - dimensions: "os:Ubuntu-18.04" + dimensions: "os:Ubuntu-22.04" dimensions: "pool:luci.chromium.ci" dimensions: "ssd:0" exe { @@ -36382,7 +36382,7 @@ dimensions: "cores:8" dimensions: "cpu:x86-64" dimensions: "free_space:standard" - dimensions: "os:Ubuntu-18.04" + dimensions: "os:Ubuntu-22.04" dimensions: "pool:luci.chromium.ci" dimensions: "ssd:0" exe { @@ -40932,7 +40932,7 @@ dimensions: "cores:8" dimensions: "cpu:x86-64" dimensions: "free_space:standard" - dimensions: "os:Ubuntu-18.04" + dimensions: "os:Ubuntu-22.04" dimensions: "pool:luci.chromium.ci" dimensions: "ssd:0" exe { @@ -44311,7 +44311,7 @@ dimensions: "cores:8" dimensions: "cpu:x86-64" dimensions: "free_space:standard" - dimensions: "os:Ubuntu-18.04" + dimensions: "os:Ubuntu-22.04" dimensions: "pool:luci.chromium.ci" dimensions: "ssd:0" exe { @@ -44563,7 +44563,7 @@ dimensions: "cores:8" dimensions: "cpu:x86-64" dimensions: "free_space:standard" - dimensions: "os:Ubuntu-18.04" + dimensions: "os:Ubuntu-22.04" dimensions: "pool:luci.chromium.ci" dimensions: "ssd:0" exe { @@ -44897,7 +44897,7 @@ dimensions: "cores:8" dimensions: "cpu:x86-64" dimensions: "free_space:standard" - dimensions: "os:Ubuntu-18.04" + dimensions: "os:Ubuntu-22.04" dimensions: "pool:luci.chromium.ci" dimensions: "ssd:0" exe { @@ -44984,7 +44984,7 @@ dimensions: "cores:8" dimensions: "cpu:x86-64" dimensions: "free_space:standard" - dimensions: "os:Ubuntu-18.04" + dimensions: "os:Ubuntu-22.04" dimensions: "pool:luci.chromium.ci" dimensions: "ssd:0" exe { @@ -45821,7 +45821,7 @@ dimensions: "cores:8" dimensions: "cpu:x86-64" dimensions: "free_space:standard" - dimensions: "os:Ubuntu-18.04" + dimensions: "os:Ubuntu-22.04" dimensions: "pool:luci.chromium.ci" dimensions: "ssd:0" exe { @@ -46240,7 +46240,7 @@ dimensions: "cores:8" dimensions: "cpu:x86-64" dimensions: "free_space:standard" - dimensions: "os:Ubuntu-18.04" + dimensions: "os:Ubuntu-22.04" dimensions: "pool:luci.chromium.ci" dimensions: "ssd:0" exe { @@ -48863,7 +48863,7 @@ dimensions: "cores:8" dimensions: "cpu:x86-64" dimensions: "free_space:standard" - dimensions: "os:Ubuntu-18.04" + dimensions: "os:Ubuntu-22.04" dimensions: "pool:luci.chromium.ci" dimensions: "ssd:0" exe { @@ -49849,7 +49849,7 @@ dimensions: "cores:8" dimensions: "cpu:x86-64" dimensions: "free_space:standard" - dimensions: "os:Ubuntu-18.04" + dimensions: "os:Ubuntu-22.04" dimensions: "pool:luci.chromium.ci" dimensions: "ssd:0" exe { @@ -52186,7 +52186,7 @@ dimensions: "cores:8" dimensions: "cpu:x86-64" dimensions: "free_space:standard" - dimensions: "os:Ubuntu-18.04" + dimensions: "os:Ubuntu-22.04" dimensions: "pool:luci.chromium.ci" dimensions: "ssd:0" exe { @@ -52440,7 +52440,7 @@ dimensions: "cores:8" dimensions: "cpu:x86-64" dimensions: "free_space:standard" - dimensions: "os:Ubuntu-18.04" + dimensions: "os:Ubuntu-22.04" dimensions: "pool:luci.chromium.ci" dimensions: "ssd:0" exe { @@ -53663,7 +53663,7 @@ dimensions: "cores:8" dimensions: "cpu:x86-64" dimensions: "free_space:standard" - dimensions: "os:Ubuntu-18.04" + dimensions: "os:Ubuntu-22.04" dimensions: "pool:luci.chromium.ci" dimensions: "ssd:0" exe { @@ -55294,7 +55294,7 @@ swarming_host: "chromium-swarm.appspot.com" dimensions: "builderless:1" dimensions: "cores:8" - dimensions: "os:Ubuntu-18.04" + dimensions: "os:Ubuntu-22.04" dimensions: "pool:luci.chromium.ci" dimensions: "ssd:0" exe { @@ -55739,7 +55739,7 @@ swarming_host: "chromium-swarm.appspot.com" dimensions: "builderless:1" dimensions: "cores:8" - dimensions: "os:Ubuntu-18.04" + dimensions: "os:Ubuntu-22.04" dimensions: "pool:luci.chromium.ci" dimensions: "ssd:0" exe {
diff --git a/infra/config/lib/linux-default.json b/infra/config/lib/linux-default.json index cc3aac5..bf8a953 100644 --- a/infra/config/lib/linux-default.json +++ b/infra/config/lib/linux-default.json
@@ -1,6 +1,7 @@ { "ci": { "3pp-linux-amd64-packager": "Ubuntu-22.04", + "ASan Release Media (32-bit x86 with V8-ARM)": "Ubuntu-22.04", "Android ASAN (dbg)": "Ubuntu-22.04", "Android FYI Release (NVIDIA Shield TV)": "Ubuntu-22.04", "Android FYI Release (Nexus 5X)": "Ubuntu-22.04", @@ -25,6 +26,7 @@ "Cast Linux": "Ubuntu-22.04", "Cast Linux ARM64": "Ubuntu-22.04", "Cast Linux Debug": "Ubuntu-22.04", + "Centipede Upload Linux ASan": "Ubuntu-22.04", "ChromeOS FYI Release (amd64-generic)": "Ubuntu-22.04", "ChromeOS FYI Release (kevin)": "Ubuntu-22.04", "ChromeOS FYI Release Skylab (kevin)": "Ubuntu-22.04", @@ -80,8 +82,10 @@ "Leak Detection Linux": "Ubuntu-22.04", "Libfuzzer Upload Linux ASan": "Ubuntu-22.04", "Libfuzzer Upload Linux ASan Debug": "Ubuntu-22.04", + "Libfuzzer Upload Linux V8-ARM64 ASan": "Ubuntu-22.04", "Libfuzzer Upload Linux32 V8-ARM ASan Debug": "Ubuntu-22.04", "Linux ASan LSan Builder": "Ubuntu-22.04", + "Linux ASan LSan Tests (1)": "Ubuntu-22.04", "Linux Builder": "Ubuntu-22.04", "Linux Builder (Wayland)": "Ubuntu-22.04", "Linux Builder (dbg)": "Ubuntu-22.04", @@ -99,6 +103,7 @@ "Linux FYI Release (Intel UHD 630)": "Ubuntu-22.04", "Linux FYI Release (NVIDIA)": "Ubuntu-22.04", "Linux Release (NVIDIA)": "Ubuntu-22.04", + "Linux TSan Tests": "Ubuntu-22.04", "Linux Tests": "Ubuntu-22.04", "Linux Tests (Wayland)": "Ubuntu-22.04", "Linux Tests (dbg)(1)": "Ubuntu-22.04", @@ -121,7 +126,10 @@ "Mac Release (Intel)": "Ubuntu-22.04", "Mac Retina Debug (AMD)": "Ubuntu-22.04", "Mac Retina Release (AMD)": "Ubuntu-22.04", + "Mac10.13 Tests": "Ubuntu-22.04", + "Mac10.15 Tests": "Ubuntu-22.04", "Network Service Linux": "Ubuntu-22.04", + "Oreo Phone Tester": "Ubuntu-22.04", "Site Isolation Android": "Ubuntu-22.04", "ToTAndroid": "Ubuntu-22.04", "ToTAndroid (dbg)": "Ubuntu-22.04", @@ -143,6 +151,7 @@ "ToTLinuxPGO": "Ubuntu-22.04", "ToTLinuxTSan": "Ubuntu-22.04", "ToTLinuxUBSanVptr": "Ubuntu-22.04", + "UBSan Release": "Ubuntu-22.04", "VR Linux": "Ubuntu-22.04", "WebKit Linux Leak": "Ubuntu-22.04", "Win10 FYI x64 DX12 Vulkan Debug (NVIDIA)": "Ubuntu-22.04", @@ -160,22 +169,36 @@ "android-12-x64-fyi-rel": "Ubuntu-22.04", "android-angle-chromium-arm64-builder": "Ubuntu-22.04", "android-angle-chromium-arm64-nexus5x": "Ubuntu-22.04", + "android-annotator-rel": "Ubuntu-22.04", "android-archive-dbg": "Ubuntu-22.04", "android-archive-rel": "Ubuntu-22.04", "android-arm64-archive-rel": "Ubuntu-22.04", + "android-asan": "Ubuntu-22.04", "android-bfcache-rel": "Ubuntu-22.04", "android-binary-size-generator": "Ubuntu-22.04", "android-build-perf-developer": "Ubuntu-22.04", + "android-chrome-pie-x86-wpt-fyi-rel": "Ubuntu-22.04", "android-code-coverage": "Ubuntu-22.04", "android-code-coverage-native": "Ubuntu-22.04", "android-cronet-arm-rel": "Ubuntu-22.04", + "android-cronet-asan-x86-rel": "Ubuntu-22.04", "android-cronet-x86-dbg": "Ubuntu-22.04", + "android-cronet-x86-dbg-10-tests": "Ubuntu-22.04", "android-cronet-x86-dbg-11-tests": "Ubuntu-22.04", + "android-cronet-x86-dbg-marshmallow-tests": "Ubuntu-22.04", + "android-cronet-x86-dbg-oreo-tests": "Ubuntu-22.04", "android-cronet-x86-rel": "Ubuntu-22.04", + "android-cronet-x86-rel-kitkat-tests": "Ubuntu-22.04", + "android-nougat-x86-rel": "Ubuntu-22.04", "android-official": "Ubuntu-22.04", "android-perfetto-rel": "Ubuntu-22.04", + "android-pie-x86-fyi-rel": "Ubuntu-22.04", "android-pie-x86-rel": "Ubuntu-22.04", "android-rust-arm32-rel": "Ubuntu-22.04", + "android-rust-arm64-dbg": "Ubuntu-22.04", + "android-rust-arm64-rel": "Ubuntu-22.04", + "android-sdk-packager": "Ubuntu-22.04", + "android-webview-13-x64-dbg-tests": "Ubuntu-22.04", "android-x86-code-coverage": "Ubuntu-22.04", "build-perf-android": "Ubuntu-22.04", "build-perf-android-siso": "Ubuntu-22.04", @@ -197,8 +220,10 @@ "fuchsia-angle-builder": "Ubuntu-22.04", "fuchsia-arm64-rel": "Ubuntu-22.04", "fuchsia-code-coverage": "Ubuntu-22.04", + "fuchsia-fyi-x64-dbg": "Ubuntu-22.04", "fuchsia-official": "Ubuntu-22.04", "fuchsia-x64-accessibility-rel": "Ubuntu-22.04", + "fuchsia-x64-cast-receiver-rel": "Ubuntu-22.04", "ios-angle-intel": "Ubuntu-22.04", "lacros-amd64-generic-binary-size-rel": "Ubuntu-22.04", "lacros-amd64-generic-rel": "Ubuntu-22.04", @@ -219,6 +244,7 @@ "linux-angle-chromium-intel": "Ubuntu-22.04", "linux-angle-chromium-nvidia": "Ubuntu-22.04", "linux-annotator-rel": "Ubuntu-22.04", + "linux-archive-dbg": "Ubuntu-22.04", "linux-archive-rel": "Ubuntu-22.04", "linux-ash-chromium-generator-rel": "Ubuntu-22.04", "linux-bfcache-rel": "Ubuntu-22.04", @@ -264,6 +290,7 @@ "linux-swangle-x64": "Ubuntu-22.04", "linux-ubsan-vptr": "Ubuntu-22.04", "linux-updater-builder-dbg": "Ubuntu-22.04", + "linux-updater-builder-rel": "Ubuntu-22.04", "linux-upload-perfetto": "Ubuntu-22.04", "linux-win_cross-rel": "Ubuntu-22.04", "linux-wpt-content-shell-asan-fyi-rel": "Ubuntu-22.04", @@ -274,9 +301,15 @@ "linux-wpt-input-fyi-rel": "Ubuntu-22.04", "mac-angle-chromium-amd": "Ubuntu-22.04", "mac-angle-chromium-intel": "Ubuntu-22.04", + "mac10.13-updater-tester-dbg": "Ubuntu-22.04", + "mac10.14-updater-tester-rel": "Ubuntu-22.04", "mac10.15-updater-tester-rel": "Ubuntu-22.04", + "mac11-arm64-rel-tests": "Ubuntu-22.04", + "mac11-arm64-updater-tester-dbg": "Ubuntu-22.04", "mac12-arm64-updater-tester-rel": "Ubuntu-22.04", "mac12-x64-updater-tester-asan-dbg": "Ubuntu-22.04", + "mac13-arm64-rel-tests": "Ubuntu-22.04", + "metadata-exporter": "Ubuntu-22.04", "rts-model-packager": "Ubuntu-22.04", "win-annotator-rel": "Ubuntu-22.04", "win-cr23-rel": "Ubuntu-22.04", @@ -284,19 +317,28 @@ "win-perfetto-rel": "Ubuntu-22.04", "win-upload-perfetto": "Ubuntu-22.04", "win10-32-on-64-updater-tester-dbg": "Ubuntu-22.04", + "win10-32-on-64-updater-tester-rel": "Ubuntu-22.04", "win10-angle-chromium-x64-intel": "Ubuntu-22.04", "win10-angle-chromium-x64-nvidia": "Ubuntu-22.04", "win10-updater-tester-dbg": "Ubuntu-22.04", "win10-updater-tester-dbg-uac": "Ubuntu-22.04", "win10-wpt-content-shell-fyi-rel": "Ubuntu-22.04", + "win11-updater-tester-dbg-uac": "Ubuntu-22.04", "win11-wpt-content-shell-fyi-rel": "Ubuntu-22.04" }, + "goma": { + "android-archive-dbg-goma-rbe-ats-canary": "Ubuntu-22.04", + "linux-archive-rel-goma-rbe-ats-canary": "Ubuntu-22.04" + }, "reclient": { - "Linux Builder (canonical wd) (reclient compare)": "Ubuntu-22.04" + "Linux Builder (canonical wd) (reclient compare)": "Ubuntu-22.04", + "Simple Chrome Builder reclient staging": "Ubuntu-22.04" }, "reviver": { + "android-launcher": "Ubuntu-22.04", "fuchsia-coordinator": "Ubuntu-22.04", - "lacros-coordinator": "Ubuntu-22.04" + "lacros-coordinator": "Ubuntu-22.04", + "win-launcher": "Ubuntu-22.04" }, "try": { "android-11-x86-rel": "Ubuntu-22.04",
diff --git a/ios/chrome/browser/promos_manager/promos_manager_impl.mm b/ios/chrome/browser/promos_manager/promos_manager_impl.mm index 4ffb9be..a4890e17 100644 --- a/ios/chrome/browser/promos_manager/promos_manager_impl.mm +++ b/ios/chrome/browser/promos_manager/promos_manager_impl.mm
@@ -548,7 +548,14 @@ auto compare_promo = [&impression_history]( std::pair<promos_manager::Promo, PromoContext> lhs, std::pair<promos_manager::Promo, PromoContext> rhs) { - // PostRestoreSignIn types are to be displayed first. + // Choice types are to be displayed first. + if (lhs.first == Promo::Choice) { + return true; + } + if (rhs.first == Promo::Choice) { + return false; + } + // PostRestoreSignIn types come next. if (lhs.first == Promo::PostRestoreSignInFullscreen || lhs.first == Promo::PostRestoreSignInAlert) { return true;
diff --git a/ios/chrome/browser/promos_manager/promos_manager_impl_unittest.mm b/ios/chrome/browser/promos_manager/promos_manager_impl_unittest.mm index ac093a1b..492e750 100644 --- a/ios/chrome/browser/promos_manager/promos_manager_impl_unittest.mm +++ b/ios/chrome/browser/promos_manager/promos_manager_impl_unittest.mm
@@ -559,7 +559,8 @@ EXPECT_EQ(promos_manager_->SortPromos(active_promos), expected); } -// Tests `SortPromos` sorts `PostRestoreSignIn` promos before others. +// Tests `SortPromos` sorts `Choice` promos before others and +// `PostRestoreSignIn` next. TEST_F(PromosManagerImplTest, SortsPromosPreferCertainTypes) { CreatePromosManager(); @@ -568,6 +569,7 @@ {promos_manager::Promo::DefaultBrowser, PromoContext{true}}, {promos_manager::Promo::PostRestoreSignInFullscreen, PromoContext{false}}, {promos_manager::Promo::PostRestoreSignInAlert, PromoContext{false}}, + {promos_manager::Promo::Choice, PromoContext{false}}, }; int today = TodaysDay(); @@ -586,13 +588,15 @@ promos_manager_->impression_history_ = impressions; std::vector<promos_manager::Promo> sorted = promos_manager_->SortPromos(active_promos); - EXPECT_EQ(sorted.size(), (size_t)4); + EXPECT_EQ(sorted.size(), (size_t)5); + // Choice comes first + EXPECT_TRUE(sorted[0] == promos_manager::Promo::Choice); // tied for the type. - EXPECT_TRUE(sorted[0] == promos_manager::Promo::PostRestoreSignInFullscreen || - sorted[0] == promos_manager::Promo::PostRestoreSignInAlert); + EXPECT_TRUE(sorted[1] == promos_manager::Promo::PostRestoreSignInFullscreen || + sorted[1] == promos_manager::Promo::PostRestoreSignInAlert); // with pending state, before the less recently shown promo (Test). - EXPECT_EQ(sorted[2], promos_manager::Promo::DefaultBrowser); - EXPECT_EQ(sorted[3], promos_manager::Promo::Test); + EXPECT_EQ(sorted[3], promos_manager::Promo::DefaultBrowser); + EXPECT_EQ(sorted[4], promos_manager::Promo::Test); } // Tests `SortPromos` sorts promos with pending state before others without.
diff --git a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1 index 94b375b3..b147729 100644 --- a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1 +++ b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@ -73923d5b84a13e968b6ade6c9ed6c9fdf797e3f0 \ No newline at end of file +4e183621aef1d69bfbbc8e8ee6fcce894abbd21b \ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1 index 46cbbf3..da5a13e 100644 --- a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1 +++ b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@ -7faa08ca66730d92203afcca6054f413c12e702d \ No newline at end of file +4dd3f4f38deeee69863d8c8bf925900122d22655 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 index 787a2a1..21af408 100644 --- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -4a0bb62f5261263ce5e66c7b60b9793ffd08f5a3 \ No newline at end of file +6dbf4ce31ef69cba81d62cd1fe4a0e35a4a7c9f2 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 index f39c789..425ba3b 100644 --- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -03466c84504eccb0bb206930cb82a7b08fc0216a \ No newline at end of file +1170bb515efa06464c5fe912b504c240c51e4352 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 index 50efb87..9fab454 100644 --- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -f8e5f1423ad43c85b3aef6c91db69a232e02573e \ No newline at end of file +b176785bbae9c11e0ba069f571a68e956984dd95 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 index b171683e..e0e9cf2 100644 --- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -2389e204f10df680affd5bf7ce07b74fb3cddcac \ No newline at end of file +e8d416c8afea6d257ef1c852067757d18441b2d7 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1 index 7e46501..08ce54a5 100644 --- a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -acf3532718ab894f2800233da3c1cdfd6aa6dfb4 \ No newline at end of file +deea15a31dfc629c977aef51f612a5afb0e9604d \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1 index ccae72b5..6c9c213 100644 --- a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -de3438c3415d671d88dee4a06cadc277780b2ad9 \ No newline at end of file +1028d583855ca5cf15d2c24d036aab3e04f0442f \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 index 1faf4038..c55c2fa 100644 --- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -017743e976a2fd2c527b91a79bfd8cb54012990f \ No newline at end of file +84accfe866937cf0d68ec859a2bb096d4e233427 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 index e239c85b..0703be0 100644 --- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -50d757824a37fb5cbf188c7aa1010a7f5da2651d \ No newline at end of file +99cf5c91aabfedea4e2475a8382d10036b694c35 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 index 1420a69..2bf6b72 100644 --- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -67da2651d1135db472eb4595984de2a1bebb2e6e \ No newline at end of file +4172beb5356cf2a07e977ed624734d0646991269 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 index 4ec09a202..058adae1 100644 --- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -0cc5f2ef9c7e63b5e1050b7b2039c1e2fd74ba5d \ No newline at end of file +e1ea32b8932b82110363c2c3aa61ddbcd1e98e9c \ No newline at end of file
diff --git a/media/base/svc_scalability_mode.h b/media/base/svc_scalability_mode.h index f96a560..37f8e34 100644 --- a/media/base/svc_scalability_mode.h +++ b/media/base/svc_scalability_mode.h
@@ -11,41 +11,46 @@ // This enum class is the corresponding implementation with WebRTC-SVC. // See https://www.w3.org/TR/webrtc-svc/#scalabilitymodes* for the detail. +// These values are persisted to logs. Entries should not be renumbered and +// numeric values should never be reused. Please keep the consistency with +// VideoEncoderUseCase in tools/metrics/histograms/enums.xml. enum class SVCScalabilityMode { - kL1T1, - kL1T2, - kL1T3, - kL2T1, - kL2T2, - kL2T3, - kL3T1, - kL3T2, - kL3T3, - kL2T1h, - kL2T2h, - kL2T3h, - kS2T1, - kS2T2, - kS2T3, - kS2T1h, - kS2T2h, - kS2T3h, - kS3T1, - kS3T2, - kS3T3, - kS3T1h, - kS3T2h, - kS3T3h, - kL2T1Key, - kL2T2Key, - kL2T2KeyShift, - kL2T3Key, - kL2T3KeyShift, - kL3T1Key, - kL3T2Key, - kL3T2KeyShift, - kL3T3Key, - kL3T3KeyShift, + kL1T1 = 0, + kL1T2 = 1, + kL1T3 = 2, + kL2T1 = 3, + kL2T2 = 4, + kL2T3 = 5, + kL3T1 = 6, + kL3T2 = 7, + kL3T3 = 8, + kL2T1h = 9, + kL2T2h = 10, + kL2T3h = 11, + kS2T1 = 12, + kS2T2 = 13, + kS2T3 = 14, + kS2T1h = 15, + kS2T2h = 16, + kS2T3h = 17, + kS3T1 = 18, + kS3T2 = 19, + kS3T3 = 20, + kS3T1h = 21, + kS3T2h = 22, + kS3T3h = 23, + kL2T1Key = 24, + kL2T2Key = 25, + kL2T2KeyShift = 26, + kL2T3Key = 27, + kL2T3KeyShift = 28, + kL3T1Key = 29, + kL3T2Key = 30, + kL3T2KeyShift = 31, + kL3T3Key = 32, + kL3T3KeyShift = 33, + + kMaxValue = kL3T3KeyShift, }; // Gets the WebRTC-SVC Spec defined scalability mode name.
diff --git a/media/capture/video/mac/video_capture_device_avfoundation_mac.h b/media/capture/video/mac/video_capture_device_avfoundation_mac.h index db968b1..4c1d3d24 100644 --- a/media/capture/video/mac/video_capture_device_avfoundation_mac.h +++ b/media/capture/video/mac/video_capture_device_avfoundation_mac.h
@@ -54,6 +54,9 @@ - (void)setFrameReceiver: (media::VideoCaptureDeviceAVFoundationFrameReceiver*)frameReceiver; +// Whether to use a GPU memory for video frames or not. +- (void)setUseGPUMemoryBuffer:(bool)useGPUMemoryBuffer; + // Sets which capture device to use by name, retrieved via |deviceNames|. // Method -setCaptureDevice: must be called at least once with a device // identifier from GetVideoCaptureDeviceNames(). It creates all the necessary
diff --git a/media/capture/video/mac/video_capture_device_avfoundation_mac.mm b/media/capture/video/mac/video_capture_device_avfoundation_mac.mm index 4ba1b20..e852f8591 100644 --- a/media/capture/video/mac/video_capture_device_avfoundation_mac.mm +++ b/media/capture/video/mac/video_capture_device_avfoundation_mac.mm
@@ -159,6 +159,12 @@ // The following attributes are set via -setCaptureHeight:width:frameRate:. float _frameRate; + // Usage of GPU memory buffer is controlled by + // `--disable-video-capture-use-gpu-memory-buffer` and + // `--video-capture-use-gpu-memory-buffer` commandline switches. This flag + // handles whether to use a GPU memoery for a video frame or not. + bool _useGPUMemoryBuffer; + // The capture format that best matches the above attributes. AVCaptureDeviceFormat* __strong _bestCaptureFormat; @@ -245,6 +251,7 @@ "SampleDeliveryDispatchQueue", DISPATCH_QUEUE_SERIAL); DCHECK(frameReceiver); + _useGPUMemoryBuffer = true; _capturedFirstFrame = false; _weakPtrHolderForStallCheck.the_self = self; _weakPtrHolderForTakePhoto.the_self = self; @@ -286,6 +293,10 @@ _frameReceiver = frameReceiver; } +- (void)setUseGPUMemoryBuffer:(bool)useGPUMemoryBuffer { + _useGPUMemoryBuffer = useGPUMemoryBuffer; +} + - (BOOL)setCaptureDevice:(NSString*)deviceId errorMessage:(NSString**)outMessage { DCHECK(_captureSession); @@ -1026,7 +1037,7 @@ // formats to an IOSurface-backed NV12 pixel buffer. // TODO(https://crbug.com/1175142): Refactor to not hijack the code paths // below the transformer code. - if (sampleHasPixelBufferOrIsMjpeg) { + if (_useGPUMemoryBuffer && sampleHasPixelBufferOrIsMjpeg) { _sampleBufferTransformer->Reconfigure( media::SampleBufferTransformer::GetBestTransformerForNv12Output( sampleBuffer), @@ -1088,15 +1099,16 @@ DCHECK_EQ(pixelBufferPixelFormat, sampleBufferPixelFormat); // First preference is to use an NV12 IOSurface as a GpuMemoryBuffer. - if (CVPixelBufferGetIOSurface(pixelBuffer) && - videoPixelFormat == media::PIXEL_FORMAT_NV12) { - [self processPixelBufferNV12IOSurface:pixelBuffer - captureFormat:captureFormat - colorSpace:colorSpace - timestamp:timestamp]; - return; + if (_useGPUMemoryBuffer) { + if (CVPixelBufferGetIOSurface(pixelBuffer) && + videoPixelFormat == media::PIXEL_FORMAT_NV12) { + [self processPixelBufferNV12IOSurface:pixelBuffer + captureFormat:captureFormat + colorSpace:colorSpace + timestamp:timestamp]; + return; + } } - // Second preference is to read the CVPixelBuffer's planes. if ([self processPixelBufferPlanes:pixelBuffer captureFormat:captureFormat
diff --git a/media/capture/video/mac/video_capture_device_mac.mm b/media/capture/video/mac/video_capture_device_mac.mm index d34e9dc5..223e891 100644 --- a/media/capture/video/mac/video_capture_device_mac.mm +++ b/media/capture/video/mac/video_capture_device_mac.mm
@@ -164,6 +164,12 @@ [capture_device_ setFrameReceiver:this]; + if (params.buffer_type == VideoCaptureBufferType::kGpuMemoryBuffer) { + [capture_device_ setUseGPUMemoryBuffer:true]; + } else if (params.buffer_type == VideoCaptureBufferType::kSharedMemory) { + [capture_device_ setUseGPUMemoryBuffer:false]; + } + NSString* errorMessage = nil; if (![capture_device_ setCaptureDevice:deviceId errorMessage:&errorMessage]) { SetErrorState(VideoCaptureError::kMacSetCaptureDeviceFailed, FROM_HERE,
diff --git a/media/gpu/v4l2/test/av1_decoder.cc b/media/gpu/v4l2/test/av1_decoder.cc index 651b66bf..b2b9c05 100644 --- a/media/gpu/v4l2/test/av1_decoder.cc +++ b/media/gpu/v4l2/test/av1_decoder.cc
@@ -696,9 +696,6 @@ !frm_header.enable_frame_end_update_cdf, V4L2_AV1_FRAME_FLAG_DISABLE_FRAME_END_UPDATE_CDF); conditionally_set_u32_flags(&v4l2_frame_params->flags, - frm_header.tile_info.uniform_spacing, - V4L2_AV1_FRAME_FLAG_UNIFORM_TILE_SPACING); - conditionally_set_u32_flags(&v4l2_frame_params->flags, frm_header.allow_warped_motion, V4L2_AV1_FRAME_FLAG_ALLOW_WARPED_MOTION); conditionally_set_u32_flags(&v4l2_frame_params->flags,
diff --git a/media/gpu/v4l2/v4l2_device.h b/media/gpu/v4l2/v4l2_device.h index 53796883..45492ba 100644 --- a/media/gpu/v4l2/v4l2_device.h +++ b/media/gpu/v4l2/v4l2_device.h
@@ -60,22 +60,6 @@ v4l2_fourcc('S', '2', '6', '5') /* HEVC parsed slices */ #endif -#if BUILDFLAG(IS_CHROMEOS) -#ifndef V4L2_CID_MPEG_VIDEO_AV1_PROFILE -#define V4L2_CID_MPEG_VIDEO_AV1_PROFILE V4L2_CID_STATELESS_AV1_PROFILE -#endif -#ifndef V4L2_MPEG_VIDEO_AV1_PROFILE_MAIN -#define V4L2_MPEG_VIDEO_AV1_PROFILE_MAIN V4L2_STATELESS_AV1_PROFILE_MAIN -#endif -#ifndef V4L2_MPEG_VIDEO_AV1_PROFILE_HIGH -#define V4L2_MPEG_VIDEO_AV1_PROFILE_HIGH V4L2_STATELESS_AV1_PROFILE_HIGH -#endif -#ifndef V4L2_MPEG_VIDEO_AV1_PROFILE_PROFESSIONAL -#define V4L2_MPEG_VIDEO_AV1_PROFILE_PROFESSIONAL \ - V4L2_STATELESS_AV1_PROFILE_PROFESSIONAL -#endif -#endif - // TODO(b/260863940): Remove this once V4L2 header is updated #ifndef V4L2_CID_MPEG_VIDEO_HEVC_PROFILE #define V4L2_CID_MPEG_VIDEO_HEVC_PROFILE (V4L2_CID_MPEG_BASE + 615)
diff --git a/media/gpu/v4l2/v4l2_utils.cc b/media/gpu/v4l2/v4l2_utils.cc index 24604a20..9c784f17 100644 --- a/media/gpu/v4l2/v4l2_utils.cc +++ b/media/gpu/v4l2/v4l2_utils.cc
@@ -21,22 +21,6 @@ #include "media/gpu/macros.h" #include "ui/gfx/geometry/size.h" -#if BUILDFLAG(IS_CHROMEOS) -#ifndef V4L2_CID_MPEG_VIDEO_AV1_PROFILE -#define V4L2_CID_MPEG_VIDEO_AV1_PROFILE V4L2_CID_STATELESS_AV1_PROFILE -#endif -#ifndef V4L2_MPEG_VIDEO_AV1_PROFILE_MAIN -#define V4L2_MPEG_VIDEO_AV1_PROFILE_MAIN V4L2_STATELESS_AV1_PROFILE_MAIN -#endif -#ifndef V4L2_MPEG_VIDEO_AV1_PROFILE_HIGH -#define V4L2_MPEG_VIDEO_AV1_PROFILE_HIGH V4L2_STATELESS_AV1_PROFILE_HIGH -#endif -#ifndef V4L2_MPEG_VIDEO_AV1_PROFILE_PROFESSIONAL -#define V4L2_MPEG_VIDEO_AV1_PROFILE_PROFESSIONAL \ - V4L2_STATELESS_AV1_PROFILE_PROFESSIONAL -#endif -#endif - // TODO(b/255770680): Remove this once V4L2 header is updated. // https://patchwork.linuxtv.org/project/linux-media/patch/20210810220552.298140-2-daniel.almeida@collabora.com/ #ifndef V4L2_PIX_FMT_AV1
diff --git a/media/gpu/v4l2/v4l2_video_decoder_delegate_av1.cc b/media/gpu/v4l2/v4l2_video_decoder_delegate_av1.cc index fa08e35..fb05a18 100644 --- a/media/gpu/v4l2/v4l2_video_decoder_delegate_av1.cc +++ b/media/gpu/v4l2/v4l2_video_decoder_delegate_av1.cc
@@ -522,8 +522,6 @@ v4l2_frame_params.flags |= V4L2_AV1_FRAME_FLAG_USE_REF_FRAME_MVS; if (frame_header.enable_frame_end_update_cdf == false) v4l2_frame_params.flags |= V4L2_AV1_FRAME_FLAG_DISABLE_FRAME_END_UPDATE_CDF; - if (frame_header.tile_info.uniform_spacing) - v4l2_frame_params.flags |= V4L2_AV1_FRAME_FLAG_UNIFORM_TILE_SPACING; if (frame_header.allow_warped_motion) v4l2_frame_params.flags |= V4L2_AV1_FRAME_FLAG_ALLOW_WARPED_MOTION; if (frame_header.reference_mode_select)
diff --git a/media/gpu/vaapi/vp9_vaapi_video_encoder_delegate.cc b/media/gpu/vaapi/vp9_vaapi_video_encoder_delegate.cc index b909580..6eb61d3 100644 --- a/media/gpu/vaapi/vp9_vaapi_video_encoder_delegate.cc +++ b/media/gpu/vaapi/vp9_vaapi_video_encoder_delegate.cc
@@ -19,9 +19,6 @@ #include "media/gpu/vaapi/vaapi_common.h" #include "media/gpu/vaapi/vaapi_wrapper.h" #include "media/gpu/vp9_svc_layers.h" - -// TODO(b/286163500): Some macro in the libvpx headers conflicts with a macro in -// Chrome headers, so we always need to include this file last. #include "third_party/libvpx/source/libvpx/vp9/ratectrl_rtc.h" namespace media {
diff --git a/media/gpu/vaapi/vp9_vaapi_video_encoder_delegate_unittest.cc b/media/gpu/vaapi/vp9_vaapi_video_encoder_delegate_unittest.cc index 8507fd5..d8618ec 100644 --- a/media/gpu/vaapi/vp9_vaapi_video_encoder_delegate_unittest.cc +++ b/media/gpu/vaapi/vp9_vaapi_video_encoder_delegate_unittest.cc
@@ -25,9 +25,6 @@ #include "testing/gtest/include/gtest/gtest.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/libvpx/source/libvpx/vp9/common/vp9_blockd.h" - -// Some macro in the libvpx headers conflicts with a macro in Chrome headers, so -// we always need to include this file last. #include "third_party/libvpx/source/libvpx/vp9/ratectrl_rtc.h" using ::testing::_;
diff --git a/media/mojo/clients/BUILD.gn b/media/mojo/clients/BUILD.gn index cbd8e90..b0f140074 100644 --- a/media/mojo/clients/BUILD.gn +++ b/media/mojo/clients/BUILD.gn
@@ -53,6 +53,8 @@ "mojo_video_decoder.h", "mojo_video_encode_accelerator.cc", "mojo_video_encode_accelerator.h", + "mojo_video_encoder_metrics_provider.cc", + "mojo_video_encoder_metrics_provider.h", ] if (is_android) { @@ -114,6 +116,7 @@ "mojo_decryptor_unittest.cc", "mojo_renderer_unittest.cc", "mojo_video_encode_accelerator_unittest.cc", + "mojo_video_encoder_metrics_provider_unittest.cc", ] deps = [
diff --git a/media/mojo/clients/mojo_video_encoder_metrics_provider.cc b/media/mojo/clients/mojo_video_encoder_metrics_provider.cc new file mode 100644 index 0000000..f315cdf --- /dev/null +++ b/media/mojo/clients/mojo_video_encoder_metrics_provider.cc
@@ -0,0 +1,63 @@ +// 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 "media/mojo/clients/mojo_video_encoder_metrics_provider.h" + +namespace media { + +MojoVideoEncoderMetricsProvider::MojoVideoEncoderMetricsProvider( + mojom::VideoEncoderUseCase use_case, + mojo::PendingRemote<mojom::VideoEncoderMetricsProvider> pending_remote) + : use_case_(use_case), pending_remote_(std::move(pending_remote)) { + DETACH_FROM_SEQUENCE(sequence_checker_); +} + +MojoVideoEncoderMetricsProvider::~MojoVideoEncoderMetricsProvider() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); +} + +void MojoVideoEncoderMetricsProvider::Initialize( + VideoCodecProfile codec_profile, + const gfx::Size& encode_size, + bool is_hardware_encoder, + SVCScalabilityMode svc_mode) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + if (pending_remote_.is_valid()) { + remote_.Bind(std::move(pending_remote_)); + } + CHECK(remote_.is_bound()); + + remote_->Initialize(use_case_, codec_profile, encode_size, + is_hardware_encoder, svc_mode); +} + +void MojoVideoEncoderMetricsProvider::IncrementEncodedFrameCount() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + if (pending_remote_.is_valid()) { + DLOG(WARNING) << __func__ << "is called before Initialize()"; + return; + } + ++num_encoded_frames_; + constexpr size_t kEncodedFrameCountBucketSize = 100; + // Basically update the number of encoded frames every 100 seconds to avoid + // the frequent mojo call. The exception is the first encoded frames update as + // it is important to represent whether the encoding actually starts. + if (num_encoded_frames_ % kEncodedFrameCountBucketSize == 0 || + num_encoded_frames_ == 1u) { + remote_->SetEncodedFrameCount(num_encoded_frames_); + } +} + +void MojoVideoEncoderMetricsProvider::SetError( + const media::EncoderStatus& status) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + if (pending_remote_.is_valid()) { + DLOG(WARNING) << __func__ << "is called before Initialize()"; + return; + } + CHECK(!status.is_ok()); + remote_->SetError(status); +} + +} // namespace media
diff --git a/media/mojo/clients/mojo_video_encoder_metrics_provider.h b/media/mojo/clients/mojo_video_encoder_metrics_provider.h new file mode 100644 index 0000000..f0b215d --- /dev/null +++ b/media/mojo/clients/mojo_video_encoder_metrics_provider.h
@@ -0,0 +1,60 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MEDIA_MOJO_CLIENTS_MOJO_VIDEO_ENCODER_METRICS_PROVIDER_H_ +#define MEDIA_MOJO_CLIENTS_MOJO_VIDEO_ENCODER_METRICS_PROVIDER_H_ + +#include "base/sequence_checker.h" +#include "base/thread_annotations.h" +#include "media/base/encoder_status.h" +#include "media/base/svc_scalability_mode.h" +#include "media/mojo/mojom/video_encoder_metrics_provider.mojom.h" +#include "mojo/public/cpp/bindings/pending_remote.h" +#include "mojo/public/cpp/bindings/remote.h" +#include "ui/gfx/geometry/size.h" + +namespace media { +class MojoVideoEncoderMetricsProvider { + public: + // MojoVideoEncoderMetricsProvider ctro can be called on any sequence. + MojoVideoEncoderMetricsProvider( + mojom::VideoEncoderUseCase use_case, + mojo::PendingRemote<mojom::VideoEncoderMetricsProvider> pending_remote); + virtual ~MojoVideoEncoderMetricsProvider(); + + MojoVideoEncoderMetricsProvider(const MojoVideoEncoderMetricsProvider&) = + delete; + MojoVideoEncoderMetricsProvider& operator=( + const MojoVideoEncoderMetricsProvider&) = delete; + MojoVideoEncoderMetricsProvider(MojoVideoEncoderMetricsProvider&&) = delete; + MojoVideoEncoderMetricsProvider& operator=( + MojoVideoEncoderMetricsProvider&&) = delete; + + // All of the function must be called on the same sequence. + void Initialize(VideoCodecProfile codec_profile, + const gfx::Size& encode_size, + bool is_hardware_encoder) { + Initialize(codec_profile, encode_size, is_hardware_encoder, + SVCScalabilityMode::kL1T1); + } + virtual void Initialize(VideoCodecProfile codec_profile, + const gfx::Size& encode_size, + bool is_hardware_encoder, + SVCScalabilityMode svc_mode); + virtual void IncrementEncodedFrameCount(); + virtual void SetError(const media::EncoderStatus& status); + + protected: + // |sequence_checker_| is used in MockMojoVideoEncoderMetricsProvider. + SEQUENCE_CHECKER(sequence_checker_); + + private: + const mojom::VideoEncoderUseCase use_case_; + mojo::PendingRemote<mojom::VideoEncoderMetricsProvider> pending_remote_; + mojo::Remote<mojom::VideoEncoderMetricsProvider> remote_ + GUARDED_BY_CONTEXT(sequence_checker_); + uint64_t num_encoded_frames_ GUARDED_BY_CONTEXT(sequence_checker_){0}; +}; +} // namespace media +#endif // MEDIA_MOJO_CLIENTS_MOJO_VIDEO_ENCODER_METRICS_PROVIDER_H_
diff --git a/media/mojo/clients/mojo_video_encoder_metrics_provider_unittest.cc b/media/mojo/clients/mojo_video_encoder_metrics_provider_unittest.cc new file mode 100644 index 0000000..3290a79 --- /dev/null +++ b/media/mojo/clients/mojo_video_encoder_metrics_provider_unittest.cc
@@ -0,0 +1,166 @@ +// 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 "media/mojo/clients/mojo_video_encoder_metrics_provider.h" + +#include "base/run_loop.h" +#include "base/test/task_environment.h" +#include "mojo/public/cpp/bindings/pending_remote.h" +#include "mojo/public/cpp/bindings/remote.h" +#include "mojo/public/cpp/bindings/self_owned_receiver.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using ::testing::InSequence; + +namespace media { + +class MockMojomVideoEncoderMetricsProvider + : public mojom::VideoEncoderMetricsProvider { + public: + MockMojomVideoEncoderMetricsProvider() = default; + ~MockMojomVideoEncoderMetricsProvider() override = default; + // mojom::VideoEncoderMetricsProvider implementation. + MOCK_METHOD(void, + Initialize, + (mojom::VideoEncoderUseCase, + VideoCodecProfile, + const gfx::Size&, + bool, + SVCScalabilityMode), + (override)); + MOCK_METHOD(void, SetEncodedFrameCount, (uint64_t), (override)); + MOCK_METHOD(void, SetError, (const media::EncoderStatus&), (override)); +}; + +class MojoVideoEncoderMetricsProviderTest : public ::testing::Test { + public: + MojoVideoEncoderMetricsProviderTest() = default; + + static constexpr auto kUseCase = mojom::VideoEncoderUseCase::kMediaRecorder; + void SetUp() override { + mojo::PendingRemote<mojom::VideoEncoderMetricsProvider> pending_remote; + mojo_encoder_metrics_receiver_ = mojo::MakeSelfOwnedReceiver( + std::make_unique<MockMojomVideoEncoderMetricsProvider>(), + pending_remote.InitWithNewPipeAndPassReceiver()); + + mojo_encoder_metrics_provider_ = + std::make_unique<MojoVideoEncoderMetricsProvider>( + kUseCase, std::move(pending_remote)); + } + void TearDown() override { + // The destruction of a mojo::SelfOwnedReceiver closes the bound message + // pipe but does not destroy the implementation object(s): this needs to + // happen manually by Close()ing it. + if (mojo_encoder_metrics_receiver_) { + mojo_encoder_metrics_receiver_->Close(); + } + } + + MockMojomVideoEncoderMetricsProvider* mock_mojo_receiver() { + return reinterpret_cast<MockMojomVideoEncoderMetricsProvider*>( + mojo_encoder_metrics_receiver_->impl()); + } + + protected: + base::test::SingleThreadTaskEnvironment task_environment_; + // This member holds on to the mock implementation of the "service" side. + mojo::SelfOwnedReceiverRef<mojom::VideoEncoderMetricsProvider> + mojo_encoder_metrics_receiver_; + + std::unique_ptr<MojoVideoEncoderMetricsProvider> + mojo_encoder_metrics_provider_; +}; + +TEST_F(MojoVideoEncoderMetricsProviderTest, CreateAndDestroy) {} + +TEST_F(MojoVideoEncoderMetricsProviderTest, CreateAndBoundAndInitialize) { + constexpr auto kCodecProfile = media::VP9PROFILE_PROFILE0; + constexpr gfx::Size kEncodeSize(1920, 1080); + constexpr bool kIsHardwareEncoder = true; + constexpr auto kSVCMode = SVCScalabilityMode::kL1T3; + + InSequence s; + EXPECT_CALL(*mock_mojo_receiver(), + Initialize(kUseCase, kCodecProfile, kEncodeSize, + kIsHardwareEncoder, kSVCMode)); + mojo_encoder_metrics_provider_->Initialize(kCodecProfile, kEncodeSize, + kIsHardwareEncoder, kSVCMode); + base::RunLoop().RunUntilIdle(); +} + +TEST_F(MojoVideoEncoderMetricsProviderTest, + CreateAndBoundAndInitializeSetEncodedFrameCount) { + constexpr auto kCodecProfile = media::VP9PROFILE_PROFILE0; + constexpr gfx::Size kEncodeSize(1920, 1080); + constexpr bool kIsHardwareEncoder = true; + constexpr auto kSVCMode = SVCScalabilityMode::kL1T3; + + InSequence s; + EXPECT_CALL(*mock_mojo_receiver(), + Initialize(kUseCase, kCodecProfile, kEncodeSize, + kIsHardwareEncoder, kSVCMode)); + mojo_encoder_metrics_provider_->Initialize(kCodecProfile, kEncodeSize, + kIsHardwareEncoder, kSVCMode); + base::RunLoop().RunUntilIdle(); + EXPECT_CALL(*mock_mojo_receiver(), SetEncodedFrameCount(1u)); + mojo_encoder_metrics_provider_->IncrementEncodedFrameCount(); + base::RunLoop().RunUntilIdle(); + for (size_t i = 0; i < 98; i++) { + mojo_encoder_metrics_provider_->IncrementEncodedFrameCount(); + } + base::RunLoop().RunUntilIdle(); + EXPECT_CALL(*mock_mojo_receiver(), SetEncodedFrameCount(100u)); + mojo_encoder_metrics_provider_->IncrementEncodedFrameCount(); + base::RunLoop().RunUntilIdle(); + for (size_t i = 0; i < 99; i++) { + mojo_encoder_metrics_provider_->IncrementEncodedFrameCount(); + } + base::RunLoop().RunUntilIdle(); + EXPECT_CALL(*mock_mojo_receiver(), SetEncodedFrameCount(200u)); + mojo_encoder_metrics_provider_->IncrementEncodedFrameCount(); + base::RunLoop().RunUntilIdle(); +} + +TEST_F(MojoVideoEncoderMetricsProviderTest, + CreateAndBoundAndInitializeAndSetError) { + constexpr auto kCodecProfile = media::VP9PROFILE_PROFILE0; + constexpr gfx::Size kEncodeSize(1920, 1080); + constexpr bool kIsHardwareEncoder = true; + constexpr auto kSVCMode = SVCScalabilityMode::kL1T3; + + InSequence s; + EXPECT_CALL(*mock_mojo_receiver(), + Initialize(kUseCase, kCodecProfile, kEncodeSize, + kIsHardwareEncoder, kSVCMode)); + mojo_encoder_metrics_provider_->Initialize(kCodecProfile, kEncodeSize, + kIsHardwareEncoder, kSVCMode); + base::RunLoop().RunUntilIdle(); + EXPECT_CALL(*mock_mojo_receiver(), SetEncodedFrameCount(1u)); + mojo_encoder_metrics_provider_->IncrementEncodedFrameCount(); + mojo_encoder_metrics_provider_->IncrementEncodedFrameCount(); + mojo_encoder_metrics_provider_->IncrementEncodedFrameCount(); + base::RunLoop().RunUntilIdle(); + const media::EncoderStatus kErrorStatus( + media::EncoderStatus::Codes::kEncoderFailedEncode, "Encoder failed"); + mojo_encoder_metrics_provider_->SetError(kErrorStatus); + EXPECT_CALL(*mock_mojo_receiver(), SetError(kErrorStatus)); + base::RunLoop().RunUntilIdle(); +} + +TEST_F(MojoVideoEncoderMetricsProviderTest, CreateAndSetError_NoCall) { + InSequence s; + const media::EncoderStatus kErrorStatus( + media::EncoderStatus::Codes::kEncoderFailedEncode, "Encoder failed"); + mojo_encoder_metrics_provider_->SetError(kErrorStatus); + base::RunLoop().RunUntilIdle(); +} + +TEST_F(MojoVideoEncoderMetricsProviderTest, + CreateAndIncrementEncodedFrameCount_NoCall) { + InSequence s; + mojo_encoder_metrics_provider_->IncrementEncodedFrameCount(); + base::RunLoop().RunUntilIdle(); +} +} // namespace media
diff --git a/media/mojo/mojom/BUILD.gn b/media/mojo/mojom/BUILD.gn index 238c0a1..d8d0c373 100644 --- a/media/mojo/mojom/BUILD.gn +++ b/media/mojo/mojom/BUILD.gn
@@ -46,6 +46,7 @@ "video_decoder.mojom", "video_encode_accelerator.mojom", "video_encoder_info.mojom", + "video_encoder_metrics_provider.mojom", "watch_time_recorder.mojom", "webrtc_video_perf.mojom", ]
diff --git a/media/mojo/mojom/video_encoder_metrics_provider.mojom b/media/mojo/mojom/video_encoder_metrics_provider.mojom new file mode 100644 index 0000000..403cd79c --- /dev/null +++ b/media/mojo/mojom/video_encoder_metrics_provider.mojom
@@ -0,0 +1,38 @@ +// 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 media.mojom; + +import "ui/gfx/geometry/mojom/geometry.mojom"; +import "media/mojo/mojom/media_types.mojom"; + +// These values are persisted to logs. Entries should not be renumbered and +// numeric values should never be reused. Please keep the consistency with +// VideoEncoderUseCase in tools/metrics/histograms/enums.xml. +enum VideoEncoderUseCase { + kCastMirroring = 0, + kMediaRecorder = 1, + kWebCodecs = 2, + kWebRTC = 3, +}; + +// Provider interface to collect video encoder metrics. +interface VideoEncoderMetricsProvider { + // Initialize() is called whenever the encoder configuration is changed. + // The UKM about the encoding represented by the previous Initialize() is + // reported if SetEncodedFrameCount() or SetError() is invoked. See + // Media.VideoEncoderMetrics in ukm.xml for the detail about the recorded UKM. + Initialize(VideoEncoderUseCase encoder_use_case, VideoCodecProfile profile, + gfx.mojom.Size encode_size, bool is_hardware_encoder, + SVCScalabilityMode svc_mode); + + // SetEncodedFramesCount() updates the number of successfully encoded frames. + // |num_encoded_frames| can be any value, but it is bucket by 100 when UKM + // is recorded. + SetEncodedFrameCount(uint64 num_encoded_frames); + + // SetError() should be called when the encoder becomes in the error state. In + // other words, |status| must not be kOk. + SetError(EncoderStatus status); +};
diff --git a/media/mojo/services/BUILD.gn b/media/mojo/services/BUILD.gn index b7e84ee..b9c858d 100644 --- a/media/mojo/services/BUILD.gn +++ b/media/mojo/services/BUILD.gn
@@ -65,6 +65,8 @@ "video_decode_perf_history.h", "video_decode_stats_recorder.cc", "video_decode_stats_recorder.h", + "video_encoder_metrics_provider.cc", + "video_encoder_metrics_provider.h", "watch_time_recorder.cc", "watch_time_recorder.h", "webrtc_video_perf_history.cc", @@ -245,6 +247,7 @@ "test_helpers.h", "video_decode_perf_history_unittest.cc", "video_decode_stats_recorder_unittest.cc", + "video_encoder_metrics_provider_unittest.cc", "watch_time_recorder_unittest.cc", "webrtc_video_perf_history_unittest.cc", "webrtc_video_perf_recorder_unittest.cc",
diff --git a/media/mojo/services/video_encoder_metrics_provider.cc b/media/mojo/services/video_encoder_metrics_provider.cc new file mode 100644 index 0000000..ecddb73 --- /dev/null +++ b/media/mojo/services/video_encoder_metrics_provider.cc
@@ -0,0 +1,99 @@ +// 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 "media/mojo/services/video_encoder_metrics_provider.h" + +#include <algorithm> + +#include "base/memory/ptr_util.h" +#include "mojo/public/cpp/bindings/self_owned_receiver.h" +#include "services/metrics/public/cpp/ukm_builders.h" +#include "services/metrics/public/cpp/ukm_recorder.h" + +namespace media { + +// static +void VideoEncoderMetricsProvider::Create( + ukm::SourceId source_id, + mojo::PendingReceiver<mojom::VideoEncoderMetricsProvider> receiver) { + mojo::MakeSelfOwnedReceiver( + base::WrapUnique(new VideoEncoderMetricsProvider(source_id)), + std::move(receiver)); +} + +VideoEncoderMetricsProvider::VideoEncoderMetricsProvider( + ukm::SourceId source_id) + : source_id_(source_id) {} + +VideoEncoderMetricsProvider::~VideoEncoderMetricsProvider() { + ReportUKMIfNeeded(); +} + +void VideoEncoderMetricsProvider::ReportUKMIfNeeded() const { + // If Initialize() is not called, no UKM is reported. + if (!initialized_) { + return; + } + ukm::UkmRecorder* ukm_recorder = ukm::UkmRecorder::Get(); + if (!ukm_recorder) { + return; + } + ukm::builders::Media_VideoEncoderMetrics builder(source_id_); + builder.SetUseCase(static_cast<int>(encoder_use_case_)); + builder.SetProfile(static_cast<int>(codec_profile_)); + builder.SetSVCMode(static_cast<int>(svc_mode_)); + builder.SetIsHardware(is_hardware_encoder_); + constexpr int kMaxResolutionBucket = 8200; + builder.SetWidth( + std::min(encode_size_.width() / 100 * 100, kMaxResolutionBucket)); + builder.SetHeight( + std::min(encode_size_.height() / 100 * 100, kMaxResolutionBucket)); + builder.SetStatus(static_cast<int>(encoder_status_.code())); + + // We report UKM even if |num_encoded_frames_| is 0 so that we know how + // Initialize() is called. However, since the number of encoded frame is + // bucketed per 100, it disables to distinguish Initialize()-only case and + // the case of encoding a few frames. Therefore, we set the number of encoded + // frames to 1 if |num_encoded_frames_| is between 1 and 99. + if (num_encoded_frames_ == 0) { + builder.SetNumEncodedFrames(0); + } else { + builder.SetNumEncodedFrames( + std::max<uint64_t>(1, num_encoded_frames_ / 100 * 100)); + } + builder.Record(ukm_recorder); + + // TODO(b/275663480): Report UMAs. +} + +void VideoEncoderMetricsProvider::Initialize( + mojom::VideoEncoderUseCase encoder_use_case, + VideoCodecProfile codec_profile, + const gfx::Size& encode_size, + bool is_hardware_encoder, + SVCScalabilityMode svc_mode) { + ReportUKMIfNeeded(); + initialized_ = true; + num_encoded_frames_ = 0; + encoder_use_case_ = encoder_use_case; + codec_profile_ = codec_profile; + encode_size_ = encode_size; + is_hardware_encoder_ = is_hardware_encoder; + encoder_status_ = EncoderStatus::Codes::kOk; + svc_mode_ = svc_mode; +} + +void VideoEncoderMetricsProvider::SetEncodedFrameCount( + uint64_t num_encoded_frames) { + num_encoded_frames_ = num_encoded_frames; +} + +void VideoEncoderMetricsProvider::SetError(const EncoderStatus& status) { + CHECK(!status.is_ok()); + if (encoder_status_.is_ok()) { + encoder_status_ = status; + } +} + +} // namespace media
diff --git a/media/mojo/services/video_encoder_metrics_provider.h b/media/mojo/services/video_encoder_metrics_provider.h new file mode 100644 index 0000000..af1e1ed0 --- /dev/null +++ b/media/mojo/services/video_encoder_metrics_provider.h
@@ -0,0 +1,54 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MEDIA_MOJO_SERVICES_VIDEO_ENCODER_METRICS_PROVIDER_H_ +#define MEDIA_MOJO_SERVICES_VIDEO_ENCODER_METRICS_PROVIDER_H_ + +#include "media/base/encoder_status.h" +#include "media/base/svc_scalability_mode.h" +#include "media/base/video_codecs.h" +#include "media/mojo/mojom/video_encoder_metrics_provider.mojom.h" +#include "media/mojo/services/media_mojo_export.h" +#include "services/metrics/public/cpp/ukm_source_id.h" +#include "ui/gfx/geometry/size.h" + +namespace media { + +// See mojom::VideoEncoderMetricsProvider for documentation. +class MEDIA_MOJO_EXPORT VideoEncoderMetricsProvider + : public mojom::VideoEncoderMetricsProvider { + public: + static void Create( + ukm::SourceId source_id, + mojo::PendingReceiver<mojom::VideoEncoderMetricsProvider> receiver); + + ~VideoEncoderMetricsProvider() override; + + // mojom::VideoEncoderMetricsProvider implementation. + void Initialize(mojom::VideoEncoderUseCase encoder_use_case, + VideoCodecProfile codec_profile, + const gfx::Size& encode_size, + bool is_hardware_encoder, + SVCScalabilityMode svc_mode) override; + void SetEncodedFrameCount(uint64_t num_encoded_frames) override; + void SetError(const EncoderStatus& status) override; + + private: + explicit VideoEncoderMetricsProvider(ukm::SourceId source_id); + + void ReportUKMIfNeeded() const; + + const ukm::SourceId source_id_; + bool initialized_ = false; + uint64_t num_encoded_frames_ = 0; + + mojom::VideoEncoderUseCase encoder_use_case_; + VideoCodecProfile codec_profile_; + gfx::Size encode_size_; + bool is_hardware_encoder_; + SVCScalabilityMode svc_mode_; + EncoderStatus encoder_status_; +}; +} // namespace media +#endif // MEDIA_MOJO_SERVICES_VIDEO_ENCODER_METRICS_PROVIDER_H_
diff --git a/media/mojo/services/video_encoder_metrics_provider_unittest.cc b/media/mojo/services/video_encoder_metrics_provider_unittest.cc new file mode 100644 index 0000000..647ab3b --- /dev/null +++ b/media/mojo/services/video_encoder_metrics_provider_unittest.cc
@@ -0,0 +1,405 @@ +// 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 <stddef.h> +#include <memory> + +#include "media/mojo/services/video_encoder_metrics_provider.h" + +#include "base/run_loop.h" +#include "base/test/test_message_loop.h" +#include "components/ukm/test_ukm_recorder.h" +#include "mojo/public/cpp/bindings/remote.h" +#include "services/metrics/public/cpp/ukm_builders.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "url/gurl.h" + +using UkmEntry = ukm::builders::Media_VideoEncoderMetrics; + +using ::testing::TestWithParam; +using ::testing::ValuesIn; + +namespace media { +namespace { +constexpr char kTestURL[] = "https://test.google.com/"; + +std::tuple<std::unique_ptr<ukm::TestAutoSetUkmRecorder>, + mojo::Remote<mojom::VideoEncoderMetricsProvider>> +Create(const std::string& url) { + auto test_recorder = std::make_unique<ukm::TestAutoSetUkmRecorder>(); + ukm::SourceId source_id = test_recorder->GetNewSourceID(); + test_recorder->UpdateSourceURL(source_id, GURL(url)); + mojo::Remote<mojom::VideoEncoderMetricsProvider> provider; + VideoEncoderMetricsProvider::Create(source_id, + provider.BindNewPipeAndPassReceiver()); + return {std::move(test_recorder), std::move(provider)}; +} +} // namespace + +class VideoEncoderMetricsProviderTest + : public TestWithParam<testing::tuple<mojom::VideoEncoderUseCase, + VideoCodecProfile, + gfx::Size, + bool, + SVCScalabilityMode>> { + public: + VideoEncoderMetricsProviderTest() = default; + ~VideoEncoderMetricsProviderTest() override = default; + + protected: + base::TestMessageLoop message_loop_; +}; + +TEST_F(VideoEncoderMetricsProviderTest, Create_NoUKMReport) { + auto [test_recorder, provider] = Create(kTestURL); + provider.reset(); + base::RunLoop().RunUntilIdle(); + const auto entries = test_recorder->GetEntriesByName(UkmEntry::kEntryName); + EXPECT_TRUE(entries.empty()); +} + +#define EXPECT_UKM(name, value) \ + test_recorder->ExpectEntryMetric(entry, name, value) + +TEST_F(VideoEncoderMetricsProviderTest, CreateAndInitialize_ReportUKM) { + auto [test_recorder, provider] = Create(kTestURL); + constexpr auto kEncoderUseCase = mojom::VideoEncoderUseCase::kWebRTC; + constexpr auto kCodecProfile = VP9PROFILE_PROFILE0; + constexpr gfx::Size kEncodeSize(1200, 700); + constexpr bool kIsHardwareEncoder = true; + constexpr auto kSVCMode = SVCScalabilityMode::kL1T3; + provider->Initialize(kEncoderUseCase, kCodecProfile, kEncodeSize, + kIsHardwareEncoder, kSVCMode); + provider.reset(); + base::RunLoop().RunUntilIdle(); + + const auto entries = test_recorder->GetEntriesByName(UkmEntry::kEntryName); + ASSERT_EQ(1u, entries.size()); + const auto* entry = entries[0]; + EXPECT_UKM(UkmEntry::kHeightName, kEncodeSize.height()); + EXPECT_UKM(UkmEntry::kIsHardwareName, kIsHardwareEncoder); + EXPECT_UKM(UkmEntry::kNumEncodedFramesName, 0); + EXPECT_UKM(UkmEntry::kProfileName, kCodecProfile); + EXPECT_UKM(UkmEntry::kStatusName, + static_cast<int64_t>(EncoderStatus::Codes::kOk)); + EXPECT_UKM(UkmEntry::kSVCModeName, static_cast<int64_t>(kSVCMode)); + EXPECT_UKM(UkmEntry::kUseCaseName, static_cast<int64_t>(kEncoderUseCase)); + EXPECT_UKM(UkmEntry::kWidthName, kEncodeSize.width()); +} + +TEST_F( + VideoEncoderMetricsProviderTest, + CreateAndInitializeAndSetSmallNumberEncodedFrameCount_ReportUKMWithOneBucket) { + auto [test_recorder, provider] = Create(kTestURL); + constexpr auto kEncoderUseCase = mojom::VideoEncoderUseCase::kWebRTC; + constexpr auto kCodecProfile = VP9PROFILE_PROFILE0; + constexpr gfx::Size kEncodeSize(1200, 700); + constexpr bool kIsHardwareEncoder = true; + constexpr auto kSVCMode = SVCScalabilityMode::kL1T3; + provider->Initialize(kEncoderUseCase, kCodecProfile, kEncodeSize, + kIsHardwareEncoder, kSVCMode); + provider->SetEncodedFrameCount(10); + provider.reset(); + base::RunLoop().RunUntilIdle(); + + const auto entries = test_recorder->GetEntriesByName(UkmEntry::kEntryName); + ASSERT_EQ(1u, entries.size()); + const auto* entry = entries[0]; + EXPECT_UKM(UkmEntry::kHeightName, kEncodeSize.height()); + EXPECT_UKM(UkmEntry::kIsHardwareName, kIsHardwareEncoder); + EXPECT_UKM(UkmEntry::kNumEncodedFramesName, 1u); + EXPECT_UKM(UkmEntry::kProfileName, kCodecProfile); + EXPECT_UKM(UkmEntry::kStatusName, + static_cast<int64_t>(EncoderStatus::Codes::kOk)); + EXPECT_UKM(UkmEntry::kSVCModeName, static_cast<int64_t>(kSVCMode)); + EXPECT_UKM(UkmEntry::kUseCaseName, static_cast<int64_t>(kEncoderUseCase)); + EXPECT_UKM(UkmEntry::kWidthName, kEncodeSize.width()); +} + +TEST_P(VideoEncoderMetricsProviderTest, + CreateAndInitializeAndSetEncodedFrameCount_ReportUKM) { + auto [test_recorder, provider] = Create(kTestURL); + auto encoder_use_case = std::get<0>(GetParam()); + auto codec_profile = std::get<1>(GetParam()); + auto encode_size = std::get<2>(GetParam()); + auto is_hardware_encoder = std::get<3>(GetParam()); + auto svc_mode = std::get<4>(GetParam()); + constexpr uint64_t kNumEncodedFrames = 100; + provider->Initialize(encoder_use_case, codec_profile, encode_size, + is_hardware_encoder, svc_mode); + provider->SetEncodedFrameCount(kNumEncodedFrames); + provider.reset(); + base::RunLoop().RunUntilIdle(); + + const auto entries = test_recorder->GetEntriesByName(UkmEntry::kEntryName); + ASSERT_EQ(1u, entries.size()); + const auto* entry = entries[0]; + const uint64_t expected_height = encode_size.height() / 100 * 100; + const uint64_t expected_width = encode_size.width() / 100 * 100; + EXPECT_UKM(UkmEntry::kHeightName, expected_height); + EXPECT_UKM(UkmEntry::kIsHardwareName, is_hardware_encoder); + EXPECT_UKM(UkmEntry::kNumEncodedFramesName, kNumEncodedFrames); + EXPECT_UKM(UkmEntry::kProfileName, codec_profile); + EXPECT_UKM(UkmEntry::kStatusName, + static_cast<int64_t>(EncoderStatus::Codes::kOk)); + EXPECT_UKM(UkmEntry::kSVCModeName, static_cast<int64_t>(svc_mode)); + EXPECT_UKM(UkmEntry::kUseCaseName, static_cast<int64_t>(encoder_use_case)); + EXPECT_UKM(UkmEntry::kWidthName, expected_width); +} + +INSTANTIATE_TEST_SUITE_P( + All, + VideoEncoderMetricsProviderTest, + ::testing::Combine(ValuesIn({ + mojom::VideoEncoderUseCase::kCastMirroring, + mojom::VideoEncoderUseCase::kMediaRecorder, + mojom::VideoEncoderUseCase::kWebCodecs, + mojom::VideoEncoderUseCase::kWebRTC, + }), + ValuesIn({ + H264PROFILE_MAIN, + VP8PROFILE_ANY, + VP9PROFILE_MIN, + AV1PROFILE_PROFILE_HIGH, + }), + ValuesIn({ + gfx::Size(640, 360), + gfx::Size(1280, 720), + }), + ::testing::Bool(), + ValuesIn({ + SVCScalabilityMode::kL1T1, + SVCScalabilityMode::kL3T3Key, + }))); + +TEST_F(VideoEncoderMetricsProviderTest, + InitializeWithVerfiyLargeResoloution_ReportCappedResolutionUKM) { + auto [test_recorder, provider] = Create(kTestURL); + constexpr auto kEncoderUseCase = mojom::VideoEncoderUseCase::kWebRTC; + constexpr auto kCodecProfile = VP9PROFILE_PROFILE0; + constexpr gfx::Size k16kEncodeSize(15360, 8640); + constexpr bool kIsHardwareEncoder = true; + constexpr auto kSVCMode = SVCScalabilityMode::kL1T3; + constexpr uint64_t kNumEncodedFrames = 100; + provider->Initialize(kEncoderUseCase, kCodecProfile, k16kEncodeSize, + kIsHardwareEncoder, kSVCMode); + provider->SetEncodedFrameCount(kNumEncodedFrames); + provider.reset(); + base::RunLoop().RunUntilIdle(); + + const auto entries = test_recorder->GetEntriesByName(UkmEntry::kEntryName); + ASSERT_EQ(1u, entries.size()); + const auto* entry = entries[0]; + constexpr uint64_t kHeight = 8200; + constexpr uint64_t kWidth = 8200; + EXPECT_UKM(UkmEntry::kHeightName, kHeight); + EXPECT_UKM(UkmEntry::kIsHardwareName, kIsHardwareEncoder); + EXPECT_UKM(UkmEntry::kNumEncodedFramesName, kNumEncodedFrames); + EXPECT_UKM(UkmEntry::kProfileName, kCodecProfile); + EXPECT_UKM(UkmEntry::kStatusName, + static_cast<int64_t>(EncoderStatus::Codes::kOk)); + EXPECT_UKM(UkmEntry::kSVCModeName, static_cast<int64_t>(kSVCMode)); + EXPECT_UKM(UkmEntry::kUseCaseName, static_cast<int64_t>(kEncoderUseCase)); + EXPECT_UKM(UkmEntry::kWidthName, kWidth); +} + +TEST_F(VideoEncoderMetricsProviderTest, + CallSetEncodedFrameCounts_ReportUKMWithTheLastEncodedFrameCount) { + auto [test_recorder, provider] = Create(kTestURL); + constexpr auto kEncoderUseCase = mojom::VideoEncoderUseCase::kWebRTC; + constexpr auto kCodecProfile = VP9PROFILE_PROFILE0; + constexpr gfx::Size kEncodeSize(1920, 1080); + constexpr bool kIsHardwareEncoder = true; + constexpr auto kSVCMode = SVCScalabilityMode::kL1T3; + provider->Initialize(kEncoderUseCase, kCodecProfile, kEncodeSize, + kIsHardwareEncoder, kSVCMode); + provider->SetEncodedFrameCount(100); + provider->SetEncodedFrameCount(200); + provider->SetEncodedFrameCount(300); + provider.reset(); + base::RunLoop().RunUntilIdle(); + + const auto entries = test_recorder->GetEntriesByName(UkmEntry::kEntryName); + ASSERT_EQ(1u, entries.size()); + const auto* entry = entries[0]; + constexpr uint64_t kHeight = kEncodeSize.height() / 100 * 100; + constexpr uint64_t kWidth = kEncodeSize.width() / 100 * 100; + EXPECT_UKM(UkmEntry::kHeightName, kHeight); + EXPECT_UKM(UkmEntry::kIsHardwareName, kIsHardwareEncoder); + EXPECT_UKM(UkmEntry::kNumEncodedFramesName, 300); + EXPECT_UKM(UkmEntry::kProfileName, kCodecProfile); + EXPECT_UKM(UkmEntry::kStatusName, + static_cast<int64_t>(EncoderStatus::Codes::kOk)); + EXPECT_UKM(UkmEntry::kSVCModeName, static_cast<int64_t>(kSVCMode)); + EXPECT_UKM(UkmEntry::kUseCaseName, static_cast<int64_t>(kEncoderUseCase)); + EXPECT_UKM(UkmEntry::kWidthName, kWidth); +} + +TEST_F(VideoEncoderMetricsProviderTest, + CreateAndInitializeAndCallSetErrors_ReportUKMWithTheFirstError) { + auto [test_recorder, provider] = Create(kTestURL); + constexpr auto kEncoderUseCase = mojom::VideoEncoderUseCase::kWebRTC; + constexpr auto kCodecProfile = VP9PROFILE_PROFILE0; + constexpr gfx::Size kEncodeSize(1920, 1080); + constexpr bool kIsHardwareEncoder = true; + constexpr auto kSVCMode = SVCScalabilityMode::kL1T3; + provider->Initialize(kEncoderUseCase, kCodecProfile, kEncodeSize, + kIsHardwareEncoder, kSVCMode); + provider->SetError({EncoderStatus::Codes::kEncoderMojoConnectionError, + "mojo connection is disclosed"}); + provider->SetError( + {EncoderStatus::Codes::kEncoderFailedEncode, "Encoder failed"}); + provider.reset(); + base::RunLoop().RunUntilIdle(); + + const auto entries = test_recorder->GetEntriesByName(UkmEntry::kEntryName); + ASSERT_EQ(1u, entries.size()); + const auto* entry = entries[0]; + constexpr uint64_t kHeight = kEncodeSize.height() / 100 * 100; + constexpr uint64_t kWidth = kEncodeSize.width() / 100 * 100; + EXPECT_UKM(UkmEntry::kHeightName, kHeight); + EXPECT_UKM(UkmEntry::kIsHardwareName, kIsHardwareEncoder); + EXPECT_UKM(UkmEntry::kNumEncodedFramesName, 0u); + EXPECT_UKM(UkmEntry::kProfileName, kCodecProfile); + EXPECT_UKM( + UkmEntry::kStatusName, + static_cast<int64_t>(EncoderStatus::Codes::kEncoderMojoConnectionError)); + EXPECT_UKM(UkmEntry::kSVCModeName, static_cast<int64_t>(kSVCMode)); + EXPECT_UKM(UkmEntry::kUseCaseName, static_cast<int64_t>(kEncoderUseCase)); + EXPECT_UKM(UkmEntry::kWidthName, kWidth); +} + +TEST_F(VideoEncoderMetricsProviderTest, + CallErrorAndNoCallSetEncodedFramesCount_ReportUKMWithTheFirstError) { + auto [test_recorder, provider] = Create(kTestURL); + constexpr auto kEncoderUseCase = mojom::VideoEncoderUseCase::kWebRTC; + constexpr auto kCodecProfile = VP9PROFILE_PROFILE0; + constexpr gfx::Size kEncodeSize(1920, 1080); + constexpr bool kIsHardwareEncoder = true; + constexpr auto kSVCMode = SVCScalabilityMode::kL1T3; + provider->Initialize(kEncoderUseCase, kCodecProfile, kEncodeSize, + kIsHardwareEncoder, kSVCMode); + provider->SetError({EncoderStatus::Codes::kEncoderMojoConnectionError, + "mojo connection is disclosed"}); + provider->SetError( + {EncoderStatus::Codes::kEncoderFailedEncode, "Encoder failed"}); + provider.reset(); + base::RunLoop().RunUntilIdle(); + + const auto entries = test_recorder->GetEntriesByName(UkmEntry::kEntryName); + ASSERT_EQ(1u, entries.size()); + const auto* entry = entries[0]; + constexpr uint64_t kHeight = kEncodeSize.height() / 100 * 100; + constexpr uint64_t kWidth = kEncodeSize.width() / 100 * 100; + EXPECT_UKM(UkmEntry::kHeightName, kHeight); + EXPECT_UKM(UkmEntry::kIsHardwareName, kIsHardwareEncoder); + EXPECT_UKM(UkmEntry::kNumEncodedFramesName, 0); + EXPECT_UKM(UkmEntry::kProfileName, kCodecProfile); + EXPECT_UKM( + UkmEntry::kStatusName, + static_cast<int64_t>(EncoderStatus::Codes::kEncoderMojoConnectionError)); + EXPECT_UKM(UkmEntry::kSVCModeName, static_cast<int64_t>(kSVCMode)); + EXPECT_UKM(UkmEntry::kUseCaseName, static_cast<int64_t>(kEncoderUseCase)); + EXPECT_UKM(UkmEntry::kWidthName, kWidth); +} + +TEST_F( + VideoEncoderMetricsProviderTest, + CallSetEncodedFrameCountsAndSetError_ReportUKMWithTheFirstErrorAndTheLastEncodedFrameCount) { + auto [test_recorder, provider] = Create(kTestURL); + constexpr auto kEncoderUseCase = mojom::VideoEncoderUseCase::kWebRTC; + constexpr auto kCodecProfile = VP9PROFILE_PROFILE0; + constexpr gfx::Size kEncodeSize(1920, 1080); + constexpr bool kIsHardwareEncoder = true; + constexpr auto kSVCMode = SVCScalabilityMode::kL1T3; + provider->Initialize(kEncoderUseCase, kCodecProfile, kEncodeSize, + kIsHardwareEncoder, kSVCMode); + provider->SetEncodedFrameCount(100); + provider->SetEncodedFrameCount(200); + provider->SetEncodedFrameCount(300); + provider->SetError( + {EncoderStatus::Codes::kEncoderFailedEncode, "Encoder failed"}); + provider->SetError( + {EncoderStatus::Codes::kEncoderIllegalState, "Encoder illegal state"}); + provider->SetEncodedFrameCount(400); + provider.reset(); + base::RunLoop().RunUntilIdle(); + + const auto entries = test_recorder->GetEntriesByName(UkmEntry::kEntryName); + ASSERT_EQ(1u, entries.size()); + const auto* entry = entries[0]; + constexpr uint64_t kHeight = kEncodeSize.height() / 100 * 100; + constexpr uint64_t kWidth = kEncodeSize.width() / 100 * 100; + EXPECT_UKM(UkmEntry::kHeightName, kHeight); + EXPECT_UKM(UkmEntry::kIsHardwareName, kIsHardwareEncoder); + EXPECT_UKM(UkmEntry::kNumEncodedFramesName, 400); + EXPECT_UKM(UkmEntry::kProfileName, kCodecProfile); + EXPECT_UKM(UkmEntry::kStatusName, + static_cast<int64_t>(EncoderStatus::Codes::kEncoderFailedEncode)); + EXPECT_UKM(UkmEntry::kSVCModeName, static_cast<int64_t>(kSVCMode)); + EXPECT_UKM(UkmEntry::kUseCaseName, static_cast<int64_t>(kEncoderUseCase)); + EXPECT_UKM(UkmEntry::kWidthName, kWidth); +} + +TEST_F(VideoEncoderMetricsProviderTest, + CreateAndTwoInitializeAndSetEncodedFrameCounts_ReportTwoUKMs) { + const struct { + mojom::VideoEncoderUseCase use_case; + VideoCodecProfile profile; + gfx::Size size; + bool is_hardware; + SVCScalabilityMode svc_mode; + EncoderStatus::Codes status; + uint64_t num_encoded_frames; + } kMetricsCases[] = { + { + mojom::VideoEncoderUseCase::kWebRTC, + VP9PROFILE_PROFILE0, + gfx::Size(600, 300), + true, + SVCScalabilityMode::kL2T3Key, + EncoderStatus::Codes::kEncoderIllegalState, + 100, + }, + { + mojom::VideoEncoderUseCase::kMediaRecorder, + H264PROFILE_HIGH, + gfx::Size(1200, 700), + /*is_hardware=*/true, + SVCScalabilityMode::kL2T3Key, + EncoderStatus::Codes::kOk, + 300, + }, + }; + auto [test_recorder, provider] = Create(kTestURL); + for (const auto& metrics : kMetricsCases) { + provider->Initialize(metrics.use_case, metrics.profile, metrics.size, + metrics.is_hardware, metrics.svc_mode); + provider->SetEncodedFrameCount(metrics.num_encoded_frames); + if (metrics.status != EncoderStatus::Codes::kOk) { + provider->SetError(metrics.status); + } + } + provider.reset(); + base::RunLoop().RunUntilIdle(); + + const auto entries = test_recorder->GetEntriesByName(UkmEntry::kEntryName); + ASSERT_EQ(std::size(kMetricsCases), entries.size()); + for (size_t i = 0; i < entries.size(); ++i) { + const auto* entry = entries[i]; + const auto& metrics = kMetricsCases[i]; + EXPECT_UKM(UkmEntry::kHeightName, metrics.size.height()); + EXPECT_UKM(UkmEntry::kIsHardwareName, metrics.is_hardware); + EXPECT_UKM(UkmEntry::kNumEncodedFramesName, metrics.num_encoded_frames); + EXPECT_UKM(UkmEntry::kProfileName, metrics.profile); + EXPECT_UKM(UkmEntry::kStatusName, static_cast<int64_t>(metrics.status)); + EXPECT_UKM(UkmEntry::kSVCModeName, static_cast<int64_t>(metrics.svc_mode)); + EXPECT_UKM(UkmEntry::kUseCaseName, static_cast<int64_t>(metrics.use_case)); + EXPECT_UKM(UkmEntry::kWidthName, metrics.size.width()); + } +} + +#undef EXPECT_UKM +} // namespace media
diff --git a/media/renderers/video_resource_updater.cc b/media/renderers/video_resource_updater.cc index a23d02eb..0bc22fb 100644 --- a/media/renderers/video_resource_updater.cc +++ b/media/renderers/video_resource_updater.cc
@@ -28,7 +28,6 @@ #include "cc/paint/skia_paint_canvas.h" #include "components/viz/client/client_resource_provider.h" #include "components/viz/client/shared_bitmap_reporter.h" -#include "components/viz/common/gpu/context_provider.h" #include "components/viz/common/gpu/raster_context_provider.h" #include "components/viz/common/quads/compositor_render_pass.h" #include "components/viz/common/quads/texture_draw_quad.h" @@ -481,16 +480,11 @@ viz::SharedImageFormat format, const gfx::ColorSpace& color_space, bool use_gpu_memory_buffer_resources, - viz::ContextProvider* context_provider, - viz::RasterContextProvider* raster_context_provider) + viz::RasterContextProvider* context_provider) : PlaneResource(plane_resource_id, size, format, /*is_software=*/false), - context_provider_(context_provider), - raster_context_provider_(raster_context_provider) { - DCHECK(context_provider_ || raster_context_provider_); - const gpu::Capabilities& caps = - raster_context_provider_ - ? raster_context_provider_->ContextCapabilities() - : context_provider_->ContextCapabilities(); + context_provider_(context_provider) { + DCHECK(context_provider_); + const gpu::Capabilities& caps = context_provider_->ContextCapabilities(); DCHECK(format.is_single_plane()); // TODO(hitawala): Add multiplanar support for software decode. overlay_candidate_ = @@ -530,22 +524,18 @@ private: gpu::SharedImageInterface* SharedImageInterface() { - auto* sii = raster_context_provider_ - ? raster_context_provider_->SharedImageInterface() - : context_provider_->SharedImageInterface(); + auto* sii = context_provider_->SharedImageInterface(); DCHECK(sii); return sii; } gpu::gles2::GLES2Interface* ContextGL() { - auto* gl = raster_context_provider_ ? raster_context_provider_->ContextGL() - : context_provider_->ContextGL(); + auto* gl = context_provider_->ContextGL(); DCHECK(gl); return gl; } - const raw_ptr<viz::ContextProvider> context_provider_; - const raw_ptr<viz::RasterContextProvider> raster_context_provider_; + const raw_ptr<viz::RasterContextProvider> context_provider_; gpu::Mailbox mailbox_; GLenum texture_target_ = GL_TEXTURE_2D; bool overlay_candidate_ = false; @@ -564,8 +554,7 @@ } VideoResourceUpdater::VideoResourceUpdater( - viz::ContextProvider* context_provider, - viz::RasterContextProvider* raster_context_provider, + viz::RasterContextProvider* context_provider, viz::SharedBitmapReporter* shared_bitmap_reporter, viz::ClientResourceProvider* resource_provider, bool use_stream_video_draw_quad, @@ -573,7 +562,6 @@ bool use_r16_texture, int max_resource_size) : context_provider_(context_provider), - raster_context_provider_(raster_context_provider), shared_bitmap_reporter_(shared_bitmap_reporter), resource_provider_(resource_provider), use_stream_video_draw_quad_(use_stream_video_draw_quad), @@ -581,8 +569,7 @@ use_r16_texture_(use_r16_texture), max_resource_size_(max_resource_size), tracing_id_(g_next_video_resource_updater_id.GetNext()) { - DCHECK(context_provider_ || raster_context_provider_ || - shared_bitmap_reporter_); + DCHECK(context_provider_ || shared_bitmap_reporter_); base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider( this, "media::VideoResourceUpdater", @@ -776,10 +763,8 @@ viz::SharedImageFormat VideoResourceUpdater::YuvSharedImageFormat( int bits_per_channel) { - DCHECK(raster_context_provider_ || context_provider_); - const auto& caps = raster_context_provider_ - ? raster_context_provider_->ContextCapabilities() - : context_provider_->ContextCapabilities(); + DCHECK(context_provider_); + const auto& caps = context_provider_->ContextCapabilities(); if (caps.disable_one_component_textures) return PaintCanvasVideoRenderer::GetRGBPixelsOutputFormat(); if (bits_per_channel <= 8) @@ -861,8 +846,7 @@ } else { all_resources_.push_back(std::make_unique<HardwarePlaneResource>( plane_resource_id, plane_size, format, color_space, - use_gpu_memory_buffer_resources_, context_provider_, - raster_context_provider_)); + use_gpu_memory_buffer_resources_, context_provider_)); } return all_resources_.back().get(); } @@ -936,8 +920,9 @@ scoped_refptr<VideoFrame> video_frame) { TRACE_EVENT0("cc", "VideoResourceUpdater::CreateForHardwarePlanes"); DCHECK(video_frame->HasTextures()); - if (!context_provider_ && !raster_context_provider_) + if (!context_provider_) { return VideoFrameExternalResources(); + } VideoFrameExternalResources external_resources; gfx::ColorSpace resource_color_space = video_frame->ColorSpace(); @@ -1456,8 +1441,7 @@ } gpu::gles2::GLES2Interface* VideoResourceUpdater::ContextGL() { - auto* gl = raster_context_provider_ ? raster_context_provider_->ContextGL() - : context_provider_->ContextGL(); + auto* gl = context_provider_->ContextGL(); DCHECK(gl); return gl; } @@ -1491,7 +1475,7 @@ if (resource_it == all_resources_.end()) return; - if ((raster_context_provider_ || context_provider_) && sync_token.HasData()) { + if (context_provider_ && sync_token.HasData()) { ContextGL()->WaitSyncTokenCHROMIUM(sync_token.GetConstData()); }
diff --git a/media/renderers/video_resource_updater.h b/media/renderers/video_resource_updater.h index b3414021..7d9ffe1 100644 --- a/media/renderers/video_resource_updater.h +++ b/media/renderers/video_resource_updater.h
@@ -33,7 +33,6 @@ namespace viz { class ClientResourceProvider; -class ContextProvider; class RasterContextProvider; class CompositorRenderPass; class SharedBitmapReporter; @@ -88,8 +87,7 @@ // For GPU compositing |context_provider| should be provided and for software // compositing |shared_bitmap_reporter| should be provided. If there is a // non-null |context_provider| we assume GPU compositing. - VideoResourceUpdater(viz::ContextProvider* context_provider, - viz::RasterContextProvider* raster_context_provider, + VideoResourceUpdater(viz::RasterContextProvider* context_provider, viz::SharedBitmapReporter* shared_bitmap_reporter, viz::ClientResourceProvider* resource_provider, bool use_stream_video_draw_quad, @@ -148,9 +146,7 @@ gfx::Size size_in_pixels; }; - bool software_compositor() const { - return context_provider_ == nullptr && raster_context_provider_ == nullptr; - } + bool software_compositor() const { return context_provider_ == nullptr; } // Reallocate |upload_pixels_| with the requested size. bool ReallocateUploadPixels(size_t needed_size); @@ -207,8 +203,7 @@ bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args, base::trace_event::ProcessMemoryDump* pmd) override; - const raw_ptr<viz::ContextProvider, DanglingUntriaged> context_provider_; - const raw_ptr<viz::RasterContextProvider> raster_context_provider_; + const raw_ptr<viz::RasterContextProvider> context_provider_; const raw_ptr<viz::SharedBitmapReporter> shared_bitmap_reporter_; const raw_ptr<viz::ClientResourceProvider, DanglingUntriaged> resource_provider_;
diff --git a/media/renderers/video_resource_updater_unittest.cc b/media/renderers/video_resource_updater_unittest.cc index ba4781dd..45d6b46 100644 --- a/media/renderers/video_resource_updater_unittest.cc +++ b/media/renderers/video_resource_updater_unittest.cc
@@ -93,16 +93,16 @@ std::unique_ptr<VideoResourceUpdater> CreateUpdaterForHardware( bool use_stream_video_draw_quad = false) { return std::make_unique<VideoResourceUpdater>( - context_provider_.get(), /*raster_context_provider=*/nullptr, nullptr, - resource_provider_.get(), use_stream_video_draw_quad, + context_provider_.get(), nullptr, resource_provider_.get(), + use_stream_video_draw_quad, /*use_gpu_memory_buffer_resources=*/false, /*use_r16_texture=*/use_r16_texture_, /*max_resource_size=*/10000); } std::unique_ptr<VideoResourceUpdater> CreateUpdaterForSoftware() { return std::make_unique<VideoResourceUpdater>( - /*context_provider=*/nullptr, /*raster_context_provider=*/nullptr, - &shared_bitmap_reporter_, resource_provider_.get(), + /*context_provider=*/nullptr, &shared_bitmap_reporter_, + resource_provider_.get(), /*use_stream_video_draw_quad=*/false, /*use_gpu_memory_buffer_resources=*/false, /*use_r16_texture=*/false,
diff --git a/net/base/features.cc b/net/base/features.cc index 0750947..bdb72ff5 100644 --- a/net/base/features.cc +++ b/net/base/features.cc
@@ -375,4 +375,14 @@ "ForceThirdPartyCookieBlockingEnabled", base::FEATURE_DISABLED_BY_DEFAULT); +// If the HTTP Cache Transaction write lock should be acquired async with +// sending the HTTP request. +BASE_FEATURE(kAsyncCacheLock, + "AsyncCacheLock", + base::FEATURE_DISABLED_BY_DEFAULT); + +BASE_FEATURE(kEnableEarlyHintsOnHttp11, + "EnableEarlyHintsOnHttp11", + base::FEATURE_DISABLED_BY_DEFAULT); + } // namespace net::features
diff --git a/net/base/features.h b/net/base/features.h index 809f858d..35f5c3091 100644 --- a/net/base/features.h +++ b/net/base/features.h
@@ -395,6 +395,13 @@ // Enables enabling third-party cookie blocking from the command line. NET_EXPORT BASE_DECLARE_FEATURE(kForceThirdPartyCookieBlocking); +// If the HTTP Cache Transaction write lock should be acquired async with +// sending the HTTP request. +NET_EXPORT BASE_DECLARE_FEATURE(kAsyncCacheLock); + +// Enables Early Hints on HTTP/1.1. +NET_EXPORT BASE_DECLARE_FEATURE(kEnableEarlyHintsOnHttp11); + } // namespace net::features #endif // NET_BASE_FEATURES_H_
diff --git a/net/http/http_cache.cc b/net/http/http_cache.cc index f6f9bf3..a4db692 100644 --- a/net/http/http_cache.cc +++ b/net/http/http_cache.cc
@@ -194,7 +194,7 @@ if (entry_) *entry_ = entry; if (transaction_) - transaction_->io_callback().Run(result); + transaction_->cache_io_callback().Run(result); } // Notifies the caller about the operation completion. Returns true if the @@ -890,7 +890,10 @@ DCHECK(entry->GetEntry()); // Always add a new transaction to the queue to maintain FIFO order. entry->add_to_entry_queue.push_back(transaction); - ProcessQueuedTransactions(entry); + // Don't process the transaction if the lock timeout handling is being tested. + if (!bypass_lock_for_test_) { + ProcessQueuedTransactions(entry); + } return ERR_IO_PENDING; } @@ -1045,7 +1048,7 @@ transaction->ResetCachePendingState(); base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( FROM_HERE, - base::BindOnce(transaction->io_callback(), net::ERR_CACHE_RACE)); + base::BindOnce(transaction->cache_io_callback(), net::ERR_CACHE_RACE)); } entry->add_to_entry_queue.clear(); } @@ -1082,7 +1085,7 @@ } // ERR_CACHE_RACE causes the transaction to restart the whole process. for (auto* queued_transaction : list) - queued_transaction->io_callback().Run(net::ERR_CACHE_RACE); + queued_transaction->cache_io_callback().Run(net::ERR_CACHE_RACE); } void HttpCache::RestartHeadersPhaseTransactions(ActiveEntry* entry) { @@ -1093,7 +1096,7 @@ while (it != entry->done_headers_queue.end()) { Transaction* done_headers_transaction = *it; it = entry->done_headers_queue.erase(it); - done_headers_transaction->io_callback().Run(net::ERR_CACHE_RACE); + done_headers_transaction->cache_io_callback().Run(net::ERR_CACHE_RACE); } } @@ -1120,6 +1123,20 @@ } void HttpCache::ProcessAddToEntryQueue(ActiveEntry* entry) { + if (delay_add_transaction_to_entry_for_test_) { + // Post a task to put the AddTransactionToEntry handling at the back of + // the task queue. This allows other tasks (like network IO) to jump + // ahead and simulate different callback ordering for testing. + base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( + FROM_HERE, + base::BindOnce(&HttpCache::ProcessAddToEntryQueueImpl, GetWeakPtr(), + base::UnsafeDanglingUntriaged(entry))); + } else { + ProcessAddToEntryQueueImpl(entry); + } +} + +void HttpCache::ProcessAddToEntryQueueImpl(ActiveEntry* entry) { DCHECK(!entry->add_to_entry_queue.empty()); // Note the entry may be new or may already have a response body written to @@ -1132,7 +1149,7 @@ entry->add_to_entry_queue.erase(entry->add_to_entry_queue.begin()); entry->headers_transaction = transaction; - transaction->io_callback().Run(OK); + transaction->cache_io_callback().Run(OK); } HttpCache::ParallelWritingPattern HttpCache::CanTransactionJoinExistingWriters( @@ -1198,7 +1215,7 @@ ProcessQueuedTransactions(entry); entry->done_headers_queue.erase(entry->done_headers_queue.begin()); - transaction->io_callback().Run(OK); + transaction->cache_io_callback().Run(OK); } void HttpCache::AddTransactionToWriters(
diff --git a/net/http/http_cache.h b/net/http/http_cache.h index ddbcbab..8f4225d 100644 --- a/net/http/http_cache.h +++ b/net/http/http_cache.h
@@ -227,6 +227,10 @@ bypass_lock_after_headers_for_test_ = true; } + void DelayAddTransactionToEntryForTesting() { + delay_add_transaction_to_entry_for_test_ = true; + } + // Causes all transactions created after this point to generate a failure // when attempting to conditionalize a network request. void FailConditionalizationForTest() { @@ -421,9 +425,9 @@ // Makes sure that the backend creation is complete before allowing the // provided transaction to use the object. Returns an error code. - // |transaction| will be notified via its IO callback if this method returns - // ERR_IO_PENDING. The transaction is free to use the backend directly at any - // time after receiving the notification. + // |transaction| will be notified via its Cache IO callback if this method + // returns ERR_IO_PENDING. The transaction is free to use the backend + // directly at any time after receiving the notification. int GetBackendForTransaction(Transaction* transaction); // Dooms the entry selected by |key|, if it is currently in the list of active @@ -431,15 +435,15 @@ void DoomActiveEntry(const std::string& key); // Dooms the entry selected by |key|. |transaction| will be notified via its - // IO callback if this method returns ERR_IO_PENDING. The entry can be - // currently in use or not. If entry is in use and the invoking transaction is - // associated with this entry and this entry is already doomed, this API + // Cache IO callback if this method returns ERR_IO_PENDING. The entry can be + // currently in use or not. If entry is in use and the invoking transaction + // is associated with this entry and this entry is already doomed, this API // should not be invoked. int DoomEntry(const std::string& key, Transaction* transaction); // Dooms the entry selected by |key|. |transaction| will be notified via its - // IO callback if this method returns ERR_IO_PENDING. The entry should not be - // currently in use. + // Cache IO callback if this method returns ERR_IO_PENDING. The entry should + // not be currently in use. int AsyncDoomEntry(const std::string& key, Transaction* transaction); // Dooms the entry associated with a GET for a given url and network @@ -473,25 +477,25 @@ // Opens the disk cache entry associated with |key|, creating the entry if it // does not already exist, returning an ActiveEntry in |*entry|. |transaction| - // will be notified via its IO callback if this method returns ERR_IO_PENDING. - // This should not be called if there already is an active entry associated - // with |key|, e.g. you should call FindActiveEntry first. + // will be notified via its Cache IO callback if this method returns + // ERR_IO_PENDING. This should not be called if there already is an active + // entry associated with |key|, e.g. you should call FindActiveEntry first. int OpenOrCreateEntry(const std::string& key, ActiveEntry** entry, Transaction* transaction); // Opens the disk cache entry associated with |key|, returning an ActiveEntry - // in |*entry|. |transaction| will be notified via its IO callback if this - // method returns ERR_IO_PENDING. This should not be called if there already - // is an active entry associated with |key|, e.g. you should call + // in |*entry|. |transaction| will be notified via its Cache IO callback if + // this method returns ERR_IO_PENDING. This should not be called if there + // already is an active entry associated with |key|, e.g. you should call // FindActiveEntry first. int OpenEntry(const std::string& key, ActiveEntry** entry, Transaction* transaction); // Creates the disk cache entry associated with |key|, returning an - // ActiveEntry in |*entry|. |transaction| will be notified via its IO callback - // if this method returns ERR_IO_PENDING. + // ActiveEntry in |*entry|. |transaction| will be notified via its Cache IO + // callback if this method returns ERR_IO_PENDING. int CreateEntry(const std::string& key, ActiveEntry** entry, Transaction* transaction); @@ -501,7 +505,8 @@ void DestroyEntry(ActiveEntry* entry); // Adds a transaction to an ActiveEntry. This method returns ERR_IO_PENDING - // and the transaction will be notified about completion via its IO callback. + // and the transaction will be notified about completion via a callback to + // cache_io_callback(). // In a failure case, the callback will be invoked with ERR_CACHE_RACE. int AddTransactionToEntry(ActiveEntry* entry, Transaction* transaction); @@ -509,7 +514,7 @@ // If the transaction is responsible for writing the response body, // it becomes the writer and returns OK. In other cases ERR_IO_PENDING is // returned and the transaction will be notified about completion via its - // IO callback. In a failure case, the callback will be invoked with + // Cache IO callback. In a failure case, the callback will be invoked with // ERR_CACHE_RACE. int DoneWithResponseHeaders(ActiveEntry* entry, Transaction* transaction, @@ -559,19 +564,23 @@ // Restarts the headers_transaction by setting its state. Since the // headers_transaction is awaiting an asynchronous operation completion, - // it will be restarted when it's IO callback is invoked. + // it will be restarted when it's Cache IO callback is invoked. void RestartHeadersTransaction(ActiveEntry* entry); // Resumes processing the queued transactions of |entry|. void ProcessQueuedTransactions(ActiveEntry* entry); // Checks if a transaction can be added to the entry. If yes, it will - // invoke the IO callback of the transaction. This is a helper function for - // OnProcessQueuedTransactions. It will take a transaction from + // invoke the Cache IO callback of the transaction. This is a helper function + // for OnProcessQueuedTransactions. It will take a transaction from // add_to_entry_queue and make it a headers_transaction, if one doesn't exist // already. void ProcessAddToEntryQueue(ActiveEntry* entry); + // The implementation is split into a separate function so that it can be + // called with a delay for testing. + void ProcessAddToEntryQueueImpl(ActiveEntry* entry); + // Returns if the transaction can join other transactions for writing to // the cache simultaneously. It is only supported for non-Read only, // GET requests which are not range requests. @@ -665,6 +674,7 @@ bool building_backend_ = false; bool bypass_lock_for_test_ = false; bool bypass_lock_after_headers_for_test_ = false; + bool delay_add_transaction_to_entry_for_test_ = false; bool fail_conditionalization_for_test_ = false; Mode mode_ = NORMAL;
diff --git a/net/http/http_cache_transaction.cc b/net/http/http_cache_transaction.cc index a48ac3aa..dc60fad 100644 --- a/net/http/http_cache_transaction.cc +++ b/net/http/http_cache_transaction.cc
@@ -197,6 +197,8 @@ io_callback_ = base::BindRepeating(&Transaction::OnIOComplete, weak_factory_.GetWeakPtr()); + cache_io_callback_ = base::BindRepeating(&Transaction::OnCacheIOComplete, + weak_factory_.GetWeakPtr()); } HttpCache::Transaction::~Transaction() { @@ -1398,7 +1400,7 @@ new_entry_->opened = true; int rv = cache_->AddTransactionToEntry(new_entry_, this); - DCHECK_EQ(rv, ERR_IO_PENDING); + CHECK_EQ(rv, ERR_IO_PENDING); // If headers phase is already done then we are here because of validation not // matching and creating a new entry. This transaction should be the @@ -1412,14 +1414,25 @@ TransitionToState(STATE_ADD_TO_ENTRY_COMPLETE); + // For a very-select case of creating a new non-range request entry, run the + // AddTransactionToEntry in parallel with sending the network request to + // hide the latency. This will run until the next ERR_IO_PENDING (or + // failure). + if (!partial_ && mode_ == WRITE && + base::FeatureList::IsEnabled(features::kAsyncCacheLock)) { + CHECK(!waiting_for_cache_io_); + waiting_for_cache_io_ = true; + rv = OK; + } + entry_lock_waiting_since_ = TimeTicks::Now(); AddCacheLockTimeoutHandler(new_entry_); return rv; } void HttpCache::Transaction::AddCacheLockTimeoutHandler(ActiveEntry* entry) { - DCHECK(next_state_ == STATE_ADD_TO_ENTRY_COMPLETE || - next_state_ == STATE_FINISH_HEADERS_COMPLETE); + CHECK(next_state_ == STATE_ADD_TO_ENTRY_COMPLETE || + next_state_ == STATE_FINISH_HEADERS_COMPLETE); if ((bypass_lock_for_test_ && next_state_ == STATE_ADD_TO_ENTRY_COMPLETE) || (bypass_lock_after_headers_for_test_ && next_state_ == STATE_FINISH_HEADERS_COMPLETE)) { @@ -1470,15 +1483,19 @@ base::UmaHistogramTimes("HttpCache.AddTransactionToEntry", entry_lock_wait); } - entry_lock_waiting_since_ = TimeTicks(); DCHECK(new_entry_); - cache_pending_ = false; - if (result == OK) - entry_ = new_entry_; + if (!waiting_for_cache_io_) { + entry_lock_waiting_since_ = TimeTicks(); + cache_pending_ = false; - // If there is a failure, the cache should have taken care of new_entry_. - new_entry_ = nullptr; + if (result == OK) { + entry_ = new_entry_; + } + + // If there is a failure, the cache should have taken care of new_entry_. + new_entry_ = nullptr; + } if (result == ERR_CACHE_RACE) { TransitionToState(STATE_HEADERS_PHASE_CANNOT_PROCEED); @@ -1504,8 +1521,9 @@ // TODO(crbug.com/713354) Access timestamp for histograms only if entry is // already written, to avoid data race since cache thread can also access // this. - if (!cache_->IsWritingInProgress(entry())) + if (entry_ && !cache_->IsWritingInProgress(entry())) { open_entry_last_used_ = entry_->GetEntry()->GetLastUsed(); + } // TODO(jkarlin): We should either handle the case or DCHECK. if (result != OK) { @@ -1864,6 +1882,12 @@ TransitionToState(STATE_SEND_REQUEST_COMPLETE); rv = network_trans_->Start(request_, io_callback_, net_log_); + if (rv != ERR_IO_PENDING && waiting_for_cache_io_) { + // queue the state transition until the HttpCache transaction completes + DCHECK(!pending_io_result_); + pending_io_result_ = rv; + rv = ERR_IO_PENDING; + } return rv; } @@ -2324,7 +2348,7 @@ // If the transaction needs to wait because another transaction is still // writing the response body, it will return ERR_IO_PENDING now and the - // io_callback_ will be invoked when the wait is done. + // cache_io_callback_ will be invoked when the wait is done. int rv = cache_->DoneWithResponseHeaders(entry_, this, partial_ != nullptr); DCHECK(!reading_ || rv == OK) << "Expected OK, but got " << rv; @@ -3644,16 +3668,17 @@ return; DCHECK(next_state_ == STATE_ADD_TO_ENTRY_COMPLETE || - next_state_ == STATE_FINISH_HEADERS_COMPLETE); + next_state_ == STATE_FINISH_HEADERS_COMPLETE || waiting_for_cache_io_); if (!cache_) return; - if (next_state_ == STATE_ADD_TO_ENTRY_COMPLETE) + if (next_state_ == STATE_ADD_TO_ENTRY_COMPLETE || waiting_for_cache_io_) { cache_->RemovePendingTransaction(this); - else + } else { DoneWithEntry(false /* entry_is_complete */); - OnIOComplete(ERR_CACHE_LOCK_TIMEOUT); + } + OnCacheIOComplete(ERR_CACHE_LOCK_TIMEOUT); } void HttpCache::Transaction::DoomPartialEntry(bool delete_object) { @@ -4000,7 +4025,46 @@ } void HttpCache::Transaction::OnIOComplete(int result) { - DoLoop(result); + if (waiting_for_cache_io_) { + CHECK_NE(result, ERR_CACHE_RACE); + // If the HttpCache IO hasn't completed yet, queue the IO result + // to be processed when the HttpCache IO completes (or times out). + pending_io_result_ = result; + } else { + DoLoop(result); + } +} + +void HttpCache::Transaction::OnCacheIOComplete(int result) { + if (waiting_for_cache_io_) { + // Handle the case of parallel HttpCache transactions being run against + // network IO. + waiting_for_cache_io_ = false; + cache_pending_ = false; + entry_lock_waiting_since_ = TimeTicks(); + + if (result == OK) { + entry_ = new_entry_; + if (!cache_->IsWritingInProgress(entry())) { + open_entry_last_used_ = entry_->GetEntry()->GetLastUsed(); + } + } else { + // The HttpCache transaction failed or timed out. Bypass the cache in + // this case independent of the state of the network IO callback. + mode_ = NONE; + } + new_entry_ = nullptr; + + // See if there is a pending IO result that completed while the HttpCache + // transaction was being processed that now needs to be processed. + if (pending_io_result_) { + int stored_result = pending_io_result_.value(); + pending_io_result_ = absl::nullopt; + OnIOComplete(stored_result); + } + } else { + DoLoop(result); + } } void HttpCache::Transaction::TransitionToState(State state) {
diff --git a/net/http/http_cache_transaction.h b/net/http/http_cache_transaction.h index b7ef641..85a417fa 100644 --- a/net/http/http_cache_transaction.h +++ b/net/http/http_cache_transaction.h
@@ -104,12 +104,21 @@ // to the cache entry. LoadState GetWriterLoadState() const; - const CompletionRepeatingCallback& io_callback() { return io_callback_; } - void SetIOCallBackForTest(CompletionRepeatingCallback cb) { io_callback_ = cb; } + // Returns the IO callback specific to HTTPCache callbacks. This is done + // indirectly so the callbacks can be replaced when testing. + // TODO(https://crbug.com/1454228/): Find a cleaner way to do this so the + // callback can be called directly. + const CompletionRepeatingCallback& cache_io_callback() { + return cache_io_callback_; + } + void SetCacheIOCallBackForTest(CompletionRepeatingCallback cb) { + cache_io_callback_ = cb; + } + const NetLogWithSource& net_log() const; // Bypasses the cache lock whenever there is lock contention. @@ -575,6 +584,11 @@ // continue its processing. void OnIOComplete(int result); + // Called to signal completion of an asynchronous HTTPCache operation. It + // uses a separate callback from OnIoComplete so that cache transaction + // operations and network IO can be run in parallel. + void OnCacheIOComplete(int result); + // When in a DoLoop, use this to set the next state as it verifies that the // state isn't set twice. void TransitionToState(State state); @@ -611,6 +625,14 @@ State next_state_{STATE_NONE}; + // Set when a HTTPCache transaction is pending in parallel with other IO. + bool waiting_for_cache_io_ = false; + + // If a pending async HTTPCache transaction takes longer than the parallel + // Network IO, this will store the result of the Network IO operation until + // the cache transaction completes (or times out). + absl::optional<int> pending_io_result_ = absl::nullopt; + // Used for tracing. const uint64_t trace_id_; @@ -689,6 +711,7 @@ int effective_load_flags_ = 0; std::unique_ptr<PartialData> partial_; // We are dealing with range requests. CompletionRepeatingCallback io_callback_; + CompletionRepeatingCallback cache_io_callback_; // cache-specific IO callback // Error code to be returned from a subsequent Read call if shared writing // failed in a separate transaction.
diff --git a/net/http/http_cache_unittest.cc b/net/http/http_cache_unittest.cc index 476dd1e..b33ed93 100644 --- a/net/http/http_cache_unittest.cc +++ b/net/http/http_cache_unittest.cc
@@ -780,7 +780,50 @@ } // namespace -using HttpCacheTest = TestWithTaskEnvironment; +using HttpCacheTestBase = TestWithTaskEnvironment; + +enum class AsyncCacheLockTestCase { + kAsyncCacheLockDisabled, + kAsyncCacheLockEnabled, +}; + +class HttpCacheTest + : public HttpCacheTestBase, + public ::testing::WithParamInterface<AsyncCacheLockTestCase> { + public: + HttpCacheTest() { + switch (GetParam()) { + case AsyncCacheLockTestCase::kAsyncCacheLockDisabled: + scoped_feature_list_.InitAndDisableFeature(features::kAsyncCacheLock); + break; + case AsyncCacheLockTestCase::kAsyncCacheLockEnabled: + scoped_feature_list_.InitAndEnableFeature(features::kAsyncCacheLock); + break; + } + } + ~HttpCacheTest() override = default; + + static const char* ParamInfoToString( + const testing::TestParamInfo<AsyncCacheLockTestCase>& info) { + switch (info.param) { + case AsyncCacheLockTestCase::kAsyncCacheLockDisabled: + return "AsyncCacheLockDisabled"; + case AsyncCacheLockTestCase::kAsyncCacheLockEnabled: + return "AsyncCacheLockEnabled"; + } + } + + private: + base::test::ScopedFeatureList scoped_feature_list_; +}; + +INSTANTIATE_TEST_SUITE_P( + All, + HttpCacheTest, + testing::ValuesIn({AsyncCacheLockTestCase::kAsyncCacheLockDisabled, + AsyncCacheLockTestCase::kAsyncCacheLockEnabled}), + HttpCacheTest::ParamInfoToString); + class HttpCacheIOCallbackTest : public HttpCacheTest { public: HttpCacheIOCallbackTest() = default; @@ -823,6 +866,13 @@ } }; +INSTANTIATE_TEST_SUITE_P( + All, + HttpCacheIOCallbackTest, + testing::ValuesIn({AsyncCacheLockTestCase::kAsyncCacheLockDisabled, + AsyncCacheLockTestCase::kAsyncCacheLockEnabled}), + HttpCacheTest::ParamInfoToString); + class HttpSplitCacheKeyTest : public HttpCacheTest { public: HttpSplitCacheKeyTest() = default; @@ -842,10 +892,17 @@ } }; +INSTANTIATE_TEST_SUITE_P( + All, + HttpSplitCacheKeyTest, + testing::ValuesIn({AsyncCacheLockTestCase::kAsyncCacheLockDisabled, + AsyncCacheLockTestCase::kAsyncCacheLockEnabled}), + HttpCacheTest::ParamInfoToString); + //----------------------------------------------------------------------------- // Tests. -TEST_F(HttpCacheTest, CreateThenDestroy) { +TEST_P(HttpCacheTest, CreateThenDestroy) { MockHttpCache cache; std::unique_ptr<HttpTransaction> trans; @@ -853,7 +910,7 @@ ASSERT_TRUE(trans.get()); } -TEST_F(HttpCacheTest, GetBackend) { +TEST_P(HttpCacheTest, GetBackend) { MockHttpCache cache(HttpCache::DefaultBackend::InMemory(0)); disk_cache::Backend* backend; @@ -863,7 +920,7 @@ EXPECT_THAT(cb.GetResult(rv), IsOk()); } -TEST_F(HttpCacheTest, SimpleGET) { +TEST_P(HttpCacheTest, SimpleGET) { MockHttpCache cache; LoadTimingInfo load_timing_info; @@ -880,7 +937,7 @@ // This test verifies that the callback passed to SetConnectedCallback() is // called once for simple GET calls that traverse the cache. -TEST_F(HttpCacheTest, SimpleGET_ConnectedCallback) { +TEST_P(HttpCacheTest, SimpleGET_ConnectedCallback) { MockHttpCache cache; ScopedMockTransaction mock_transaction(kSimpleGET_Transaction); @@ -906,7 +963,7 @@ // This test verifies that when the callback passed to SetConnectedCallback() // returns an error, the transaction fails with that error. -TEST_F(HttpCacheTest, SimpleGET_ConnectedCallbackReturnError) { +TEST_P(HttpCacheTest, SimpleGET_ConnectedCallbackReturnError) { MockHttpCache cache; MockHttpRequest request(kSimpleGET_Transaction); ConnectedHandler connected_handler; @@ -929,7 +986,7 @@ // This test verifies that the callback passed to SetConnectedCallback() is // called once for requests that hit the cache. -TEST_F(HttpCacheTest, SimpleGET_ConnectedCallbackOnCacheHit) { +TEST_P(HttpCacheTest, SimpleGET_ConnectedCallbackOnCacheHit) { MockHttpCache cache; { @@ -970,7 +1027,7 @@ // This test verifies that when the callback passed to SetConnectedCallback() // is called for a request that hit the cache and returns an error, the cache // entry is reusable. -TEST_F(HttpCacheTest, SimpleGET_ConnectedCallbackOnCacheHitReturnError) { +TEST_P(HttpCacheTest, SimpleGET_ConnectedCallbackOnCacheHitReturnError) { MockHttpCache cache; { @@ -1029,7 +1086,7 @@ // This test verifies that when the callback passed to SetConnectedCallback() // returns `ERR_INCONSISTENT_IP_ADDRESS_SPACE`, the cache entry is invalidated. -TEST_F(HttpCacheTest, +TEST_P(HttpCacheTest, SimpleGET_ConnectedCallbackOnCacheHitReturnInconsistentIpError) { MockHttpCache cache; @@ -1092,7 +1149,7 @@ // returns // `ERR_CACHED_IP_ADDRESS_SPACE_BLOCKED_BY_LOCAL_NETWORK_ACCESS_POLICY`, the // cache entry is invalidated, and we'll retry the connection from the network. -TEST_F( +TEST_P( HttpCacheTest, SimpleGET_ConnectedCallbackOnCacheHitReturnLocalNetworkAccessBlockedError) { MockHttpCache cache; @@ -1158,7 +1215,7 @@ // This test verifies that the callback passed to SetConnectedCallback() is // called with the right transport type when the cached entry was originally // fetched via proxy. -TEST_F(HttpCacheTest, SimpleGET_ConnectedCallbackOnCacheHitFromProxy) { +TEST_P(HttpCacheTest, SimpleGET_ConnectedCallbackOnCacheHitFromProxy) { MockHttpCache cache; TransportInfo proxied_transport_info = TestTransportInfo(); @@ -1203,6 +1260,27 @@ ElementsAre(expected_transport_info)); } +TEST_P(HttpCacheTest, SimpleGET_DelayedCacheLock) { + MockHttpCache cache; + LoadTimingInfo load_timing_info; + + // Configure the cache to delay the response for AddTransactionToEntry so it + // gets sequenced behind any other tasks that get generated when starting the + // transaction (i.e. network activity when run in parallel with the cache + // lock). + cache.http_cache()->DelayAddTransactionToEntryForTesting(); + + // Write to the cache. + RunTransactionTestAndGetTiming(cache.http_cache(), kSimpleGET_Transaction, + NetLogWithSource::Make(NetLogSourceType::NONE), + &load_timing_info); + + EXPECT_EQ(1, cache.network_layer()->transaction_count()); + EXPECT_EQ(0, cache.disk_cache()->open_count()); + EXPECT_EQ(1, cache.disk_cache()->create_count()); + TestLoadTimingNetworkRequest(load_timing_info); +} + enum class SplitCacheTestCase { kSplitCacheDisabled, kSplitCacheNikFrameSiteEnabled, @@ -1233,7 +1311,7 @@ } class HttpCacheTest_SplitCacheFeature - : public HttpCacheTest, + : public HttpCacheTestBase, public ::testing::WithParamInterface<SplitCacheTestCase> { public: HttpCacheTest_SplitCacheFeature() { @@ -1315,7 +1393,7 @@ } }); -TEST_F(HttpCacheTest, SimpleGETNoDiskCache) { +TEST_P(HttpCacheTest, SimpleGETNoDiskCache) { MockHttpCache cache; cache.disk_cache()->set_fail_requests(true); @@ -1348,7 +1426,7 @@ TestLoadTimingNetworkRequest(load_timing_info); } -TEST_F(HttpCacheTest, SimpleGETNoDiskCache2) { +TEST_P(HttpCacheTest, SimpleGETNoDiskCache2) { // This will initialize a cache object with NULL backend. auto factory = std::make_unique<MockBlockingBackendFactory>(); factory->set_fail(true); @@ -1363,7 +1441,7 @@ } // Tests that IOBuffers are not referenced after IO completes. -TEST_F(HttpCacheTest, ReleaseBuffer) { +TEST_P(HttpCacheTest, ReleaseBuffer) { MockHttpCache cache; // Write to the cache. @@ -1384,7 +1462,7 @@ EXPECT_EQ(kBufferSize, cb.GetResult(rv)); } -TEST_F(HttpCacheTest, SimpleGETWithDiskFailures) { +TEST_P(HttpCacheTest, SimpleGETWithDiskFailures) { MockHttpCache cache; cache.disk_cache()->set_soft_failures_mask(MockDiskEntry::FAIL_ALL); @@ -1406,7 +1484,7 @@ // Tests that disk failures after the transaction has started don't cause the // request to fail. -TEST_F(HttpCacheTest, SimpleGETWithDiskFailures2) { +TEST_P(HttpCacheTest, SimpleGETWithDiskFailures2) { MockHttpCache cache; MockHttpRequest request(kSimpleGET_Transaction); @@ -1443,7 +1521,7 @@ } // Tests that we handle failures to read from the cache. -TEST_F(HttpCacheTest, SimpleGETWithDiskFailures3) { +TEST_P(HttpCacheTest, SimpleGETWithDiskFailures3) { MockHttpCache cache; // Read from the network, and write to the cache. @@ -1479,7 +1557,7 @@ EXPECT_EQ(3, cache.disk_cache()->create_count()); } -TEST_F(HttpCacheTest, SimpleGET_LoadOnlyFromCache_Hit) { +TEST_P(HttpCacheTest, SimpleGET_LoadOnlyFromCache_Hit) { MockHttpCache cache; RecordingNetLogObserver net_log_observer; @@ -1546,7 +1624,7 @@ TestLoadTimingCachedResponse(load_timing_info); } -TEST_F(HttpCacheTest, SimpleGET_LoadOnlyFromCache_Miss) { +TEST_P(HttpCacheTest, SimpleGET_LoadOnlyFromCache_Miss) { MockHttpCache cache; // force this transaction to read from the cache @@ -1571,7 +1649,7 @@ EXPECT_EQ(0, cache.disk_cache()->create_count()); } -TEST_F(HttpCacheTest, SimpleGET_LoadPreferringCache_Hit) { +TEST_P(HttpCacheTest, SimpleGET_LoadPreferringCache_Hit) { MockHttpCache cache; // write to the cache @@ -1588,7 +1666,7 @@ EXPECT_EQ(1, cache.disk_cache()->create_count()); } -TEST_F(HttpCacheTest, SimpleGET_LoadPreferringCache_Miss) { +TEST_P(HttpCacheTest, SimpleGET_LoadPreferringCache_Miss) { MockHttpCache cache; // force this transaction to read from the cache if valid @@ -1603,7 +1681,7 @@ } // Tests LOAD_SKIP_CACHE_VALIDATION in the presence of vary headers. -TEST_F(HttpCacheTest, SimpleGET_LoadPreferringCache_VaryMatch) { +TEST_P(HttpCacheTest, SimpleGET_LoadPreferringCache_VaryMatch) { MockHttpCache cache; // Write to the cache. @@ -1625,7 +1703,7 @@ } // Tests LOAD_SKIP_CACHE_VALIDATION in the presence of vary headers. -TEST_F(HttpCacheTest, SimpleGET_LoadPreferringCache_VaryMismatch) { +TEST_P(HttpCacheTest, SimpleGET_LoadPreferringCache_VaryMismatch) { MockHttpCache cache; // Write to the cache. @@ -1653,7 +1731,7 @@ } // Tests that we honor Vary: * with LOAD_SKIP_CACHE_VALIDATION (crbug/778681) -TEST_F(HttpCacheTest, SimpleGET_LoadSkipCacheValidation_VaryStar) { +TEST_P(HttpCacheTest, SimpleGET_LoadSkipCacheValidation_VaryStar) { MockHttpCache cache; // Write to the cache. @@ -1680,7 +1758,7 @@ // Tests that was_cached was set properly on a failure, even if the cached // response wasn't returned. -TEST_F(HttpCacheTest, SimpleGET_CacheSignal_Failure) { +TEST_P(HttpCacheTest, SimpleGET_CacheSignal_Failure) { for (bool use_memory_entry_data : {false, true}) { MockHttpCache cache; cache.disk_cache()->set_support_in_memory_entry_data(use_memory_entry_data); @@ -1731,7 +1809,7 @@ // Tests that if the transaction is destroyed right after setting the // cache_entry_status_ as CANT_CONDITIONALIZE, then RecordHistograms should not // hit a dcheck. -TEST_F(HttpCacheTest, RecordHistogramsCantConditionalize) { +TEST_P(HttpCacheTest, RecordHistogramsCantConditionalize) { MockHttpCache cache; cache.disk_cache()->set_support_in_memory_entry_data(true); @@ -1760,7 +1838,7 @@ } // Confirm if we have an empty cache, a read is marked as network verified. -TEST_F(HttpCacheTest, SimpleGET_NetworkAccessed_Network) { +TEST_P(HttpCacheTest, SimpleGET_NetworkAccessed_Network) { MockHttpCache cache; // write to the cache @@ -1778,7 +1856,7 @@ // Confirm if we have a fresh entry in cache, it isn't marked as // network verified. -TEST_F(HttpCacheTest, SimpleGET_NetworkAccessed_Cache) { +TEST_P(HttpCacheTest, SimpleGET_NetworkAccessed_Cache) { MockHttpCache cache; // Prime cache. @@ -1798,7 +1876,7 @@ EXPECT_EQ(CacheEntryStatus::ENTRY_USED, response_info.cache_entry_status); } -TEST_F(HttpCacheTest, SimpleGET_LoadBypassCache) { +TEST_P(HttpCacheTest, SimpleGET_LoadBypassCache) { MockHttpCache cache; // Write to the cache. @@ -1843,7 +1921,7 @@ TestLoadTimingNetworkRequest(load_timing_info); } -TEST_F(HttpCacheTest, SimpleGET_LoadBypassCache_Implicit) { +TEST_P(HttpCacheTest, SimpleGET_LoadBypassCache_Implicit) { MockHttpCache cache; // write to the cache @@ -1860,7 +1938,7 @@ EXPECT_EQ(2, cache.disk_cache()->create_count()); } -TEST_F(HttpCacheTest, SimpleGET_LoadBypassCache_Implicit2) { +TEST_P(HttpCacheTest, SimpleGET_LoadBypassCache_Implicit2) { MockHttpCache cache; // write to the cache @@ -1877,7 +1955,7 @@ EXPECT_EQ(2, cache.disk_cache()->create_count()); } -TEST_F(HttpCacheTest, SimpleGET_LoadValidateCache) { +TEST_P(HttpCacheTest, SimpleGET_LoadValidateCache) { MockHttpCache cache; // Write to the cache. @@ -1903,7 +1981,7 @@ TestLoadTimingNetworkRequest(load_timing_info); } -TEST_F(HttpCacheTest, SimpleGET_LoadValidateCache_Implicit) { +TEST_P(HttpCacheTest, SimpleGET_LoadValidateCache_Implicit) { MockHttpCache cache; // write to the cache @@ -1925,7 +2003,7 @@ // Tests that |unused_since_prefetch| is updated accordingly (e.g. it is set to // true after a prefetch and set back to false when the prefetch is used). -TEST_F(HttpCacheTest, SimpleGET_UnusedSincePrefetch) { +TEST_P(HttpCacheTest, SimpleGET_UnusedSincePrefetch) { MockHttpCache cache; HttpResponseInfo response_info; @@ -1971,7 +2049,7 @@ // in HttpResponseInfo entries with the |restricted_prefetch| flag set. Also // tests that responses with |restricted_prefetch| flag set can only be used by // requests that have the LOAD_CAN_USE_RESTRICTED_PREFETCH load flag. -TEST_F(HttpCacheTest, SimpleGET_RestrictedPrefetchIsRestrictedUntilReuse) { +TEST_P(HttpCacheTest, SimpleGET_RestrictedPrefetchIsRestrictedUntilReuse) { MockHttpCache cache; HttpResponseInfo response_info; @@ -2017,7 +2095,7 @@ EXPECT_FALSE(response_info.network_accessed); } -TEST_F(HttpCacheTest, SimpleGET_RestrictedPrefetchReuseIsLimited) { +TEST_P(HttpCacheTest, SimpleGET_RestrictedPrefetchReuseIsLimited) { MockHttpCache cache; HttpResponseInfo response_info; @@ -2053,7 +2131,7 @@ EXPECT_FALSE(response_info.network_accessed); } -TEST_F(HttpCacheTest, SimpleGET_UnusedSincePrefetchWriteError) { +TEST_P(HttpCacheTest, SimpleGET_UnusedSincePrefetchWriteError) { MockHttpCache cache; HttpResponseInfo response_info; @@ -2075,7 +2153,7 @@ // Make sure that if a prefetch entry is truncated, then an attempt to re-use it // gets aborted in connected handler that truncated bit is not lost. -TEST_F(HttpCacheTest, PrefetchTruncateCancelInConnectedCallback) { +TEST_P(HttpCacheTest, PrefetchTruncateCancelInConnectedCallback) { MockHttpCache cache; ScopedMockTransaction transaction(kSimpleGET_Transaction); @@ -2152,7 +2230,7 @@ // Make sure that if a stale-while-revalidate entry is truncated, then an // attempt to re-use it gets aborted in connected handler that truncated bit is // not lost. -TEST_F(HttpCacheTest, StaleWhiteRevalidateTruncateCancelInConnectedCallback) { +TEST_P(HttpCacheTest, StaleWhiteRevalidateTruncateCancelInConnectedCallback) { MockHttpCache cache; ScopedMockTransaction transaction(kSimpleGET_Transaction); @@ -2234,7 +2312,7 @@ } // Tests that we don't remove extra headers for simple requests. -TEST_F(HttpCacheTest, SimpleGET_PreserveRequestHeaders) { +TEST_P(HttpCacheTest, SimpleGET_PreserveRequestHeaders) { for (bool use_memory_entry_data : {false, true}) { MockHttpCache cache; cache.disk_cache()->set_support_in_memory_entry_data(use_memory_entry_data); @@ -2265,7 +2343,7 @@ } // Tests that we don't remove extra headers for conditionalized requests. -TEST_F(HttpCacheTest, ConditionalizedGET_PreserveRequestHeaders) { +TEST_P(HttpCacheTest, ConditionalizedGET_PreserveRequestHeaders) { for (bool use_memory_entry_data : {false, true}) { MockHttpCache cache; // Unlike in SimpleGET_PreserveRequestHeaders, this entry can be @@ -2289,7 +2367,7 @@ } } -TEST_F(HttpCacheTest, SimpleGET_ManyReaders) { +TEST_P(HttpCacheTest, SimpleGET_ManyReaders) { MockHttpCache cache; MockHttpRequest request(kSimpleGET_Transaction); @@ -2351,7 +2429,7 @@ EXPECT_EQ(1, cache.disk_cache()->create_count()); } -TEST_F(HttpCacheTest, RangeGET_FullAfterPartial) { +TEST_P(HttpCacheTest, RangeGET_FullAfterPartial) { MockHttpCache cache; // Request a prefix. @@ -2398,7 +2476,7 @@ // Tests that when a range request transaction becomes a writer for the first // range and then fails conditionalization for the next range and decides to // doom the entry, then there should not be a dcheck assertion hit. -TEST_F(HttpCacheTest, RangeGET_OverlappingRangesCouldntConditionalize) { +TEST_P(HttpCacheTest, RangeGET_OverlappingRangesCouldntConditionalize) { MockHttpCache cache; { @@ -2439,7 +2517,7 @@ } } -TEST_F(HttpCacheTest, RangeGET_FullAfterPartialReuse) { +TEST_P(HttpCacheTest, RangeGET_FullAfterPartialReuse) { MockHttpCache cache; // Request a prefix. @@ -2505,7 +2583,7 @@ // This test verifies that the ConnectedCallback passed to a cache transaction // is called once per subrange in the case of a range request with a partial // cache hit. -TEST_F(HttpCacheTest, RangeGET_ConnectedCallbackCalledForEachRange) { +TEST_P(HttpCacheTest, RangeGET_ConnectedCallbackCalledForEachRange) { MockHttpCache cache; // Request an infix range and populate the cache with it. @@ -2567,7 +2645,7 @@ // This test verifies that when the ConnectedCallback passed to a cache range // transaction returns an `ERR_INCONSISTENT_IP_ADDRESS_SPACE` error during a // partial read from cache, then the cache entry is invalidated. -TEST_F(HttpCacheTest, RangeGET_ConnectedCallbackReturnInconsistentIpError) { +TEST_P(HttpCacheTest, RangeGET_ConnectedCallbackReturnInconsistentIpError) { MockHttpCache cache; // Request an infix range and populate the cache with it. @@ -2658,7 +2736,7 @@ // This test verifies that when the ConnectedCallback passed to a cache range // transaction returns an `ERR_INCONSISTENT_IP_ADDRESS_SPACE` error during a // network transaction, then the cache entry is invalidated. -TEST_F(HttpCacheTest, +TEST_P(HttpCacheTest, RangeGET_ConnectedCallbackReturnInconsistentIpErrorForNetwork) { MockHttpCache cache; @@ -2746,7 +2824,7 @@ // transaction returns an error for the second (or third) subrange transaction, // the overall cache transaction fails with that error. The cache entry is still // usable after that. -TEST_F(HttpCacheTest, RangeGET_ConnectedCallbackReturnErrorSecondTime) { +TEST_P(HttpCacheTest, RangeGET_ConnectedCallbackReturnErrorSecondTime) { MockHttpCache cache; // Request an infix range and populate the cache with it. @@ -2842,7 +2920,7 @@ // This test verifies that the ConnectedCallback passed to a cache transaction // is called once per subrange in the case of a range request with a partial // cache hit, even when a prefix of the range is cached. -TEST_F(HttpCacheTest, RangeGET_ConnectedCallbackCalledForEachRangeWithPrefix) { +TEST_P(HttpCacheTest, RangeGET_ConnectedCallbackCalledForEachRangeWithPrefix) { MockHttpCache cache; // Request a prefix range and populate the cache with it. @@ -2894,7 +2972,7 @@ // Tests that a range transaction is still usable even if it's unable to access // the cache. -TEST_F(HttpCacheTest, RangeGET_FailedCacheAccess) { +TEST_P(HttpCacheTest, RangeGET_FailedCacheAccess) { MockHttpCache cache; ScopedMockTransaction transaction(kRangeGET_TransactionOK); @@ -2928,7 +3006,7 @@ } // Tests that we can have parallel validation on range requests. -TEST_F(HttpCacheTest, RangeGET_ParallelValidationNoMatch) { +TEST_P(HttpCacheTest, RangeGET_ParallelValidationNoMatch) { MockHttpCache cache; ScopedMockTransaction transaction(kRangeGET_TransactionOK); @@ -2991,7 +3069,7 @@ // Tests that if a transaction is dooming the entry and the entry was doomed by // another transaction that was not part of the entry and created a new entry, // the new entry should not be incorrectly doomed. (crbug.com/736993) -TEST_F(HttpCacheTest, RangeGET_ParallelValidationNoMatchDoomEntry) { +TEST_P(HttpCacheTest, RangeGET_ParallelValidationNoMatchDoomEntry) { MockHttpCache cache; ScopedMockTransaction transaction(kRangeGET_TransactionOK); @@ -3077,7 +3155,7 @@ // Same as above but tests that the 2nd transaction does not do anything if // there is nothing to doom. (crbug.com/736993) -TEST_F(HttpCacheTest, RangeGET_ParallelValidationNoMatchDoomEntry1) { +TEST_P(HttpCacheTest, RangeGET_ParallelValidationNoMatchDoomEntry1) { MockHttpCache cache; ScopedMockTransaction transaction(kRangeGET_TransactionOK); @@ -3165,7 +3243,7 @@ } // Tests parallel validation on range requests with non-overlapping ranges. -TEST_F(HttpCacheTest, RangeGET_ParallelValidationDifferentRanges) { +TEST_P(HttpCacheTest, RangeGET_ParallelValidationDifferentRanges) { MockHttpCache cache; ScopedMockTransaction transaction(kRangeGET_TransactionOK); @@ -3268,7 +3346,7 @@ } // Tests that a request does not create Writers when readers is not empty. -TEST_F(HttpCacheTest, RangeGET_DoNotCreateWritersWhenReaderExists) { +TEST_P(HttpCacheTest, RangeGET_DoNotCreateWritersWhenReaderExists) { MockHttpCache cache; // Save a request in the cache so that the next request can become a @@ -3314,7 +3392,7 @@ // Tests parallel validation on range requests can be successfully restarted // when there is a cache lock timeout. -TEST_F(HttpCacheTest, RangeGET_ParallelValidationCacheLockTimeout) { +TEST_P(HttpCacheTest, RangeGET_ParallelValidationCacheLockTimeout) { MockHttpCache cache; ScopedMockTransaction transaction(kRangeGET_TransactionOK); @@ -3403,7 +3481,7 @@ // Tests a full request and a simultaneous range request and the range request // dooms the entry created by the full request due to not being able to // conditionalize. -TEST_F(HttpCacheTest, RangeGET_ParallelValidationCouldntConditionalize) { +TEST_P(HttpCacheTest, RangeGET_ParallelValidationCouldntConditionalize) { MockHttpCache cache; MockTransaction mock_transaction(kSimpleGET_Transaction); @@ -3489,7 +3567,7 @@ // Tests a 200 request and a simultaneous range request where conditionalization // is possible. -TEST_F(HttpCacheTest, RangeGET_ParallelValidationCouldConditionalize) { +TEST_P(HttpCacheTest, RangeGET_ParallelValidationCouldConditionalize) { MockHttpCache cache; MockTransaction mock_transaction(kSimpleGET_Transaction); @@ -3573,7 +3651,7 @@ } // Tests parallel validation on range requests with overlapping ranges. -TEST_F(HttpCacheTest, RangeGET_ParallelValidationOverlappingRanges) { +TEST_P(HttpCacheTest, RangeGET_ParallelValidationOverlappingRanges) { MockHttpCache cache; ScopedMockTransaction transaction(kRangeGET_TransactionOK); @@ -3676,7 +3754,7 @@ // Tests parallel validation on range requests with overlapping ranges and the // impact of deleting the writer on transactions that have validated. -TEST_F(HttpCacheTest, RangeGET_ParallelValidationRestartDoneHeaders) { +TEST_P(HttpCacheTest, RangeGET_ParallelValidationRestartDoneHeaders) { MockHttpCache cache; ScopedMockTransaction transaction(kRangeGET_TransactionOK); @@ -3774,7 +3852,7 @@ } // A test of doing a range request to a cached 301 response -TEST_F(HttpCacheTest, RangeGET_CachedRedirect) { +TEST_P(HttpCacheTest, RangeGET_CachedRedirect) { RangeTransactionServer handler; handler.set_redirect(true); @@ -3874,7 +3952,7 @@ // A transaction that fails to validate an entry, while attempting to write // the response, should still get data to its consumer even if the attempt to // create a new entry fails. -TEST_F(HttpCacheTest, SimpleGET_ValidationFailureWithCreateFailure) { +TEST_P(HttpCacheTest, SimpleGET_ValidationFailureWithCreateFailure) { MockHttpCache cache; MockHttpRequest request(kSimpleGET_Transaction); request.load_flags |= LOAD_VALIDATE_CACHE; @@ -3935,7 +4013,7 @@ } // Parallel validation results in 200. -TEST_F(HttpCacheTest, SimpleGET_ParallelValidationNoMatch) { +TEST_P(HttpCacheTest, SimpleGET_ParallelValidationNoMatch) { MockHttpCache cache; MockHttpRequest request(kSimpleGET_Transaction); request.load_flags |= LOAD_VALIDATE_CACHE; @@ -3985,7 +4063,7 @@ EXPECT_EQ(5, cache.disk_cache()->create_count()); } -TEST_F(HttpCacheTest, RangeGET_Enormous) { +TEST_P(HttpCacheTest, RangeGET_Enormous) { // Test for how blockfile's limit on range namespace interacts with // HttpCache::Transaction. // See https://crbug.com/770694 @@ -4054,7 +4132,7 @@ // Parallel validation results in 200 for 1 transaction and validation matches // for subsequent transactions. -TEST_F(HttpCacheTest, SimpleGET_ParallelValidationNoMatch1) { +TEST_P(HttpCacheTest, SimpleGET_ParallelValidationNoMatch1) { MockHttpCache cache; MockHttpRequest request(kSimpleGET_Transaction); @@ -4115,7 +4193,7 @@ // Tests that a GET followed by a DELETE results in DELETE immediately starting // the headers phase and the entry is doomed. -TEST_F(HttpCacheTest, SimpleGET_ParallelValidationDelete) { +TEST_P(HttpCacheTest, SimpleGET_ParallelValidationDelete) { MockHttpCache cache; MockHttpRequest request(kSimpleGET_Transaction); @@ -4179,7 +4257,7 @@ // Tests that a transaction which is in validated queue can be destroyed without // any impact to other transactions. -TEST_F(HttpCacheTest, SimpleGET_ParallelValidationCancelValidated) { +TEST_P(HttpCacheTest, SimpleGET_ParallelValidationCancelValidated) { MockHttpCache cache; MockHttpRequest request(kSimpleGET_Transaction); @@ -4233,7 +4311,7 @@ // Tests that an idle writer transaction can be deleted without impacting the // existing writers. -TEST_F(HttpCacheTest, SimpleGET_ParallelWritingCancelIdleTransaction) { +TEST_P(HttpCacheTest, SimpleGET_ParallelWritingCancelIdleTransaction) { MockHttpCache cache; MockHttpRequest request(kSimpleGET_Transaction); @@ -4281,7 +4359,7 @@ // Tests that a transaction which is in validated queue can timeout and start // the headers phase again. -TEST_F(HttpCacheTest, SimpleGET_ParallelValidationValidatedTimeout) { +TEST_P(HttpCacheTest, SimpleGET_ParallelValidationValidatedTimeout) { MockHttpCache cache; MockHttpRequest request(kSimpleGET_Transaction); @@ -4336,7 +4414,7 @@ // Tests that a transaction which is in readers can be destroyed without // any impact to other transactions. -TEST_F(HttpCacheTest, SimpleGET_ParallelValidationCancelReader) { +TEST_P(HttpCacheTest, SimpleGET_ParallelValidationCancelReader) { MockHttpCache cache; MockHttpRequest request(kSimpleGET_Transaction); @@ -4433,7 +4511,7 @@ // Tests that when the only writer goes away, it immediately cleans up rather // than wait for the network request to finish. See https://crbug.com/804868. -TEST_F(HttpCacheTest, SimpleGET_HangingCacheWriteCleanup) { +TEST_P(HttpCacheTest, SimpleGET_HangingCacheWriteCleanup) { MockHttpCache mock_cache; MockHttpRequest request(kSimpleGET_Transaction); @@ -4476,7 +4554,7 @@ // Tests that a transaction writer can be destroyed mid-read. // A waiting for read transaction should be able to read the data that was // driven by the Read started by the cancelled writer. -TEST_F(HttpCacheTest, SimpleGET_ParallelWritingCancelWriter) { +TEST_P(HttpCacheTest, SimpleGET_ParallelWritingCancelWriter) { MockHttpCache cache; MockHttpRequest request(kSimpleGET_Transaction); @@ -4565,7 +4643,7 @@ // Tests the case when network read failure happens. Idle and waiting // transactions should fail and headers transaction should be restarted. -TEST_F(HttpCacheTest, SimpleGET_ParallelWritingNetworkReadFailed) { +TEST_P(HttpCacheTest, SimpleGET_ParallelWritingNetworkReadFailed) { MockHttpCache cache; ScopedMockTransaction fail_transaction(kSimpleGET_Transaction); @@ -4645,7 +4723,7 @@ // Tests the case when cache write failure happens. Idle and waiting // transactions should fail and headers transaction should be restarted. -TEST_F(HttpCacheTest, SimpleGET_ParallelWritingCacheWriteFailed) { +TEST_P(HttpCacheTest, SimpleGET_ParallelWritingCacheWriteFailed) { MockHttpCache cache; MockHttpRequest request(kSimpleGET_Transaction); @@ -4742,7 +4820,7 @@ // TODO(shivanisha) Testing this because it is allowed by the code but looks // like the code should disallow two POSTs without LOAD_ONLY_FROM_CACHE with the // same upload data identifier to map to the same entry. -TEST_F(HttpCacheTest, SimplePOST_ParallelWritingDisallowed) { +TEST_P(HttpCacheTest, SimplePOST_ParallelWritingDisallowed) { MockHttpCache cache; MockTransaction transaction(kSimplePOST_Transaction); @@ -4803,7 +4881,7 @@ // Tests the case when parallel writing succeeds. Tests both idle and waiting // transactions. -TEST_F(HttpCacheTest, SimpleGET_ParallelWritingSuccess) { +TEST_P(HttpCacheTest, SimpleGET_ParallelWritingSuccess) { MockHttpCache cache; MockHttpRequest request(kSimpleGET_Transaction); @@ -4886,7 +4964,7 @@ // Tests the case when parallel writing involves things bigger than what cache // can store. In this case, the best we can do is re-fetch it. -TEST_F(HttpCacheTest, SimpleGET_ParallelWritingHuge) { +TEST_P(HttpCacheTest, SimpleGET_ParallelWritingHuge) { MockHttpCache cache; cache.disk_cache()->set_max_file_size(10); @@ -4959,7 +5037,7 @@ // transaction that created the network transaction becomes a reader. Also // verifies that the network bytes are only attributed to the transaction that // created the network transaction. -TEST_F(HttpCacheTest, SimpleGET_ParallelWritingVerifyNetworkBytes) { +TEST_P(HttpCacheTest, SimpleGET_ParallelWritingVerifyNetworkBytes) { MockHttpCache cache; MockHttpRequest request(kSimpleGET_Transaction); @@ -5012,7 +5090,7 @@ } // Tests than extra Read from the consumer should not hang/crash the browser. -TEST_F(HttpCacheTest, SimpleGET_ExtraRead) { +TEST_P(HttpCacheTest, SimpleGET_ExtraRead) { MockHttpCache cache; MockHttpRequest request(kSimpleGET_Transaction); Context c; @@ -5044,7 +5122,7 @@ // Tests when a writer is destroyed mid-read, all the other writer transactions // can continue writing to the entry. -TEST_F(HttpCacheTest, SimpleGET_ParallelValidationCancelWriter) { +TEST_P(HttpCacheTest, SimpleGET_ParallelValidationCancelWriter) { MockHttpCache cache; ScopedMockTransaction transaction(kSimpleGET_Transaction); @@ -5109,7 +5187,7 @@ // Tests that when StopCaching is invoked on a writer, dependent transactions // are restarted. -TEST_F(HttpCacheTest, SimpleGET_ParallelValidationStopCaching) { +TEST_P(HttpCacheTest, SimpleGET_ParallelValidationStopCaching) { MockHttpCache cache; MockHttpRequest request(kSimpleGET_Transaction); @@ -5164,7 +5242,7 @@ // Tests that when StopCaching is invoked on a writer transaction, it is a // no-op if there are other writer transactions. -TEST_F(HttpCacheTest, SimpleGET_ParallelWritersStopCachingNoOp) { +TEST_P(HttpCacheTest, SimpleGET_ParallelWritersStopCachingNoOp) { MockHttpCache cache; MockHttpRequest request(kSimpleGET_Transaction); @@ -5230,7 +5308,7 @@ // Tests that a transaction is currently in headers phase and is destroyed // leading to destroying the entry. -TEST_F(HttpCacheTest, SimpleGET_ParallelValidationCancelHeaders) { +TEST_P(HttpCacheTest, SimpleGET_ParallelValidationCancelHeaders) { MockHttpCache cache; MockHttpRequest request(kSimpleGET_Transaction); @@ -5281,7 +5359,7 @@ // Similar to the above test, except here cache write fails and the // validated transactions should be restarted. -TEST_F(HttpCacheTest, SimpleGET_ParallelWritersFailWrite) { +TEST_P(HttpCacheTest, SimpleGET_ParallelWritersFailWrite) { MockHttpCache cache; MockHttpRequest request(kSimpleGET_Transaction); @@ -5358,7 +5436,7 @@ // If cancelling a request is racing with another request for the same resource // finishing, we have to make sure that we remove both transactions from the // entry. -TEST_F(HttpCacheTest, SimpleGET_RacingReaders) { +TEST_P(HttpCacheTest, SimpleGET_RacingReaders) { MockHttpCache cache; MockHttpRequest request(kSimpleGET_Transaction); @@ -5437,7 +5515,7 @@ // Tests that we can doom an entry with pending transactions and delete one of // the pending transactions before the first one completes. // See http://code.google.com/p/chromium/issues/detail?id=25588 -TEST_F(HttpCacheTest, SimpleGET_DoomWithPending) { +TEST_P(HttpCacheTest, SimpleGET_DoomWithPending) { // We need simultaneous doomed / not_doomed entries so let's use a real cache. MockHttpCache cache(HttpCache::DefaultBackend::InMemory(1024 * 1024)); @@ -5485,7 +5563,7 @@ } } -TEST_F(HttpCacheTest, DoomDoesNotSetHints) { +TEST_P(HttpCacheTest, DoomDoesNotSetHints) { // Test that a doomed writer doesn't set in-memory index hints. MockHttpCache cache; cache.disk_cache()->set_support_in_memory_entry_data(true); @@ -5559,7 +5637,7 @@ // This is a test for http://code.google.com/p/chromium/issues/detail?id=4731. // We may attempt to delete an entry synchronously with the act of adding a new // transaction to said entry. -TEST_F(HttpCacheTest, FastNoStoreGET_DoneWithPending) { +TEST_P(HttpCacheTest, FastNoStoreGET_DoneWithPending) { MockHttpCache cache; // The headers will be served right from the call to Start() the request. @@ -5610,7 +5688,7 @@ RemoveMockTransaction(&kFastNoStoreGET_Transaction); } -TEST_F(HttpCacheTest, SimpleGET_ManyWriters_CancelFirst) { +TEST_P(HttpCacheTest, SimpleGET_ManyWriters_CancelFirst) { MockHttpCache cache; MockHttpRequest request(kSimpleGET_Transaction); @@ -5667,7 +5745,7 @@ // Tests that we can cancel requests that are queued waiting to open the disk // cache entry. -TEST_F(HttpCacheTest, SimpleGET_ManyWriters_CancelCreate) { +TEST_P(HttpCacheTest, SimpleGET_ManyWriters_CancelCreate) { MockHttpCache cache; MockHttpRequest request(kSimpleGET_Transaction); @@ -5717,7 +5795,7 @@ } // Tests that we can cancel a single request to open a disk cache entry. -TEST_F(HttpCacheTest, SimpleGET_CancelCreate) { +TEST_P(HttpCacheTest, SimpleGET_CancelCreate) { MockHttpCache cache; MockHttpRequest request(kSimpleGET_Transaction); @@ -5741,7 +5819,7 @@ } // Tests that we delete/create entries even if multiple requests are queued. -TEST_F(HttpCacheTest, SimpleGET_ManyWriters_BypassCache) { +TEST_P(HttpCacheTest, SimpleGET_ManyWriters_BypassCache) { MockHttpCache cache; MockHttpRequest request(kSimpleGET_Transaction); @@ -5784,7 +5862,7 @@ // Tests that a (simulated) timeout allows transactions waiting on the cache // lock to continue. -TEST_F(HttpCacheTest, SimpleGET_WriterTimeout) { +TEST_P(HttpCacheTest, SimpleGET_WriterTimeout) { MockHttpCache cache; cache.SimulateCacheLockTimeout(); @@ -5809,7 +5887,7 @@ // Tests that a (simulated) timeout allows transactions waiting on the cache // lock to continue but read only transactions to error out. -TEST_F(HttpCacheTest, SimpleGET_WriterTimeoutReadOnlyError) { +TEST_P(HttpCacheTest, SimpleGET_WriterTimeoutReadOnlyError) { MockHttpCache cache; // Simulate timeout. @@ -5835,7 +5913,7 @@ ReadAndVerifyTransaction(c1.trans.get(), kSimpleGET_Transaction); } -TEST_F(HttpCacheTest, SimpleGET_AbandonedCacheRead) { +TEST_P(HttpCacheTest, SimpleGET_AbandonedCacheRead) { MockHttpCache cache; // write to the cache @@ -5866,7 +5944,7 @@ // Tests that we can delete the HttpCache and deal with queued transactions // ("waiting for the backend" as opposed to Active or Doomed entries). -TEST_F(HttpCacheTest, SimpleGET_ManyWriters_DeleteCache) { +TEST_P(HttpCacheTest, SimpleGET_ManyWriters_DeleteCache) { auto cache = std::make_unique<MockHttpCache>( std::make_unique<MockBackendNoCbFactory>()); @@ -5897,7 +5975,7 @@ } // Tests that we queue requests when initializing the backend. -TEST_F(HttpCacheTest, SimpleGET_WaitForBackend) { +TEST_P(HttpCacheTest, SimpleGET_WaitForBackend) { auto factory = std::make_unique<MockBlockingBackendFactory>(); MockBlockingBackendFactory* factory_ptr = factory.get(); MockHttpCache cache(std::move(factory)); @@ -5944,7 +6022,7 @@ // Tests that we can cancel requests that are queued waiting for the backend // to be initialized. -TEST_F(HttpCacheTest, SimpleGET_WaitForBackend_CancelCreate) { +TEST_P(HttpCacheTest, SimpleGET_WaitForBackend_CancelCreate) { auto factory = std::make_unique<MockBlockingBackendFactory>(); MockBlockingBackendFactory* factory_ptr = factory.get(); MockHttpCache cache(std::move(factory)); @@ -5995,7 +6073,7 @@ } // Tests that we can delete the HttpCache while creating the backend. -TEST_F(HttpCacheTest, DeleteCacheWaitingForBackend) { +TEST_P(HttpCacheTest, DeleteCacheWaitingForBackend) { auto factory = std::make_unique<MockBlockingBackendFactory>(); MockBlockingBackendFactory* factory_ptr = factory.get(); auto cache = std::make_unique<MockHttpCache>(std::move(factory)); @@ -6028,7 +6106,7 @@ // Tests that we can delete the cache while creating the backend, from within // one of the callbacks. -TEST_F(HttpCacheTest, DeleteCacheWaitingForBackend2) { +TEST_P(HttpCacheTest, DeleteCacheWaitingForBackend2) { auto factory = std::make_unique<MockBlockingBackendFactory>(); MockBlockingBackendFactory* factory_ptr = factory.get(); auto cache = std::make_unique<MockHttpCache>(std::move(factory)); @@ -6069,7 +6147,7 @@ EXPECT_FALSE(cb2.have_result()); } -TEST_F(HttpCacheTest, TypicalGET_ConditionalRequest) { +TEST_P(HttpCacheTest, TypicalGET_ConditionalRequest) { MockHttpCache cache; // write to the cache @@ -6103,7 +6181,7 @@ response_data->clear(); } -TEST_F(HttpCacheTest, ETagGET_ConditionalRequest_304) { +TEST_P(HttpCacheTest, ETagGET_ConditionalRequest_304) { MockHttpCache cache; ScopedMockTransaction transaction(kETagGET_Transaction); @@ -6179,7 +6257,7 @@ } // Tests revalidation after a vary match. -TEST_F(HttpCacheTest, GET_ValidateCache_VaryMatch) { +TEST_P(HttpCacheTest, GET_ValidateCache_VaryMatch) { MockHttpCache cache; // Write to the cache. @@ -6212,7 +6290,7 @@ } // Tests revalidation after a vary mismatch if etag is present. -TEST_F(HttpCacheTest, GET_ValidateCache_VaryMismatch) { +TEST_P(HttpCacheTest, GET_ValidateCache_VaryMismatch) { MockHttpCache cache; // Write to the cache. @@ -6246,7 +6324,7 @@ } // Tests revalidation after a vary mismatch due to vary: * if etag is present. -TEST_F(HttpCacheTest, GET_ValidateCache_VaryMismatchStar) { +TEST_P(HttpCacheTest, GET_ValidateCache_VaryMismatchStar) { MockHttpCache cache; // Write to the cache. @@ -6278,7 +6356,7 @@ } // Tests lack of revalidation after a vary mismatch and no etag. -TEST_F(HttpCacheTest, GET_DontValidateCache_VaryMismatch) { +TEST_P(HttpCacheTest, GET_DontValidateCache_VaryMismatch) { MockHttpCache cache; // Write to the cache. @@ -6311,7 +6389,7 @@ } // Tests that a new vary header provided when revalidating an entry is saved. -TEST_F(HttpCacheTest, GET_ValidateCache_VaryMatch_UpdateVary) { +TEST_P(HttpCacheTest, GET_ValidateCache_VaryMatch_UpdateVary) { MockHttpCache cache; // Write to the cache. @@ -6350,7 +6428,7 @@ // Tests that new request headers causing a vary mismatch are paired with the // new response when the server says the old response can be used. -TEST_F(HttpCacheTest, GET_ValidateCache_VaryMismatch_UpdateRequestHeader) { +TEST_P(HttpCacheTest, GET_ValidateCache_VaryMismatch_UpdateRequestHeader) { MockHttpCache cache; // Write to the cache. @@ -6385,7 +6463,7 @@ // Tests that a 304 without vary headers doesn't delete the previously stored // vary data after a vary match revalidation. -TEST_F(HttpCacheTest, GET_ValidateCache_VaryMatch_DontDeleteVary) { +TEST_P(HttpCacheTest, GET_ValidateCache_VaryMatch_DontDeleteVary) { MockHttpCache cache; // Write to the cache. @@ -6422,7 +6500,7 @@ // Tests that a 304 without vary headers doesn't delete the previously stored // vary data after a vary mismatch. -TEST_F(HttpCacheTest, GET_ValidateCache_VaryMismatch_DontDeleteVary) { +TEST_P(HttpCacheTest, GET_ValidateCache_VaryMismatch_DontDeleteVary) { MockHttpCache cache; // Write to the cache. @@ -6466,7 +6544,7 @@ request->extra_headers.HasHeader(HttpRequestHeaders::kIfNoneMatch)); } -TEST_F(HttpCacheTest, ETagGET_Http10) { +TEST_P(HttpCacheTest, ETagGET_Http10) { MockHttpCache cache; ScopedMockTransaction transaction(kETagGET_Transaction); @@ -6489,7 +6567,7 @@ EXPECT_EQ(1, cache.disk_cache()->create_count()); } -TEST_F(HttpCacheTest, ETagGET_Http10_Range) { +TEST_P(HttpCacheTest, ETagGET_Http10_Range) { MockHttpCache cache; ScopedMockTransaction transaction(kETagGET_Transaction); @@ -6525,7 +6603,7 @@ response_data->clear(); } -TEST_F(HttpCacheTest, ETagGET_ConditionalRequest_304_NoStore) { +TEST_P(HttpCacheTest, ETagGET_ConditionalRequest_304_NoStore) { MockHttpCache cache; ScopedMockTransaction transaction(kETagGET_Transaction); @@ -6669,7 +6747,7 @@ // Check that when an "if-modified-since" header is attached // to the request, the result still updates the cached entry. -TEST_F(HttpCacheTest, ConditionalizedRequestUpdatesCache1) { +TEST_P(HttpCacheTest, ConditionalizedRequestUpdatesCache1) { // First network response for |kUrl|. static const Response kNetResponse1 = { "HTTP/1.1 200 OK", @@ -6695,7 +6773,7 @@ // Check that when an "if-none-match" header is attached // to the request, the result updates the cached entry. -TEST_F(HttpCacheTest, ConditionalizedRequestUpdatesCache2) { +TEST_P(HttpCacheTest, ConditionalizedRequestUpdatesCache2) { // First network response for |kUrl|. static const Response kNetResponse1 = { "HTTP/1.1 200 OK", @@ -6723,7 +6801,7 @@ // Check that when an "if-modified-since" header is attached // to a request, the 304 (not modified result) result updates the cached // headers, and the 304 response is returned rather than the cached response. -TEST_F(HttpCacheTest, ConditionalizedRequestUpdatesCache3) { +TEST_P(HttpCacheTest, ConditionalizedRequestUpdatesCache3) { // First network response for |kUrl|. static const Response kNetResponse1 = { "HTTP/1.1 200 OK", @@ -6760,7 +6838,7 @@ // Test that when doing an externally conditionalized if-modified-since // and there is no corresponding cache entry, a new cache entry is NOT // created (304 response). -TEST_F(HttpCacheTest, ConditionalizedRequestUpdatesCache4) { +TEST_P(HttpCacheTest, ConditionalizedRequestUpdatesCache4) { MockHttpCache cache; const char kUrl[] = "http://foobar.com/main.css"; @@ -6804,7 +6882,7 @@ // Test that when doing an externally conditionalized if-modified-since // and there is no corresponding cache entry, a new cache entry is NOT // created (200 response). -TEST_F(HttpCacheTest, ConditionalizedRequestUpdatesCache5) { +TEST_P(HttpCacheTest, ConditionalizedRequestUpdatesCache5) { MockHttpCache cache; const char kUrl[] = "http://foobar.com/main.css"; @@ -6849,7 +6927,7 @@ // if the date does not match the cache entry's last-modified date, // then we do NOT use the response (304) to update the cache. // (the if-modified-since date is 2 days AFTER the cache's modification date). -TEST_F(HttpCacheTest, ConditionalizedRequestUpdatesCache6) { +TEST_P(HttpCacheTest, ConditionalizedRequestUpdatesCache6) { static const Response kNetResponse1 = { "HTTP/1.1 200 OK", "Date: Fri, 12 Jun 2009 21:46:42 GMT\n" @@ -6879,7 +6957,7 @@ // Test that when doing an externally conditionalized if-none-match // if the etag does not match the cache entry's etag, then we do not use the // response (304) to update the cache. -TEST_F(HttpCacheTest, ConditionalizedRequestUpdatesCache7) { +TEST_P(HttpCacheTest, ConditionalizedRequestUpdatesCache7) { static const Response kNetResponse1 = { "HTTP/1.1 200 OK", "Date: Fri, 12 Jun 2009 21:46:42 GMT\n" @@ -6906,7 +6984,7 @@ // Test that doing an externally conditionalized request with both if-none-match // and if-modified-since updates the cache. -TEST_F(HttpCacheTest, ConditionalizedRequestUpdatesCache8) { +TEST_P(HttpCacheTest, ConditionalizedRequestUpdatesCache8) { static const Response kNetResponse1 = { "HTTP/1.1 200 OK", "Date: Fri, 12 Jun 2009 21:46:42 GMT\n" @@ -6934,7 +7012,7 @@ // Test that doing an externally conditionalized request with both if-none-match // and if-modified-since does not update the cache with only one match. -TEST_F(HttpCacheTest, ConditionalizedRequestUpdatesCache9) { +TEST_P(HttpCacheTest, ConditionalizedRequestUpdatesCache9) { static const Response kNetResponse1 = { "HTTP/1.1 200 OK", "Date: Fri, 12 Jun 2009 21:46:42 GMT\n" @@ -6963,7 +7041,7 @@ // Test that doing an externally conditionalized request with both if-none-match // and if-modified-since does not update the cache with only one match. -TEST_F(HttpCacheTest, ConditionalizedRequestUpdatesCache10) { +TEST_P(HttpCacheTest, ConditionalizedRequestUpdatesCache10) { static const Response kNetResponse1 = { "HTTP/1.1 200 OK", "Date: Fri, 12 Jun 2009 21:46:42 GMT\n" @@ -6990,7 +7068,7 @@ kNetResponse1, kNetResponse2, kNetResponse1, kExtraRequestHeaders); } -TEST_F(HttpCacheTest, UrlContainingHash) { +TEST_P(HttpCacheTest, UrlContainingHash) { MockHttpCache cache; // Do a typical GET request -- should write an entry into our cache. @@ -7016,7 +7094,7 @@ // Tests that we skip the cache for POST requests that do not have an upload // identifier. -TEST_F(HttpCacheTest, SimplePOST_SkipsCache) { +TEST_P(HttpCacheTest, SimplePOST_SkipsCache) { MockHttpCache cache; RunTransactionTest(cache.http_cache(), kSimplePOST_Transaction); @@ -7027,7 +7105,7 @@ } // Tests POST handling with a disabled cache (no DCHECK). -TEST_F(HttpCacheTest, SimplePOST_DisabledCache) { +TEST_P(HttpCacheTest, SimplePOST_DisabledCache) { MockHttpCache cache; cache.http_cache()->set_mode(HttpCache::Mode::DISABLE); @@ -7038,7 +7116,7 @@ EXPECT_EQ(0, cache.disk_cache()->create_count()); } -TEST_F(HttpCacheTest, SimplePOST_LoadOnlyFromCache_Miss) { +TEST_P(HttpCacheTest, SimplePOST_LoadOnlyFromCache_Miss) { MockHttpCache cache; MockTransaction transaction(kSimplePOST_Transaction); @@ -7061,7 +7139,7 @@ EXPECT_EQ(0, cache.disk_cache()->create_count()); } -TEST_F(HttpCacheTest, SimplePOST_LoadOnlyFromCache_Hit) { +TEST_P(HttpCacheTest, SimplePOST_LoadOnlyFromCache_Hit) { MockHttpCache cache; // Test that we hit the cache for POST requests. @@ -7097,7 +7175,7 @@ } // Test that we don't hit the cache for POST requests if there is a byte range. -TEST_F(HttpCacheTest, SimplePOST_WithRanges) { +TEST_P(HttpCacheTest, SimplePOST_WithRanges) { MockHttpCache cache; MockTransaction transaction(kSimplePOST_Transaction); @@ -7124,7 +7202,7 @@ } // Tests that a POST is cached separately from a GET. -TEST_F(HttpCacheTest, SimplePOST_SeparateCache) { +TEST_P(HttpCacheTest, SimplePOST_SeparateCache) { MockHttpCache cache; std::vector<std::unique_ptr<UploadElementReader>> element_readers; @@ -7153,7 +7231,7 @@ } // Tests that a successful POST invalidates a previously cached GET. -TEST_F(HttpCacheTest, SimplePOST_Invalidate_205) { +TEST_P(HttpCacheTest, SimplePOST_Invalidate_205) { MockHttpCache cache; MockTransaction transaction(kSimpleGET_Transaction); @@ -7260,7 +7338,7 @@ // Tests that a successful POST invalidates a previously cached GET, even when // there is no upload identifier. -TEST_F(HttpCacheTest, SimplePOST_NoUploadId_Invalidate_205) { +TEST_P(HttpCacheTest, SimplePOST_NoUploadId_Invalidate_205) { MockHttpCache cache; MockTransaction transaction(kSimpleGET_Transaction); @@ -7299,7 +7377,7 @@ } // Tests that processing a POST before creating the backend doesn't crash. -TEST_F(HttpCacheTest, SimplePOST_NoUploadId_NoBackend) { +TEST_P(HttpCacheTest, SimplePOST_NoUploadId_NoBackend) { // This will initialize a cache object with NULL backend. auto factory = std::make_unique<MockBlockingBackendFactory>(); factory->set_fail(true); @@ -7322,7 +7400,7 @@ } // Tests that we don't invalidate entries as a result of a failed POST. -TEST_F(HttpCacheTest, SimplePOST_DontInvalidate_100) { +TEST_P(HttpCacheTest, SimplePOST_DontInvalidate_100) { MockHttpCache cache; MockTransaction transaction(kSimpleGET_Transaction); @@ -7361,7 +7439,7 @@ } // Tests that a HEAD request is not cached by itself. -TEST_F(HttpCacheTest, SimpleHEAD_LoadOnlyFromCache_Miss) { +TEST_P(HttpCacheTest, SimpleHEAD_LoadOnlyFromCache_Miss) { MockHttpCache cache; MockTransaction transaction(kSimplePOST_Transaction); AddMockTransaction(&transaction); @@ -7387,7 +7465,7 @@ } // Tests that a HEAD request is served from a cached GET. -TEST_F(HttpCacheTest, SimpleHEAD_LoadOnlyFromCache_Hit) { +TEST_P(HttpCacheTest, SimpleHEAD_LoadOnlyFromCache_Hit) { MockHttpCache cache; MockTransaction transaction(kSimpleGET_Transaction); AddMockTransaction(&transaction); @@ -7412,7 +7490,7 @@ } // Tests that a read-only request served from the cache preserves CL. -TEST_F(HttpCacheTest, SimpleHEAD_ContentLengthOnHit_Read) { +TEST_P(HttpCacheTest, SimpleHEAD_ContentLengthOnHit_Read) { MockHttpCache cache; MockTransaction transaction(kSimpleGET_Transaction); AddMockTransaction(&transaction); @@ -7434,7 +7512,7 @@ } // Tests that a read-write request served from the cache preserves CL. -TEST_F(HttpCacheTest, ETagHEAD_ContentLengthOnHit_ReadWrite) { +TEST_P(HttpCacheTest, ETagHEAD_ContentLengthOnHit_ReadWrite) { MockHttpCache cache; MockTransaction transaction(kETagGET_Transaction); AddMockTransaction(&transaction); @@ -7457,7 +7535,7 @@ } // Tests that a HEAD request that includes byte ranges bypasses the cache. -TEST_F(HttpCacheTest, SimpleHEAD_WithRanges) { +TEST_P(HttpCacheTest, SimpleHEAD_WithRanges) { MockHttpCache cache; MockTransaction transaction(kSimpleGET_Transaction); AddMockTransaction(&transaction); @@ -7477,8 +7555,8 @@ RemoveMockTransaction(&transaction); } -// Tests that a HEAD request can be served from a partialy cached resource. -TEST_F(HttpCacheTest, SimpleHEAD_WithCachedRanges) { +// Tests that a HEAD request can be served from a partially cached resource. +TEST_P(HttpCacheTest, SimpleHEAD_WithCachedRanges) { MockHttpCache cache; AddMockTransaction(&kRangeGET_TransactionOK); @@ -7507,7 +7585,7 @@ } // Tests that a HEAD request can be served from a truncated resource. -TEST_F(HttpCacheTest, SimpleHEAD_WithTruncatedEntry) { +TEST_P(HttpCacheTest, SimpleHEAD_WithTruncatedEntry) { MockHttpCache cache; AddMockTransaction(&kRangeGET_TransactionOK); @@ -7540,7 +7618,7 @@ } // Tests that a HEAD request updates the cached response. -TEST_F(HttpCacheTest, TypicalHEAD_UpdatesResponse) { +TEST_P(HttpCacheTest, TypicalHEAD_UpdatesResponse) { MockHttpCache cache; MockTransaction transaction(kTypicalGET_Transaction); AddMockTransaction(&transaction); @@ -7578,7 +7656,7 @@ } // Tests that an externally conditionalized HEAD request updates the cache. -TEST_F(HttpCacheTest, TypicalHEAD_ConditionalizedRequestUpdatesResponse) { +TEST_P(HttpCacheTest, TypicalHEAD_ConditionalizedRequestUpdatesResponse) { MockHttpCache cache; MockTransaction transaction(kTypicalGET_Transaction); AddMockTransaction(&transaction); @@ -7618,7 +7696,7 @@ } // Tests that a HEAD request invalidates an old cached entry. -TEST_F(HttpCacheTest, SimpleHEAD_InvalidatesEntry) { +TEST_P(HttpCacheTest, SimpleHEAD_InvalidatesEntry) { MockHttpCache cache; MockTransaction transaction(kTypicalGET_Transaction); AddMockTransaction(&transaction); @@ -7642,7 +7720,7 @@ } // Tests that we do not cache the response of a PUT. -TEST_F(HttpCacheTest, SimplePUT_Miss) { +TEST_P(HttpCacheTest, SimplePUT_Miss) { MockHttpCache cache; MockTransaction transaction(kSimplePOST_Transaction); @@ -7666,7 +7744,7 @@ } // Tests that we invalidate entries as a result of a PUT. -TEST_F(HttpCacheTest, SimplePUT_Invalidate) { +TEST_P(HttpCacheTest, SimplePUT_Invalidate) { MockHttpCache cache; MockTransaction transaction(kSimpleGET_Transaction); @@ -7702,7 +7780,7 @@ } // Tests that we invalidate entries as a result of a PUT. -TEST_F(HttpCacheTest, SimplePUT_Invalidate_305) { +TEST_P(HttpCacheTest, SimplePUT_Invalidate_305) { MockHttpCache cache; MockTransaction transaction(kSimpleGET_Transaction); @@ -7741,7 +7819,7 @@ } // Tests that we don't invalidate entries as a result of a failed PUT. -TEST_F(HttpCacheTest, SimplePUT_DontInvalidate_404) { +TEST_P(HttpCacheTest, SimplePUT_DontInvalidate_404) { MockHttpCache cache; MockTransaction transaction(kSimpleGET_Transaction); @@ -7780,7 +7858,7 @@ } // Tests that we do not cache the response of a DELETE. -TEST_F(HttpCacheTest, SimpleDELETE_Miss) { +TEST_P(HttpCacheTest, SimpleDELETE_Miss) { MockHttpCache cache; MockTransaction transaction(kSimplePOST_Transaction); @@ -7804,7 +7882,7 @@ } // Tests that we invalidate entries as a result of a DELETE. -TEST_F(HttpCacheTest, SimpleDELETE_Invalidate) { +TEST_P(HttpCacheTest, SimpleDELETE_Invalidate) { MockHttpCache cache; MockTransaction transaction(kSimpleGET_Transaction); @@ -7840,7 +7918,7 @@ } // Tests that we invalidate entries as a result of a DELETE. -TEST_F(HttpCacheTest, SimpleDELETE_Invalidate_301) { +TEST_P(HttpCacheTest, SimpleDELETE_Invalidate_301) { MockHttpCache cache; MockTransaction transaction(kSimpleGET_Transaction); @@ -7872,7 +7950,7 @@ } // Tests that we don't invalidate entries as a result of a failed DELETE. -TEST_F(HttpCacheTest, SimpleDELETE_DontInvalidate_416) { +TEST_P(HttpCacheTest, SimpleDELETE_DontInvalidate_416) { MockHttpCache cache; MockTransaction transaction(kSimpleGET_Transaction); @@ -7905,7 +7983,7 @@ } // Tests that we invalidate entries as a result of a PATCH. -TEST_F(HttpCacheTest, SimplePATCH_Invalidate) { +TEST_P(HttpCacheTest, SimplePATCH_Invalidate) { MockHttpCache cache; MockTransaction transaction(kSimpleGET_Transaction); @@ -7941,7 +8019,7 @@ } // Tests that we invalidate entries as a result of a PATCH. -TEST_F(HttpCacheTest, SimplePATCH_Invalidate_301) { +TEST_P(HttpCacheTest, SimplePATCH_Invalidate_301) { MockHttpCache cache; MockTransaction transaction(kSimpleGET_Transaction); @@ -7973,7 +8051,7 @@ } // Tests that we don't invalidate entries as a result of a failed PATCH. -TEST_F(HttpCacheTest, SimplePATCH_DontInvalidate_416) { +TEST_P(HttpCacheTest, SimplePATCH_DontInvalidate_416) { MockHttpCache cache; MockTransaction transaction(kSimpleGET_Transaction); @@ -8006,7 +8084,7 @@ } // Tests that we don't invalidate entries after a failed network transaction. -TEST_F(HttpCacheTest, SimpleGET_DontInvalidateOnFailure) { +TEST_P(HttpCacheTest, SimpleGET_DontInvalidateOnFailure) { MockHttpCache cache; // Populate the cache. @@ -8033,7 +8111,7 @@ RemoveMockTransaction(&transaction); } -TEST_F(HttpCacheTest, RangeGET_SkipsCache) { +TEST_P(HttpCacheTest, RangeGET_SkipsCache) { MockHttpCache cache; // Test that we skip the cache for range GET requests. Eventually, we will @@ -8065,7 +8143,7 @@ // Test that we skip the cache for range requests that include a validation // header. -TEST_F(HttpCacheTest, RangeGET_SkipsCache2) { +TEST_P(HttpCacheTest, RangeGET_SkipsCache2) { MockHttpCache cache; MockTransaction transaction(kRangeGET_Transaction); @@ -8098,7 +8176,7 @@ EXPECT_EQ(0, cache.disk_cache()->create_count()); } -TEST_F(HttpCacheTest, SimpleGET_DoesntLogHeaders) { +TEST_P(HttpCacheTest, SimpleGET_DoesntLogHeaders) { MockHttpCache cache; RecordingNetLogObserver net_log_observer; @@ -8109,7 +8187,7 @@ net_log_observer, NetLogEventType::HTTP_CACHE_CALLER_REQUEST_HEADERS)); } -TEST_F(HttpCacheTest, RangeGET_LogsHeaders) { +TEST_P(HttpCacheTest, RangeGET_LogsHeaders) { MockHttpCache cache; RecordingNetLogObserver net_log_observer; @@ -8120,7 +8198,7 @@ net_log_observer, NetLogEventType::HTTP_CACHE_CALLER_REQUEST_HEADERS)); } -TEST_F(HttpCacheTest, ExternalValidation_LogsHeaders) { +TEST_P(HttpCacheTest, ExternalValidation_LogsHeaders) { MockHttpCache cache; RecordingNetLogObserver net_log_observer; @@ -8133,7 +8211,7 @@ net_log_observer, NetLogEventType::HTTP_CACHE_CALLER_REQUEST_HEADERS)); } -TEST_F(HttpCacheTest, SpecialHeaders_LogsHeaders) { +TEST_P(HttpCacheTest, SpecialHeaders_LogsHeaders) { MockHttpCache cache; RecordingNetLogObserver net_log_observer; @@ -8147,7 +8225,7 @@ } // Tests that receiving 206 for a regular request is handled correctly. -TEST_F(HttpCacheTest, GET_Crazy206) { +TEST_P(HttpCacheTest, GET_Crazy206) { MockHttpCache cache; // Write to the cache. @@ -8171,7 +8249,7 @@ } // Tests that receiving 416 for a regular request is handled correctly. -TEST_F(HttpCacheTest, GET_Crazy416) { +TEST_P(HttpCacheTest, GET_Crazy416) { MockHttpCache cache; // Write to the cache. @@ -8188,7 +8266,7 @@ } // Tests that we don't store partial responses that can't be validated. -TEST_F(HttpCacheTest, RangeGET_NoStrongValidators) { +TEST_P(HttpCacheTest, RangeGET_NoStrongValidators) { MockHttpCache cache; std::string headers; @@ -8215,7 +8293,7 @@ } // Tests failures to conditionalize byte range requests. -TEST_F(HttpCacheTest, RangeGET_NoConditionalization) { +TEST_P(HttpCacheTest, RangeGET_NoConditionalization) { MockHttpCache cache; cache.FailConditionalizations(); std::string headers; @@ -8243,7 +8321,7 @@ // Tests that restarting a partial request when the cached data cannot be // revalidated logs an event. -TEST_F(HttpCacheTest, RangeGET_NoValidation_LogsRestart) { +TEST_P(HttpCacheTest, RangeGET_NoValidation_LogsRestart) { MockHttpCache cache; cache.FailConditionalizations(); @@ -8264,7 +8342,7 @@ // Tests that a failure to conditionalize a regular request (no range) with a // sparse entry results in a full response. -TEST_F(HttpCacheTest, GET_NoConditionalization) { +TEST_P(HttpCacheTest, GET_NoConditionalization) { for (bool use_memory_entry_data : {false, true}) { MockHttpCache cache; cache.disk_cache()->set_support_in_memory_entry_data(use_memory_entry_data); @@ -8318,7 +8396,7 @@ // Verifies that conditionalization failures when asking for a range that would // require the cache to modify the range to ask, result in a network request // that matches the user's one. -TEST_F(HttpCacheTest, RangeGET_NoConditionalization2) { +TEST_P(HttpCacheTest, RangeGET_NoConditionalization2) { MockHttpCache cache; cache.FailConditionalizations(); std::string headers; @@ -8356,7 +8434,7 @@ } // Tests that we cache partial responses that lack content-length. -TEST_F(HttpCacheTest, RangeGET_NoContentLength) { +TEST_P(HttpCacheTest, RangeGET_NoContentLength) { MockHttpCache cache; std::string headers; @@ -8388,7 +8466,7 @@ // Tests that we can cache range requests and fetch random blocks from the // cache and the network. -TEST_F(HttpCacheTest, RangeGET_OK) { +TEST_P(HttpCacheTest, RangeGET_OK) { MockHttpCache cache; AddMockTransaction(&kRangeGET_TransactionOK); std::string headers; @@ -8445,7 +8523,7 @@ RemoveMockTransaction(&kRangeGET_TransactionOK); } -TEST_F(HttpCacheTest, RangeGET_CacheReadError) { +TEST_P(HttpCacheTest, RangeGET_CacheReadError) { // Tests recovery on cache read error on range request. MockHttpCache cache; AddMockTransaction(&kRangeGET_TransactionOK); @@ -8478,7 +8556,7 @@ // Tests that range requests with no-store get correct content-length // (https://crbug.com/700197). -TEST_F(HttpCacheTest, RangeGET_NoStore) { +TEST_P(HttpCacheTest, RangeGET_NoStore) { MockHttpCache cache; MockTransaction transaction(kRangeGET_TransactionOK); @@ -8499,7 +8577,7 @@ } // Tests a 304 setting no-store on existing 206 entry. -TEST_F(HttpCacheTest, RangeGET_NoStore304) { +TEST_P(HttpCacheTest, RangeGET_NoStore304) { MockHttpCache cache; MockTransaction transaction(kRangeGET_TransactionOK); @@ -8540,7 +8618,7 @@ // Tests that we can cache range requests and fetch random blocks from the // cache and the network, with synchronous responses. -TEST_F(HttpCacheTest, RangeGET_SyncOK) { +TEST_P(HttpCacheTest, RangeGET_SyncOK) { MockHttpCache cache; MockTransaction transaction(kRangeGET_TransactionOK); @@ -8600,7 +8678,7 @@ // Tests that if the previous transaction is cancelled while busy (doing sparse // IO), a new transaction (that reuses that same ActiveEntry) waits until the // entry is ready again. -TEST_F(HttpCacheTest, Sparse_WaitForEntry) { +TEST_P(HttpCacheTest, Sparse_WaitForEntry) { MockHttpCache cache; ScopedMockTransaction transaction(kRangeGET_TransactionOK); @@ -8629,7 +8707,7 @@ } // Tests that we don't revalidate an entry unless we are required to do so. -TEST_F(HttpCacheTest, RangeGET_Revalidate1) { +TEST_P(HttpCacheTest, RangeGET_Revalidate1) { MockHttpCache cache; std::string headers; @@ -8679,7 +8757,7 @@ } // Checks that we revalidate an entry when the headers say so. -TEST_F(HttpCacheTest, RangeGET_Revalidate2) { +TEST_P(HttpCacheTest, RangeGET_Revalidate2) { MockHttpCache cache; std::string headers; @@ -8711,7 +8789,7 @@ } // Tests that we deal with 304s for range requests. -TEST_F(HttpCacheTest, RangeGET_304) { +TEST_P(HttpCacheTest, RangeGET_304) { MockHttpCache cache; AddMockTransaction(&kRangeGET_TransactionOK); std::string headers; @@ -8741,7 +8819,7 @@ } // Tests that we deal with 206s when revalidating range requests. -TEST_F(HttpCacheTest, RangeGET_ModifiedResult) { +TEST_P(HttpCacheTest, RangeGET_ModifiedResult) { MockHttpCache cache; AddMockTransaction(&kRangeGET_TransactionOK); std::string headers; @@ -8781,7 +8859,7 @@ // the caller as is. In this context, a subrange means a response that starts // with the same byte that was requested, but that is not the whole range that // was requested. -TEST_F(HttpCacheTest, RangeGET_206ReturnsSubrangeRange_NoCachedContent) { +TEST_P(HttpCacheTest, RangeGET_206ReturnsSubrangeRange_NoCachedContent) { MockHttpCache cache; std::string headers; @@ -8805,7 +8883,7 @@ // Tests that when a server returns 206 with a sub-range of the requested range, // and there was an entry stored in the cache, the cache gets out of the way. -TEST_F(HttpCacheTest, RangeGET_206ReturnsSubrangeRange_CachedContent) { +TEST_P(HttpCacheTest, RangeGET_206ReturnsSubrangeRange_CachedContent) { MockHttpCache cache; std::string headers; @@ -8846,7 +8924,7 @@ // Tests that when a server returns 206 with a sub-range of the requested range, // and there was an entry stored in the cache, the cache gets out of the way, // when the caller is not using ranges. -TEST_F(HttpCacheTest, GET_206ReturnsSubrangeRange_CachedContent) { +TEST_P(HttpCacheTest, GET_206ReturnsSubrangeRange_CachedContent) { MockHttpCache cache; std::string headers; @@ -8884,7 +8962,7 @@ // not have any relationship with the requested range (may or may not be // contained). The important part is that the first byte doesn't match the first // requested byte. -TEST_F(HttpCacheTest, RangeGET_206ReturnsWrongRange_NoCachedContent) { +TEST_P(HttpCacheTest, RangeGET_206ReturnsWrongRange_NoCachedContent) { MockHttpCache cache; std::string headers; @@ -8914,7 +8992,7 @@ // Tests that when a server returns 206 with a random range and there is // an entry stored in the cache, the cache gets out of the way. -TEST_F(HttpCacheTest, RangeGET_206ReturnsWrongRange_CachedContent) { +TEST_P(HttpCacheTest, RangeGET_206ReturnsWrongRange_CachedContent) { MockHttpCache cache; std::string headers; @@ -8952,7 +9030,7 @@ // Tests that when a caller asks for a range beyond EOF, with an empty cache, // the response matches the one provided by the server. -TEST_F(HttpCacheTest, RangeGET_206ReturnsSmallerFile_NoCachedContent) { +TEST_P(HttpCacheTest, RangeGET_206ReturnsSmallerFile_NoCachedContent) { MockHttpCache cache; std::string headers; @@ -8973,7 +9051,7 @@ // Tests that when a caller asks for a range beyond EOF, with a cached entry, // the cache automatically fixes the request. -TEST_F(HttpCacheTest, RangeGET_206ReturnsSmallerFile_CachedContent) { +TEST_P(HttpCacheTest, RangeGET_206ReturnsSmallerFile_CachedContent) { MockHttpCache cache; std::string headers; @@ -9000,7 +9078,7 @@ // Tests that when a caller asks for a not-satisfiable range, the server's // response is forwarded to the caller. -TEST_F(HttpCacheTest, RangeGET_416_NoCachedContent) { +TEST_P(HttpCacheTest, RangeGET_416_NoCachedContent) { MockHttpCache cache; std::string headers; @@ -9022,7 +9100,7 @@ } // Tests that we cache 301s for range requests. -TEST_F(HttpCacheTest, RangeGET_301) { +TEST_P(HttpCacheTest, RangeGET_301) { MockHttpCache cache; ScopedMockTransaction transaction(kRangeGET_TransactionOK); transaction.status = "HTTP/1.1 301 Moved Permanently"; @@ -9045,7 +9123,7 @@ // Tests that we can cache range requests when the start or end is unknown. // We start with one suffix request, followed by a request from a given point. -TEST_F(HttpCacheTest, UnknownRangeGET_1) { +TEST_P(HttpCacheTest, UnknownRangeGET_1) { MockHttpCache cache; AddMockTransaction(&kRangeGET_TransactionOK); std::string headers; @@ -9080,7 +9158,7 @@ // Tests that we can cache range requests when the start or end is unknown. // We start with one request from a given point, followed by a suffix request. // We'll also verify that synchronous cache responses work as intended. -TEST_F(HttpCacheTest, UnknownRangeGET_2) { +TEST_P(HttpCacheTest, UnknownRangeGET_2) { MockHttpCache cache; std::string headers; @@ -9118,7 +9196,7 @@ // Similar to UnknownRangeGET_2, except that the resource size is empty. // Regression test for crbug.com/813061, and probably https://crbug.com/1375128 -TEST_F(HttpCacheTest, UnknownRangeGET_3) { +TEST_P(HttpCacheTest, UnknownRangeGET_3) { MockHttpCache cache; std::string headers; @@ -9159,7 +9237,7 @@ // Testcase for https://crbug.com/1433305, validation of range request to a // cache 302, which is notably bodiless. -TEST_F(HttpCacheTest, UnknownRangeGET_302) { +TEST_P(HttpCacheTest, UnknownRangeGET_302) { MockHttpCache cache; std::string headers; @@ -9215,7 +9293,7 @@ // Testcase for https://crbug.com/1433305, validation of range request to a // cache 302, which is notably bodiless, where the 302 is replaced with an // actual body. -TEST_F(HttpCacheTest, UnknownRangeGET_302_Replaced) { +TEST_P(HttpCacheTest, UnknownRangeGET_302_Replaced) { MockHttpCache cache; std::string headers; @@ -9270,7 +9348,7 @@ // Tests that receiving Not Modified when asking for an open range doesn't mess // up things. -TEST_F(HttpCacheTest, UnknownRangeGET_304) { +TEST_P(HttpCacheTest, UnknownRangeGET_304) { MockHttpCache cache; std::string headers; @@ -9298,7 +9376,7 @@ } // Tests that we can handle non-range requests when we have cached a range. -TEST_F(HttpCacheTest, GET_Previous206) { +TEST_P(HttpCacheTest, GET_Previous206) { MockHttpCache cache; AddMockTransaction(&kRangeGET_TransactionOK); std::string headers; @@ -9336,7 +9414,7 @@ // Tests that we can handle non-range requests when we have cached the first // part of the object and the server replies with 304 (Not Modified). -TEST_F(HttpCacheTest, GET_Previous206_NotModified) { +TEST_P(HttpCacheTest, GET_Previous206_NotModified) { MockHttpCache cache; MockTransaction transaction(kRangeGET_TransactionOK); @@ -9388,7 +9466,7 @@ // Tests that we can handle a regular request to a sparse entry, that results in // new content provided by the server (206). -TEST_F(HttpCacheTest, GET_Previous206_NewContent) { +TEST_P(HttpCacheTest, GET_Previous206_NewContent) { MockHttpCache cache; AddMockTransaction(&kRangeGET_TransactionOK); std::string headers; @@ -9433,7 +9511,7 @@ } // Tests that we can handle cached 206 responses that are not sparse. -TEST_F(HttpCacheTest, GET_Previous206_NotSparse) { +TEST_P(HttpCacheTest, GET_Previous206_NotSparse) { MockHttpCache cache; MockHttpRequest request(kSimpleGET_Transaction); @@ -9478,7 +9556,7 @@ // Tests that we can handle cached 206 responses that are not sparse. This time // we issue a range request and expect to receive a range. -TEST_F(HttpCacheTest, RangeGET_Previous206_NotSparse_2) { +TEST_P(HttpCacheTest, RangeGET_Previous206_NotSparse_2) { MockHttpCache cache; AddMockTransaction(&kRangeGET_TransactionOK); @@ -9519,7 +9597,7 @@ } // Tests that we can handle cached 206 responses that can't be validated. -TEST_F(HttpCacheTest, GET_Previous206_NotValidation) { +TEST_P(HttpCacheTest, GET_Previous206_NotValidation) { MockHttpCache cache; MockHttpRequest request(kSimpleGET_Transaction); @@ -9561,7 +9639,7 @@ } // Tests that we can handle range requests with cached 200 responses. -TEST_F(HttpCacheTest, RangeGET_Previous200) { +TEST_P(HttpCacheTest, RangeGET_Previous200) { MockHttpCache cache; // Store the whole thing with status 200. @@ -9630,7 +9708,7 @@ } // Tests that we can handle a 200 response when dealing with sparse entries. -TEST_F(HttpCacheTest, RangeRequestResultsIn200) { +TEST_P(HttpCacheTest, RangeRequestResultsIn200) { MockHttpCache cache; AddMockTransaction(&kRangeGET_TransactionOK); std::string headers; @@ -9670,7 +9748,7 @@ // Tests that a range request that falls outside of the size that we know about // only deletes the entry if the resource has indeed changed. -TEST_F(HttpCacheTest, RangeGET_MoreThanCurrentSize) { +TEST_P(HttpCacheTest, RangeGET_MoreThanCurrentSize) { MockHttpCache cache; AddMockTransaction(&kRangeGET_TransactionOK); std::string headers; @@ -9703,7 +9781,7 @@ } // Tests that we don't delete a sparse entry when we cancel a request. -TEST_F(HttpCacheTest, RangeGET_Cancel) { +TEST_P(HttpCacheTest, RangeGET_Cancel) { MockHttpCache cache; AddMockTransaction(&kRangeGET_TransactionOK); @@ -9741,7 +9819,7 @@ // Tests that we don't mark an entry as truncated if it is partial and not // already truncated. -TEST_F(HttpCacheTest, RangeGET_CancelWhileReading) { +TEST_P(HttpCacheTest, RangeGET_CancelWhileReading) { MockHttpCache cache; AddMockTransaction(&kRangeGET_TransactionOK); @@ -9780,7 +9858,7 @@ // Tests that we don't delete a sparse entry when we start a new request after // cancelling the previous one. -TEST_F(HttpCacheTest, RangeGET_Cancel2) { +TEST_P(HttpCacheTest, RangeGET_Cancel2) { MockHttpCache cache; AddMockTransaction(&kRangeGET_TransactionOK); @@ -9826,7 +9904,7 @@ // A slight variation of the previous test, this time we cancel two requests in // a row, making sure that the second is waiting for the entry to be ready. -TEST_F(HttpCacheTest, RangeGET_Cancel3) { +TEST_P(HttpCacheTest, RangeGET_Cancel3) { MockHttpCache cache; AddMockTransaction(&kRangeGET_TransactionOK); @@ -9886,7 +9964,7 @@ } // Tests that an invalid range response results in no cached entry. -TEST_F(HttpCacheTest, RangeGET_InvalidResponse1) { +TEST_P(HttpCacheTest, RangeGET_InvalidResponse1) { MockHttpCache cache; std::string headers; @@ -9915,7 +9993,7 @@ } // Tests that we reject a range that doesn't match the content-length. -TEST_F(HttpCacheTest, RangeGET_InvalidResponse2) { +TEST_P(HttpCacheTest, RangeGET_InvalidResponse2) { MockHttpCache cache; std::string headers; @@ -9945,7 +10023,7 @@ // Tests that if a server tells us conflicting information about a resource we // drop the entry. -TEST_F(HttpCacheTest, RangeGET_InvalidResponse3) { +TEST_P(HttpCacheTest, RangeGET_InvalidResponse3) { MockHttpCache cache; std::string headers; @@ -9984,7 +10062,7 @@ } // Tests that we handle large range values properly. -TEST_F(HttpCacheTest, RangeGET_LargeValues) { +TEST_P(HttpCacheTest, RangeGET_LargeValues) { // We need a real sparse cache for this test. MockHttpCache cache(HttpCache::DefaultBackend::InMemory(1024 * 1024)); std::string headers; @@ -10018,7 +10096,7 @@ // Tests that we don't crash with a range request if the disk cache was not // initialized properly. -TEST_F(HttpCacheTest, RangeGET_NoDiskCache) { +TEST_P(HttpCacheTest, RangeGET_NoDiskCache) { auto factory = std::make_unique<MockBlockingBackendFactory>(); factory->set_fail(true); factory->FinishCreation(); // We'll complete synchronously. @@ -10033,7 +10111,7 @@ } // Tests that we handle byte range requests that skip the cache. -TEST_F(HttpCacheTest, RangeHEAD) { +TEST_P(HttpCacheTest, RangeHEAD) { MockHttpCache cache; AddMockTransaction(&kRangeGET_TransactionOK); @@ -10055,7 +10133,7 @@ // Tests that we don't crash when after reading from the cache we issue a // request for the next range and the server gives us a 200 synchronously. -TEST_F(HttpCacheTest, RangeGET_FastFlakyServer) { +TEST_P(HttpCacheTest, RangeGET_FastFlakyServer) { MockHttpCache cache; ScopedMockTransaction transaction(kRangeGET_TransactionOK); @@ -10083,7 +10161,7 @@ // Tests that when the server gives us less data than expected, we don't keep // asking for more data. -TEST_F(HttpCacheTest, RangeGET_FastFlakyServer2) { +TEST_P(HttpCacheTest, RangeGET_FastFlakyServer2) { MockHttpCache cache; // First, check with an empty cache (WRITE mode). @@ -10121,7 +10199,7 @@ RemoveMockTransaction(&transaction); } -TEST_F(HttpCacheTest, RangeGET_OK_LoadOnlyFromCache) { +TEST_P(HttpCacheTest, RangeGET_OK_LoadOnlyFromCache) { MockHttpCache cache; AddMockTransaction(&kRangeGET_TransactionOK); @@ -10158,7 +10236,7 @@ } // Tests the handling of the "truncation" flag. -TEST_F(HttpCacheTest, WriteResponseInfo_Truncated) { +TEST_P(HttpCacheTest, WriteResponseInfo_Truncated) { MockHttpCache cache; disk_cache::Entry* entry; ASSERT_TRUE(cache.CreateBackendEntry( @@ -10183,7 +10261,7 @@ } // Tests basic pickling/unpickling of HttpResponseInfo. -TEST_F(HttpCacheTest, PersistHttpResponseInfo) { +TEST_P(HttpCacheTest, PersistHttpResponseInfo) { const IPEndPoint expected_endpoint = IPEndPoint(IPAddress(1, 2, 3, 4), 80); // Set some fields (add more if needed.) HttpResponseInfo response1; @@ -10210,7 +10288,7 @@ // Tests that we delete an entry when the request is cancelled before starting // to read from the network. -TEST_F(HttpCacheTest, DoomOnDestruction) { +TEST_P(HttpCacheTest, DoomOnDestruction) { MockHttpCache cache; MockHttpRequest request(kSimpleGET_Transaction); @@ -10240,7 +10318,7 @@ // Tests that we delete an entry when the request is cancelled if the response // does not have content-length and strong validators. -TEST_F(HttpCacheTest, DoomOnDestruction2) { +TEST_P(HttpCacheTest, DoomOnDestruction2) { MockHttpCache cache; MockHttpRequest request(kSimpleGET_Transaction); @@ -10277,7 +10355,7 @@ // Tests that we delete an entry when the request is cancelled if the response // has an "Accept-Ranges: none" header. -TEST_F(HttpCacheTest, DoomOnDestruction3) { +TEST_P(HttpCacheTest, DoomOnDestruction3) { MockHttpCache cache; MockTransaction transaction(kSimpleGET_Transaction); @@ -10322,7 +10400,7 @@ } // Tests that we mark an entry as incomplete when the request is cancelled. -TEST_F(HttpCacheTest, SetTruncatedFlag) { +TEST_P(HttpCacheTest, SetTruncatedFlag) { MockHttpCache cache; ScopedMockTransaction transaction(kSimpleGET_Transaction); @@ -10373,7 +10451,7 @@ // Tests that we do not mark an entry as truncated when the request is // cancelled. -TEST_F(HttpCacheTest, DontSetTruncatedFlagForGarbledResponseCode) { +TEST_P(HttpCacheTest, DontSetTruncatedFlagForGarbledResponseCode) { MockHttpCache cache; ScopedMockTransaction transaction(kSimpleGET_Transaction); @@ -10431,7 +10509,7 @@ } // Tests that we don't mark an entry as truncated when we read everything. -TEST_F(HttpCacheTest, DontSetTruncatedFlag) { +TEST_P(HttpCacheTest, DontSetTruncatedFlag) { MockHttpCache cache; ScopedMockTransaction transaction(kSimpleGET_Transaction); @@ -10462,7 +10540,7 @@ } // Tests that sparse entries don't set the truncate flag. -TEST_F(HttpCacheTest, RangeGET_DontTruncate) { +TEST_P(HttpCacheTest, RangeGET_DontTruncate) { MockHttpCache cache; ScopedMockTransaction transaction(kRangeGET_TransactionOK); @@ -10489,7 +10567,7 @@ // Tests that sparse entries don't set the truncate flag (when the byte range // starts after 0). -TEST_F(HttpCacheTest, RangeGET_DontTruncate2) { +TEST_P(HttpCacheTest, RangeGET_DontTruncate2) { MockHttpCache cache; ScopedMockTransaction transaction(kRangeGET_TransactionOK); @@ -10515,7 +10593,7 @@ } // Tests that we can continue with a request that was interrupted. -TEST_F(HttpCacheTest, GET_IncompleteResource) { +TEST_P(HttpCacheTest, GET_IncompleteResource) { MockHttpCache cache; ScopedMockTransaction transaction(kRangeGET_TransactionOK); @@ -10551,7 +10629,7 @@ } // Tests the handling of no-store when revalidating a truncated entry. -TEST_F(HttpCacheTest, GET_IncompleteResource_NoStore) { +TEST_P(HttpCacheTest, GET_IncompleteResource_NoStore) { MockHttpCache cache; AddMockTransaction(&kRangeGET_TransactionOK); @@ -10597,7 +10675,7 @@ } // Tests cancelling a request after the server sent no-store. -TEST_F(HttpCacheTest, GET_IncompleteResource_Cancel) { +TEST_P(HttpCacheTest, GET_IncompleteResource_Cancel) { MockHttpCache cache; AddMockTransaction(&kRangeGET_TransactionOK); @@ -10657,7 +10735,7 @@ } // Tests that we delete truncated entries if the server changes its mind midway. -TEST_F(HttpCacheTest, GET_IncompleteResource2) { +TEST_P(HttpCacheTest, GET_IncompleteResource2) { MockHttpCache cache; AddMockTransaction(&kRangeGET_TransactionOK); @@ -10695,7 +10773,7 @@ } // Tests that we always validate a truncated request. -TEST_F(HttpCacheTest, GET_IncompleteResource3) { +TEST_P(HttpCacheTest, GET_IncompleteResource3) { MockHttpCache cache; AddMockTransaction(&kRangeGET_TransactionOK); @@ -10731,7 +10809,7 @@ } // Tests that we handle 401s for truncated resources. -TEST_F(HttpCacheTest, GET_IncompleteResourceWithAuth) { +TEST_P(HttpCacheTest, GET_IncompleteResourceWithAuth) { MockHttpCache cache; AddMockTransaction(&kRangeGET_TransactionOK); @@ -10780,7 +10858,7 @@ // Test that the transaction won't retry failed partial requests // after it starts reading data. http://crbug.com/474835 -TEST_F(HttpCacheTest, TransactionRetryLimit) { +TEST_P(HttpCacheTest, TransactionRetryLimit) { MockHttpCache cache; // Cache 0-9, so that we have data to read before failing. @@ -10815,7 +10893,7 @@ } // Tests that we cache a 200 response to the validation request. -TEST_F(HttpCacheTest, GET_IncompleteResource4) { +TEST_P(HttpCacheTest, GET_IncompleteResource4) { MockHttpCache cache; ScopedMockTransaction transaction(kRangeGET_TransactionOK); @@ -10845,7 +10923,7 @@ // Tests that when we cancel a request that was interrupted, we mark it again // as truncated. -TEST_F(HttpCacheTest, GET_CancelIncompleteResource) { +TEST_P(HttpCacheTest, GET_CancelIncompleteResource) { MockHttpCache cache; ScopedMockTransaction transaction(kRangeGET_TransactionOK); @@ -10887,7 +10965,7 @@ } // Tests that we can handle range requests when we have a truncated entry. -TEST_F(HttpCacheTest, RangeGET_IncompleteResource) { +TEST_P(HttpCacheTest, RangeGET_IncompleteResource) { MockHttpCache cache; AddMockTransaction(&kRangeGET_TransactionOK); @@ -10912,7 +10990,7 @@ RemoveMockTransaction(&kRangeGET_TransactionOK); } -TEST_F(HttpCacheTest, SyncRead) { +TEST_P(HttpCacheTest, SyncRead) { MockHttpCache cache; // This test ensures that a read that completes synchronously does not cause @@ -10950,7 +11028,7 @@ EXPECT_THAT(c3.error(), IsOk()); } -TEST_F(HttpCacheTest, ValidationResultsIn200) { +TEST_P(HttpCacheTest, ValidationResultsIn200) { MockHttpCache cache; // This test ensures that a conditional request, which results in a 200 @@ -10968,7 +11046,7 @@ RunTransactionTest(cache.http_cache(), kETagGET_Transaction); } -TEST_F(HttpCacheTest, CachedRedirect) { +TEST_P(HttpCacheTest, CachedRedirect) { MockHttpCache cache; ScopedMockTransaction kTestTransaction(kSimpleGET_Transaction); @@ -11044,7 +11122,7 @@ // Verify that no-cache resources are stored in cache, but are not fetched from // cache during normal loads. -TEST_F(HttpCacheTest, CacheControlNoCacheNormalLoad) { +TEST_P(HttpCacheTest, CacheControlNoCacheNormalLoad) { for (bool use_memory_entry_data : {false, true}) { MockHttpCache cache; cache.disk_cache()->set_support_in_memory_entry_data(use_memory_entry_data); @@ -11080,7 +11158,7 @@ // Verify that no-cache resources are stored in cache and fetched from cache // when the LOAD_SKIP_CACHE_VALIDATION flag is set. -TEST_F(HttpCacheTest, CacheControlNoCacheHistoryLoad) { +TEST_P(HttpCacheTest, CacheControlNoCacheHistoryLoad) { MockHttpCache cache; ScopedMockTransaction transaction(kSimpleGET_Transaction); @@ -11107,7 +11185,7 @@ entry->Close(); } -TEST_F(HttpCacheTest, CacheControlNoStore) { +TEST_P(HttpCacheTest, CacheControlNoStore) { MockHttpCache cache; ScopedMockTransaction transaction(kSimpleGET_Transaction); @@ -11132,7 +11210,7 @@ EXPECT_FALSE(cache.OpenBackendEntry(request.CacheKey(), &entry)); } -TEST_F(HttpCacheTest, CacheControlNoStore2) { +TEST_P(HttpCacheTest, CacheControlNoStore2) { // this test is similar to the above test, except that the initial response // is cachable, but when it is validated, no-store is received causing the // cached document to be deleted. @@ -11161,7 +11239,7 @@ EXPECT_FALSE(cache.OpenBackendEntry(request.CacheKey(), &entry)); } -TEST_F(HttpCacheTest, CacheControlNoStore3) { +TEST_P(HttpCacheTest, CacheControlNoStore3) { // this test is similar to the above test, except that the response is a 304 // instead of a 200. this should never happen in practice, but it seems like // a good thing to verify that we still destroy the cache entry. @@ -11192,7 +11270,7 @@ } // Ensure that we don't cache requests served over bad HTTPS. -TEST_F(HttpCacheTest, SimpleGET_SSLError) { +TEST_P(HttpCacheTest, SimpleGET_SSLError) { MockHttpCache cache; MockTransaction transaction = kSimpleGET_Transaction; @@ -11218,7 +11296,7 @@ } // Ensure that we don't crash by if left-behind transactions. -TEST_F(HttpCacheTest, OutlivedTransactions) { +TEST_P(HttpCacheTest, OutlivedTransactions) { auto cache = std::make_unique<MockHttpCache>(); std::unique_ptr<HttpTransaction> trans; @@ -11229,7 +11307,7 @@ } // Test that the disabled mode works. -TEST_F(HttpCacheTest, CacheDisabledMode) { +TEST_P(HttpCacheTest, CacheDisabledMode) { MockHttpCache cache; // write to the cache @@ -11253,7 +11331,7 @@ // HttpResponseHeaders::request_time and HttpResponseHeaders::response_time // fields also gets updated. // http://crbug.com/20594. -TEST_F(HttpCacheTest, UpdatesRequestResponseTimeOn304) { +TEST_P(HttpCacheTest, UpdatesRequestResponseTimeOn304) { MockHttpCache cache; const char kUrl[] = "http://foobar"; @@ -11413,7 +11491,7 @@ EXPECT_FALSE(response.was_cached); } -TEST_F(HttpCacheTest, HttpCacheProfileThirdPartyCSS) { +TEST_P(HttpCacheTest, HttpCacheProfileThirdPartyCSS) { base::HistogramTester histograms; MockHttpCache cache; HttpResponseInfo response; @@ -11456,7 +11534,7 @@ histograms.ExpectTotalCount("HttpCache.Pattern.CSSThirdParty", 1); } -TEST_F(HttpCacheTest, HttpCacheProfileThirdPartyJavaScript) { +TEST_P(HttpCacheTest, HttpCacheProfileThirdPartyJavaScript) { base::HistogramTester histograms; MockHttpCache cache; HttpResponseInfo response; @@ -11499,7 +11577,7 @@ histograms.ExpectTotalCount("HttpCache.Pattern.JavaScriptThirdParty", 1); } -TEST_F(HttpCacheTest, HttpCacheProfileThirdPartyFont) { +TEST_P(HttpCacheTest, HttpCacheProfileThirdPartyFont) { base::HistogramTester histograms; MockHttpCache cache; HttpResponseInfo response; @@ -11647,7 +11725,7 @@ EXPECT_FALSE(response.was_cached); } -TEST_F(HttpCacheTest, SplitCacheEnabledByDefault) { +TEST_P(HttpCacheTest, SplitCacheEnabledByDefault) { HttpCache::ClearGlobalsForTesting(); HttpCache::SplitCacheFeatureEnableByDefault(); EXPECT_TRUE(HttpCache::IsSplitCacheEnabled()); @@ -11681,7 +11759,7 @@ EXPECT_FALSE(response.was_cached); } -TEST_F(HttpCacheTest, SplitCacheEnabledByDefaultButOverridden) { +TEST_P(HttpCacheTest, SplitCacheEnabledByDefaultButOverridden) { HttpCache::ClearGlobalsForTesting(); base::test::ScopedFeatureList feature_list; feature_list.InitAndDisableFeature( @@ -11730,7 +11808,7 @@ EXPECT_FALSE(response.was_cached); } -TEST_F(HttpCacheTest, NonSplitCache) { +TEST_F(HttpCacheTestBase, NonSplitCache) { base::test::ScopedFeatureList feature_list; feature_list.InitAndDisableFeature( net::features::kSplitCacheByNetworkIsolationKey); @@ -11762,7 +11840,7 @@ EXPECT_TRUE(response.was_cached); } -TEST_F(HttpCacheTest, SkipVaryCheck) { +TEST_P(HttpCacheTest, SkipVaryCheck) { MockHttpCache cache; // Write a simple vary transaction to the cache. @@ -11787,7 +11865,7 @@ RunTransactionTest(cache.http_cache(), transaction); } -TEST_F(HttpCacheTest, SkipVaryCheckStar) { +TEST_P(HttpCacheTest, SkipVaryCheckStar) { MockHttpCache cache; // Write a simple vary:* transaction to the cache. @@ -11813,7 +11891,7 @@ // Tests that we only return valid entries with LOAD_ONLY_FROM_CACHE // transactions unless LOAD_SKIP_CACHE_VALIDATION is set. -TEST_F(HttpCacheTest, ValidLoadOnlyFromCache) { +TEST_P(HttpCacheTest, ValidLoadOnlyFromCache) { MockHttpCache cache; base::SimpleTestClock clock; cache.http_cache()->SetClockForTesting(&clock); @@ -11837,7 +11915,7 @@ RunTransactionTest(cache.http_cache(), transaction); } -TEST_F(HttpCacheTest, InvalidLoadFlagCombination) { +TEST_P(HttpCacheTest, InvalidLoadFlagCombination) { MockHttpCache cache; // Put the resource in the cache. @@ -11855,7 +11933,7 @@ // Tests that we don't mark entries as truncated when a filter detects the end // of the stream. -TEST_F(HttpCacheTest, FilterCompletion) { +TEST_P(HttpCacheTest, FilterCompletion) { MockHttpCache cache; TestCompletionCallback callback; @@ -11889,7 +11967,7 @@ // Tests that we don't mark entries as truncated and release the cache // entry when DoneReading() is called before any Read() calls, such as // for a redirect. -TEST_F(HttpCacheTest, DoneReading) { +TEST_P(HttpCacheTest, DoneReading) { MockHttpCache cache; TestCompletionCallback callback; @@ -11918,7 +11996,7 @@ } // Tests that we stop caching when told. -TEST_F(HttpCacheTest, StopCachingDeletesEntry) { +TEST_P(HttpCacheTest, StopCachingDeletesEntry) { MockHttpCache cache; TestCompletionCallback callback; MockHttpRequest request(kSimpleGET_Transaction); @@ -11956,7 +12034,7 @@ // Tests that we stop caching when told, even if DoneReading is called // after StopCaching. -TEST_F(HttpCacheTest, StopCachingThenDoneReadingDeletesEntry) { +TEST_P(HttpCacheTest, StopCachingThenDoneReadingDeletesEntry) { MockHttpCache cache; TestCompletionCallback callback; MockHttpRequest request(kSimpleGET_Transaction); @@ -11996,7 +12074,7 @@ } // Tests that we stop caching when told, when using auth. -TEST_F(HttpCacheTest, StopCachingWithAuthDeletesEntry) { +TEST_P(HttpCacheTest, StopCachingWithAuthDeletesEntry) { MockHttpCache cache; TestCompletionCallback callback; MockTransaction mock_transaction(kSimpleGET_Transaction); @@ -12027,7 +12105,7 @@ } // Tests that when we are told to stop caching we don't throw away valid data. -TEST_F(HttpCacheTest, StopCachingSavesEntry) { +TEST_P(HttpCacheTest, StopCachingSavesEntry) { MockHttpCache cache; TestCompletionCallback callback; MockHttpRequest request(kSimpleGET_Transaction); @@ -12066,7 +12144,7 @@ } // Tests that we handle truncated enries when StopCaching is called. -TEST_F(HttpCacheTest, StopCachingTruncatedEntry) { +TEST_P(HttpCacheTest, StopCachingTruncatedEntry) { MockHttpCache cache; TestCompletionCallback callback; MockHttpRequest request(kRangeGET_TransactionOK); @@ -12385,7 +12463,7 @@ // Tests that we detect truncated resources from the net when there is // a Content-Length header. -TEST_F(HttpCacheTest, TruncatedByContentLength) { +TEST_P(HttpCacheTest, TruncatedByContentLength) { MockHttpCache cache; TestCompletionCallback callback; @@ -12406,7 +12484,7 @@ // Tests that we actually flag entries as truncated when we detect an error // from the net. -TEST_F(HttpCacheTest, TruncatedByContentLength2) { +TEST_P(HttpCacheTest, TruncatedByContentLength2) { MockHttpCache cache; TestCompletionCallback callback; @@ -12425,7 +12503,7 @@ // Make sure that calling SetPriority on a cache transaction passes on // its priority updates to its underlying network transaction. -TEST_F(HttpCacheTest, SetPriority) { +TEST_P(HttpCacheTest, SetPriority) { MockHttpCache cache; HttpRequestInfo info; @@ -12462,7 +12540,7 @@ // Make sure that calling SetWebSocketHandshakeStreamCreateHelper on a cache // transaction passes on its argument to the underlying network transaction. -TEST_F(HttpCacheTest, SetWebSocketHandshakeStreamCreateHelper) { +TEST_P(HttpCacheTest, SetWebSocketHandshakeStreamCreateHelper) { MockHttpCache cache; HttpRequestInfo info; @@ -12489,7 +12567,7 @@ // Make sure that a cache transaction passes on its priority to // newly-created network transactions. -TEST_F(HttpCacheTest, SetPriorityNewTransaction) { +TEST_P(HttpCacheTest, SetPriorityNewTransaction) { MockHttpCache cache; AddMockTransaction(&kRangeGET_TransactionOK); @@ -12542,7 +12620,7 @@ } // namespace -TEST_F(HttpCacheTest, NetworkBytesCacheMissAndThenHit) { +TEST_P(HttpCacheTest, NetworkBytesCacheMissAndThenHit) { MockHttpCache cache; MockTransaction transaction(kSimpleGET_Transaction); @@ -12556,7 +12634,7 @@ EXPECT_EQ(0, received); } -TEST_F(HttpCacheTest, NetworkBytesConditionalRequest304) { +TEST_P(HttpCacheTest, NetworkBytesConditionalRequest304) { MockHttpCache cache; ScopedMockTransaction transaction(kETagGET_Transaction); @@ -12572,7 +12650,7 @@ EXPECT_EQ(MockNetworkTransaction::kTotalReceivedBytes, received); } -TEST_F(HttpCacheTest, NetworkBytesConditionalRequest200) { +TEST_P(HttpCacheTest, NetworkBytesConditionalRequest200) { MockHttpCache cache; MockTransaction transaction(kTypicalGET_Transaction); @@ -12599,7 +12677,7 @@ RemoveMockTransaction(&transaction); } -TEST_F(HttpCacheTest, NetworkBytesRange) { +TEST_P(HttpCacheTest, NetworkBytesRange) { MockHttpCache cache; AddMockTransaction(&kRangeGET_TransactionOK); MockTransaction transaction(kRangeGET_TransactionOK); @@ -12742,7 +12820,7 @@ EXPECT_FALSE(TransactionRequiredNetwork(LOAD_NORMAL)); } -TEST_F(HttpCacheTest, StaleContentNotUsedWhenLoadFlagNotSet) { +TEST_P(HttpCacheTest, StaleContentNotUsedWhenLoadFlagNotSet) { MockHttpCache cache; ScopedMockTransaction stale_while_revalidate_transaction( @@ -12767,7 +12845,7 @@ EXPECT_FALSE(response_info.async_revalidation_requested); } -TEST_F(HttpCacheTest, StaleContentUsedWhenLoadFlagSetAndUsableThenTimesout) { +TEST_P(HttpCacheTest, StaleContentUsedWhenLoadFlagSetAndUsableThenTimesout) { MockHttpCache cache; base::SimpleTestClock clock; cache.http_cache()->SetClockForTesting(&clock); @@ -12808,7 +12886,7 @@ EXPECT_FALSE(response_info.async_revalidation_requested); } -TEST_F(HttpCacheTest, StaleContentUsedWhenLoadFlagSetAndUsable) { +TEST_P(HttpCacheTest, StaleContentUsedWhenLoadFlagSetAndUsable) { MockHttpCache cache; base::SimpleTestClock clock; cache.http_cache()->SetClockForTesting(&clock); @@ -12864,7 +12942,7 @@ EXPECT_TRUE(response_info.stale_revalidate_timeout.is_null()); } -TEST_F(HttpCacheTest, StaleContentNotUsedWhenUnusable) { +TEST_P(HttpCacheTest, StaleContentNotUsedWhenUnusable) { MockHttpCache cache; ScopedMockTransaction stale_while_revalidate_transaction( @@ -12890,7 +12968,7 @@ EXPECT_FALSE(response_info.async_revalidation_requested); } -TEST_F(HttpCacheTest, StaleContentWriteError) { +TEST_P(HttpCacheTest, StaleContentWriteError) { MockHttpCache cache; base::SimpleTestClock clock; cache.http_cache()->SetClockForTesting(&clock); @@ -12923,7 +13001,7 @@ // Tests that we allow multiple simultaneous, non-overlapping transactions to // take place on a sparse entry. -TEST_F(HttpCacheTest, RangeGET_MultipleRequests) { +TEST_P(HttpCacheTest, RangeGET_MultipleRequests) { MockHttpCache cache; // Create a transaction for bytes 0-9. @@ -12958,7 +13036,7 @@ // implemented so it returns ERR_CACHE_MISS. See also // HttpCacheTest.RangeGET_OK_LoadOnlyFromCache. // TODO(ricea): Update this test if it is implemented in future. -TEST_F(HttpCacheTest, RangeGET_Previous200_LoadOnlyFromCache) { +TEST_P(HttpCacheTest, RangeGET_Previous200_LoadOnlyFromCache) { MockHttpCache cache; // Store the whole thing with status 200. @@ -13000,7 +13078,7 @@ // with "Cache-Control: no-store" arrives. That means that another request for // the same URL can be processed before the response body of the original // request arrives. -TEST_F(HttpCacheTest, NoStoreResponseShouldNotBlockFollowingRequests) { +TEST_P(HttpCacheTest, NoStoreResponseShouldNotBlockFollowingRequests) { MockHttpCache cache; ScopedMockTransaction mock_transaction(kSimpleGET_Transaction); mock_transaction.response_headers = "Cache-Control: no-store\n"; @@ -13041,7 +13119,7 @@ // Tests that serving a response entirely from cache replays the previous // SSLInfo. -TEST_F(HttpCacheTest, CachePreservesSSLInfo) { +TEST_P(HttpCacheTest, CachePreservesSSLInfo) { static const uint16_t kTLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 = 0xc02f; int status = 0; SSLConnectionStatusSetCipherSuite(kTLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, @@ -13087,7 +13165,7 @@ } // Tests that SSLInfo gets updated when revalidating a cached response. -TEST_F(HttpCacheTest, RevalidationUpdatesSSLInfo) { +TEST_P(HttpCacheTest, RevalidationUpdatesSSLInfo) { static const uint16_t kTLS_RSA_WITH_RC4_128_MD5 = 0x0004; static const uint16_t kTLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 = 0xc02f; @@ -13147,7 +13225,7 @@ EXPECT_TRUE(cert2->EqualsIncludingChain(response_info.ssl_info.cert.get())); } -TEST_F(HttpCacheTest, CacheEntryStatusOther) { +TEST_P(HttpCacheTest, CacheEntryStatusOther) { MockHttpCache cache; HttpResponseInfo response_info; @@ -13159,7 +13237,7 @@ EXPECT_EQ(CacheEntryStatus::ENTRY_OTHER, response_info.cache_entry_status); } -TEST_F(HttpCacheTest, CacheEntryStatusNotInCache) { +TEST_P(HttpCacheTest, CacheEntryStatusNotInCache) { MockHttpCache cache; HttpResponseInfo response_info; @@ -13172,7 +13250,7 @@ response_info.cache_entry_status); } -TEST_F(HttpCacheTest, CacheEntryStatusUsed) { +TEST_P(HttpCacheTest, CacheEntryStatusUsed) { MockHttpCache cache; RunTransactionTest(cache.http_cache(), kSimpleGET_Transaction); @@ -13185,7 +13263,7 @@ EXPECT_EQ(CacheEntryStatus::ENTRY_USED, response_info.cache_entry_status); } -TEST_F(HttpCacheTest, CacheEntryStatusValidated) { +TEST_P(HttpCacheTest, CacheEntryStatusValidated) { MockHttpCache cache; RunTransactionTest(cache.http_cache(), kETagGET_Transaction); @@ -13203,7 +13281,7 @@ response_info.cache_entry_status); } -TEST_F(HttpCacheTest, CacheEntryStatusUpdated) { +TEST_P(HttpCacheTest, CacheEntryStatusUpdated) { MockHttpCache cache; RunTransactionTest(cache.http_cache(), kETagGET_Transaction); @@ -13219,7 +13297,7 @@ EXPECT_EQ(CacheEntryStatus::ENTRY_UPDATED, response_info.cache_entry_status); } -TEST_F(HttpCacheTest, CacheEntryStatusCantConditionalize) { +TEST_P(HttpCacheTest, CacheEntryStatusCantConditionalize) { MockHttpCache cache; cache.FailConditionalizations(); RunTransactionTest(cache.http_cache(), kTypicalGET_Transaction); @@ -13234,7 +13312,7 @@ response_info.cache_entry_status); } -TEST_F(HttpSplitCacheKeyTest, GetResourceURLFromHttpCacheKey) { +TEST_P(HttpSplitCacheKeyTest, GetResourceURLFromHttpCacheKey) { base::test::ScopedFeatureList feature_list; feature_list.InitAndEnableFeature( net::features::kSplitCacheByNetworkIsolationKey); @@ -13248,7 +13326,7 @@ } } -TEST_F(HttpCacheTest, GetResourceURLFromHttpCacheKey) { +TEST_P(HttpCacheTest, GetResourceURLFromHttpCacheKey) { const struct { std::string input; std::string output; @@ -13297,13 +13375,14 @@ } }; -TEST_F(HttpCacheIOCallbackTest, FailedDoomFollowedByOpen) { +TEST_P(HttpCacheIOCallbackTest, FailedDoomFollowedByOpen) { MockHttpCache cache; TestCompletionCallbackForHttpCache cb; std::unique_ptr<Transaction> transaction = std::make_unique<Transaction>(DEFAULT_PRIORITY, cache.http_cache()); transaction->SetIOCallBackForTest(cb.callback()); + transaction->SetCacheIOCallBackForTest(cb.callback()); // Create the backend here as our direct calls to DoomEntry and OpenEntry // below require that it exists. @@ -13336,13 +13415,14 @@ ASSERT_EQ(entry1, nullptr); } -TEST_F(HttpCacheIOCallbackTest, FailedDoomFollowedByCreate) { +TEST_P(HttpCacheIOCallbackTest, FailedDoomFollowedByCreate) { MockHttpCache cache; TestCompletionCallbackForHttpCache cb; std::unique_ptr<Transaction> transaction = std::make_unique<Transaction>(DEFAULT_PRIORITY, cache.http_cache()); transaction->SetIOCallBackForTest(cb.callback()); + transaction->SetCacheIOCallBackForTest(cb.callback()); // Create the backend here as our direct calls to DoomEntry and CreateEntry // below require that it exists. @@ -13375,13 +13455,14 @@ ASSERT_EQ(entry1, nullptr); } -TEST_F(HttpCacheIOCallbackTest, FailedDoomFollowedByDoom) { +TEST_P(HttpCacheIOCallbackTest, FailedDoomFollowedByDoom) { MockHttpCache cache; TestCompletionCallbackForHttpCache cb; std::unique_ptr<Transaction> transaction = std::make_unique<Transaction>(DEFAULT_PRIORITY, cache.http_cache()); transaction->SetIOCallBackForTest(cb.callback()); + transaction->SetCacheIOCallBackForTest(cb.callback()); // Create the backend here as our direct calls to DoomEntry below require that // it exists. @@ -13410,13 +13491,14 @@ ASSERT_EQ(cb.results()[1], ERR_CACHE_RACE); } -TEST_F(HttpCacheIOCallbackTest, FailedOpenFollowedByCreate) { +TEST_P(HttpCacheIOCallbackTest, FailedOpenFollowedByCreate) { MockHttpCache cache; TestCompletionCallbackForHttpCache cb; std::unique_ptr<Transaction> transaction = std::make_unique<Transaction>(DEFAULT_PRIORITY, cache.http_cache()); transaction->SetIOCallBackForTest(cb.callback()); + transaction->SetCacheIOCallBackForTest(cb.callback()); // Create the backend here as our direct calls to OpenEntry and CreateEntry // below require that it exists. @@ -13452,13 +13534,14 @@ ASSERT_EQ(entry2, nullptr); } -TEST_F(HttpCacheIOCallbackTest, FailedCreateFollowedByOpen) { +TEST_P(HttpCacheIOCallbackTest, FailedCreateFollowedByOpen) { MockHttpCache cache; TestCompletionCallbackForHttpCache cb; std::unique_ptr<Transaction> transaction = std::make_unique<Transaction>(DEFAULT_PRIORITY, cache.http_cache()); transaction->SetIOCallBackForTest(cb.callback()); + transaction->SetCacheIOCallBackForTest(cb.callback()); // Create the backend here as our direct calls to CreateEntry and OpenEntry // below require that it exists. @@ -13494,13 +13577,14 @@ ASSERT_EQ(entry2, nullptr); } -TEST_F(HttpCacheIOCallbackTest, FailedCreateFollowedByCreate) { +TEST_P(HttpCacheIOCallbackTest, FailedCreateFollowedByCreate) { MockHttpCache cache; TestCompletionCallbackForHttpCache cb; std::unique_ptr<Transaction> transaction = std::make_unique<Transaction>(DEFAULT_PRIORITY, cache.http_cache()); transaction->SetIOCallBackForTest(cb.callback()); + transaction->SetCacheIOCallBackForTest(cb.callback()); // Create the backend here as our direct calls to CreateEntry below require // that it exists. @@ -13535,13 +13619,14 @@ ASSERT_EQ(entry2, nullptr); } -TEST_F(HttpCacheIOCallbackTest, CreateFollowedByCreate) { +TEST_P(HttpCacheIOCallbackTest, CreateFollowedByCreate) { MockHttpCache cache; TestCompletionCallbackForHttpCache cb; std::unique_ptr<Transaction> transaction = std::make_unique<Transaction>(DEFAULT_PRIORITY, cache.http_cache()); transaction->SetIOCallBackForTest(cb.callback()); + transaction->SetCacheIOCallBackForTest(cb.callback()); // Create the backend here as our direct calls to CreateEntry below require // that it exists. @@ -13574,13 +13659,14 @@ ASSERT_EQ(entry2, nullptr); } -TEST_F(HttpCacheIOCallbackTest, OperationFollowedByDoom) { +TEST_P(HttpCacheIOCallbackTest, OperationFollowedByDoom) { MockHttpCache cache; TestCompletionCallbackForHttpCache cb; std::unique_ptr<Transaction> transaction = std::make_unique<Transaction>(DEFAULT_PRIORITY, cache.http_cache()); transaction->SetIOCallBackForTest(cb.callback()); + transaction->SetCacheIOCallBackForTest(cb.callback()); // Create the backend here as our direct calls to CreateEntry and DoomEntry // below require that it exists. @@ -13611,13 +13697,14 @@ ASSERT_EQ(cb.results()[1], ERR_CACHE_RACE); } -TEST_F(HttpCacheIOCallbackTest, CreateFollowedByOpenOrCreate) { +TEST_P(HttpCacheIOCallbackTest, CreateFollowedByOpenOrCreate) { MockHttpCache cache; TestCompletionCallbackForHttpCache cb; std::unique_ptr<Transaction> transaction = std::make_unique<Transaction>(DEFAULT_PRIORITY, cache.http_cache()); transaction->SetIOCallBackForTest(cb.callback()); + transaction->SetCacheIOCallBackForTest(cb.callback()); // Create the backend here as our direct calls to CreateEntry and // OpenOrCreateEntry below require that it exists. @@ -13651,13 +13738,14 @@ ASSERT_EQ(entry1->disk_entry, entry2->disk_entry); } -TEST_F(HttpCacheIOCallbackTest, FailedCreateFollowedByOpenOrCreate) { +TEST_P(HttpCacheIOCallbackTest, FailedCreateFollowedByOpenOrCreate) { MockHttpCache cache; TestCompletionCallbackForHttpCache cb; std::unique_ptr<Transaction> transaction = std::make_unique<Transaction>(DEFAULT_PRIORITY, cache.http_cache()); transaction->SetIOCallBackForTest(cb.callback()); + transaction->SetCacheIOCallBackForTest(cb.callback()); // Create the backend here as our direct calls to CreateEntry and // OpenOrCreateEntry below require that it exists. @@ -13693,13 +13781,14 @@ ASSERT_EQ(entry2, nullptr); } -TEST_F(HttpCacheIOCallbackTest, OpenFollowedByOpenOrCreate) { +TEST_P(HttpCacheIOCallbackTest, OpenFollowedByOpenOrCreate) { MockHttpCache cache; TestCompletionCallbackForHttpCache cb; std::unique_ptr<Transaction> transaction = std::make_unique<Transaction>(DEFAULT_PRIORITY, cache.http_cache()); transaction->SetIOCallBackForTest(cb.callback()); + transaction->SetCacheIOCallBackForTest(cb.callback()); // Create the backend here as our direct calls to OpenEntry and // OpenOrCreateEntry below require that it exists. @@ -13746,13 +13835,14 @@ ASSERT_EQ(entry1->disk_entry, entry2->disk_entry); } -TEST_F(HttpCacheIOCallbackTest, FailedOpenFollowedByOpenOrCreate) { +TEST_P(HttpCacheIOCallbackTest, FailedOpenFollowedByOpenOrCreate) { MockHttpCache cache; TestCompletionCallbackForHttpCache cb; std::unique_ptr<Transaction> transaction = std::make_unique<Transaction>(DEFAULT_PRIORITY, cache.http_cache()); transaction->SetIOCallBackForTest(cb.callback()); + transaction->SetCacheIOCallBackForTest(cb.callback()); // Create the backend here as our direct calls to OpenEntry and // OpenOrCreateEntry below require that it exists. @@ -13788,13 +13878,14 @@ ASSERT_EQ(entry2, nullptr); } -TEST_F(HttpCacheIOCallbackTest, OpenOrCreateFollowedByCreate) { +TEST_P(HttpCacheIOCallbackTest, OpenOrCreateFollowedByCreate) { MockHttpCache cache; TestCompletionCallbackForHttpCache cb; std::unique_ptr<Transaction> transaction = std::make_unique<Transaction>(DEFAULT_PRIORITY, cache.http_cache()); transaction->SetIOCallBackForTest(cb.callback()); + transaction->SetCacheIOCallBackForTest(cb.callback()); // Create the backend here as our direct calls to OpenOrCreateEntry and // CreateEntry below require that it exists. @@ -13827,13 +13918,14 @@ ASSERT_EQ(entry2, nullptr); } -TEST_F(HttpCacheIOCallbackTest, OpenOrCreateFollowedByOpenOrCreate) { +TEST_P(HttpCacheIOCallbackTest, OpenOrCreateFollowedByOpenOrCreate) { MockHttpCache cache; TestCompletionCallbackForHttpCache cb; std::unique_ptr<Transaction> transaction = std::make_unique<Transaction>(DEFAULT_PRIORITY, cache.http_cache()); transaction->SetIOCallBackForTest(cb.callback()); + transaction->SetCacheIOCallBackForTest(cb.callback()); // Create the backend here as our direct calls to OpenOrCreateEntry below // require that it exists. @@ -13866,13 +13958,14 @@ ASSERT_NE(entry2, nullptr); } -TEST_F(HttpCacheIOCallbackTest, FailedOpenOrCreateFollowedByOpenOrCreate) { +TEST_P(HttpCacheIOCallbackTest, FailedOpenOrCreateFollowedByOpenOrCreate) { MockHttpCache cache; TestCompletionCallbackForHttpCache cb; std::unique_ptr<Transaction> transaction = std::make_unique<Transaction>(DEFAULT_PRIORITY, cache.http_cache()); transaction->SetIOCallBackForTest(cb.callback()); + transaction->SetCacheIOCallBackForTest(cb.callback()); // Create the backend here as our direct calls to OpenOrCreateEntry below // require that it exists. @@ -13908,7 +14001,7 @@ ASSERT_EQ(entry2, nullptr); } -TEST_F(HttpCacheTest, DnsAliasesNoRevalidation) { +TEST_P(HttpCacheTest, DnsAliasesNoRevalidation) { MockHttpCache cache; HttpResponseInfo response; ScopedMockTransaction transaction(kSimpleGET_Transaction); @@ -13929,7 +14022,7 @@ EXPECT_THAT(response.dns_aliases, testing::ElementsAre("alias1", "alias2")); } -TEST_F(HttpCacheTest, NoDnsAliasesNoRevalidation) { +TEST_P(HttpCacheTest, NoDnsAliasesNoRevalidation) { MockHttpCache cache; HttpResponseInfo response; ScopedMockTransaction transaction(kSimpleGET_Transaction); @@ -13950,7 +14043,7 @@ EXPECT_TRUE(response.dns_aliases.empty()); } -TEST_F(HttpCacheTest, DnsAliasesRevalidation) { +TEST_P(HttpCacheTest, DnsAliasesRevalidation) { MockHttpCache cache; HttpResponseInfo response; ScopedMockTransaction transaction(kTypicalGET_Transaction); @@ -13982,7 +14075,7 @@ EXPECT_THAT(response.dns_aliases, testing::ElementsAre("alias3", "alias4")); } -TEST_F(HttpCacheTest, FirstPartySetsBypassCache_ShouldBypass_NoId) { +TEST_P(HttpCacheTest, FirstPartySetsBypassCache_ShouldBypass_NoId) { MockHttpCache cache; HttpResponseInfo response; ScopedMockTransaction transaction(kSimpleGET_Transaction); @@ -13997,7 +14090,7 @@ EXPECT_FALSE(response.was_cached); } -TEST_F(HttpCacheTest, FirstPartySetsBypassCache_ShouldBypass_IdTooSmall) { +TEST_P(HttpCacheTest, FirstPartySetsBypassCache_ShouldBypass_IdTooSmall) { MockHttpCache cache; HttpResponseInfo response; ScopedMockTransaction transaction(kSimpleGET_Transaction); @@ -14015,7 +14108,7 @@ EXPECT_FALSE(response.was_cached); } -TEST_F(HttpCacheTest, FirstPartySetsBypassCache_ShouldNotBypass) { +TEST_P(HttpCacheTest, FirstPartySetsBypassCache_ShouldNotBypass) { MockHttpCache cache; HttpResponseInfo response; ScopedMockTransaction transaction(kSimpleGET_Transaction); @@ -14033,7 +14126,7 @@ EXPECT_TRUE(response.was_cached); } -TEST_F(HttpCacheTest, FirstPartySetsBypassCache_ShouldNotBypass_NoFilter) { +TEST_P(HttpCacheTest, FirstPartySetsBypassCache_ShouldNotBypass_NoFilter) { MockHttpCache cache; HttpResponseInfo response; ScopedMockTransaction transaction(kSimpleGET_Transaction); @@ -14047,7 +14140,7 @@ EXPECT_TRUE(response.was_cached); } -TEST_F(HttpCacheTest, SecurityHeadersAreCopiedToConditionalizedResponse) { +TEST_P(HttpCacheTest, SecurityHeadersAreCopiedToConditionalizedResponse) { MockHttpCache cache; HttpResponseInfo response; ScopedMockTransaction transaction(kSimpleGET_Transaction);
diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc index d8bade0..e976ccd 100644 --- a/net/http/http_network_transaction.cc +++ b/net/http/http_network_transaction.cc
@@ -57,6 +57,7 @@ #include "net/http/transport_security_state.h" #include "net/http/url_security_manager.h" #include "net/log/net_log_event_type.h" +#include "net/proxy_resolution/proxy_info.h" #include "net/socket/client_socket_factory.h" #include "net/socket/next_proto.h" #include "net/socket/transport_client_socket_pool.h" @@ -107,6 +108,23 @@ response_info->proxy_server = ProxyServer(); } +// Returns true when Early Hints are allowed on the given protocol. +bool EarlyHintsAreAllowedOn(HttpResponseInfo::ConnectionInfo connection_info) { + switch (connection_info) { + case HttpResponseInfo::ConnectionInfo::CONNECTION_INFO_HTTP0_9: + case HttpResponseInfo::ConnectionInfo::CONNECTION_INFO_HTTP1_0: + return false; + case HttpResponseInfo::ConnectionInfo::CONNECTION_INFO_HTTP1_1: + return base::FeatureList::IsEnabled(features::kEnableEarlyHintsOnHttp11); + default: + CHECK_NE(connection_info, + HttpResponseInfo::ConnectionInfo::NUM_OF_CONNECTION_INFOS); + // Implicitly allow CONNECTION_INFO_UNKNOWN because this is the default + // value and ConnectionInfo isn't always set. + return true; + } +} + } // namespace const int HttpNetworkTransaction::kDrainBodyBufferSize; @@ -1151,15 +1169,20 @@ response_.headers.get()); // Early Hints does not make sense for a WebSocket handshake. - if (ForWebSocketHandshake()) + if (ForWebSocketHandshake()) { return ERR_FAILED; + } - // TODO(crbug.com/671310): Validate headers? It seems that - // "Content-Encoding" etc should not appear. + // TODO(https://crbug.com/671310): Validate headers? "Content-Encoding" etc + // should not appear since informational responses can't contain content. + // https://www.rfc-editor.org/rfc/rfc9110#name-informational-1xx - if (early_response_headers_callback_) + if (EarlyHintsAreAllowedOn(response_.connection_info) && + early_response_headers_callback_) { early_response_headers_callback_.Run(std::move(response_.headers)); + } + // Reset response headers for the final response. response_.headers = base::MakeRefCounted<HttpResponseHeaders>(std::string()); next_state_ = STATE_READ_HEADERS;
diff --git a/services/device/public/cpp/geolocation/geolocation_manager.cc b/services/device/public/cpp/geolocation/geolocation_manager.cc index 15a0d940..54991a73 100644 --- a/services/device/public/cpp/geolocation/geolocation_manager.cc +++ b/services/device/public/cpp/geolocation/geolocation_manager.cc
@@ -46,15 +46,6 @@ } #if BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_CHROMEOS) - -void GeolocationManager::AppAttemptsToUseGeolocation() { - system_geolocation_source_->AppAttemptsToUseGeolocation(); -} - -void GeolocationManager::AppCeasesToUseGeolocation() { - system_geolocation_source_->AppCeasesToUseGeolocation(); -} - GeolocationManager::GeolocationManager( std::unique_ptr<SystemGeolocationSource> system_geolocation_source) : system_geolocation_source_(std::move(system_geolocation_source)), @@ -109,12 +100,20 @@ return *system_geolocation_source_; } -#else - -void GeolocationManager::AppAttemptsToUseGeolocation() {} - -void GeolocationManager::AppCeasesToUseGeolocation() {} - #endif +void GeolocationManager::TrackGeolocationAttempted( + const std::string& app_name) { +#if BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_CHROMEOS) + system_geolocation_source_->TrackGeolocationAttempted(app_name); +#endif +} + +void GeolocationManager::TrackGeolocationRelinquished( + const std::string& app_name) { +#if BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_CHROMEOS) + system_geolocation_source_->TrackGeolocationRelinquished(app_name); +#endif +} + } // namespace device
diff --git a/services/device/public/cpp/geolocation/geolocation_manager.h b/services/device/public/cpp/geolocation/geolocation_manager.h index 3550912e..546fe74 100644 --- a/services/device/public/cpp/geolocation/geolocation_manager.h +++ b/services/device/public/cpp/geolocation/geolocation_manager.h
@@ -6,6 +6,7 @@ #define SERVICES_DEVICE_PUBLIC_CPP_GEOLOCATION_GEOLOCATION_MANAGER_H_ #include <memory> +#include <string> #include "base/component_export.h" #include "build/build_config.h" @@ -33,8 +34,8 @@ // Sets the global instance of the Geolocation Manager. static void SetInstance(std::unique_ptr<GeolocationManager> manager); - void AppAttemptsToUseGeolocation(); - void AppCeasesToUseGeolocation(); + void TrackGeolocationAttempted(const std::string& app_name = ""); + void TrackGeolocationRelinquished(const std::string& app_name = ""); #if !BUILDFLAG(IS_APPLE) && !BUILDFLAG(IS_CHROMEOS) // Default empty implementation of Geolocation Manager. It is used on operation
diff --git a/services/device/public/cpp/geolocation/system_geolocation_source.h b/services/device/public/cpp/geolocation/system_geolocation_source.h index 08e2f9d..68cc9be4 100644 --- a/services/device/public/cpp/geolocation/system_geolocation_source.h +++ b/services/device/public/cpp/geolocation/system_geolocation_source.h
@@ -46,12 +46,12 @@ // Informs system that some page wants to use geolocation. This function may // be implemented if the OS specific implementation requires it. - virtual void AppAttemptsToUseGeolocation() {} + virtual void TrackGeolocationAttempted(const std::string& app_name) {} // Informs that some page does not need to use geolocation any more. This // function should be called only if the intention to use geolocation was - // signalled for the same page using AppAttemptsToUseGeolocation(). This + // signalled for the same page using TrackGeolocationAttempted(). This // function may be implemented if the OS specific implementation requires it. - virtual void AppCeasesToUseGeolocation() {} + virtual void TrackGeolocationRelinquished(const std::string& app_name) {} #if BUILDFLAG(IS_APPLE) // This method accepts a callback. The callback is to be called always when
diff --git a/services/device/public/cpp/geolocation/system_geolocation_source_mac.h b/services/device/public/cpp/geolocation/system_geolocation_source_mac.h index 64c87e1..86951c48 100644 --- a/services/device/public/cpp/geolocation/system_geolocation_source_mac.h +++ b/services/device/public/cpp/geolocation/system_geolocation_source_mac.h
@@ -41,7 +41,7 @@ void StopWatchingPosition() override; // Calls requestWhenInUseAuthorization from CLLocationManager. - void AppAttemptsToUseGeolocation() override; + void TrackGeolocationAttempted(const std::string& app_name) override; private: LocationSystemPermissionStatus GetSystemPermission() const;
diff --git a/services/device/public/cpp/geolocation/system_geolocation_source_mac.mm b/services/device/public/cpp/geolocation/system_geolocation_source_mac.mm index aed8700..8a15fa8 100644 --- a/services/device/public/cpp/geolocation/system_geolocation_source_mac.mm +++ b/services/device/public/cpp/geolocation/system_geolocation_source_mac.mm
@@ -110,7 +110,8 @@ return LocationSystemPermissionStatus::kDenied; } -void SystemGeolocationSourceMac::AppAttemptsToUseGeolocation() { +void SystemGeolocationSourceMac::TrackGeolocationAttempted( + const std::string& app_name) { #if BUILDFLAG(IS_IOS) if (@available(ios 8.0, macOS 10.15, *)) { [location_manager_ requestWhenInUseAuthorization];
diff --git a/services/network/public/cpp/proxy_config_mojom_traits.cc b/services/network/public/cpp/proxy_config_mojom_traits.cc index 5795671..700be7d4 100644 --- a/services/network/public/cpp/proxy_config_mojom_traits.cc +++ b/services/network/public/cpp/proxy_config_mojom_traits.cc
@@ -4,6 +4,8 @@ #include "services/network/public/cpp/proxy_config_mojom_traits.h" +#include "base/debug/dump_without_crashing.h" +#include "mojo/public/cpp/bindings/scoped_message_error_crash_key.h" #include "net/base/proxy_string_util.h" #include "url/gurl.h" @@ -27,8 +29,12 @@ if (!data.ReadRules(&rules)) return false; for (const auto& rule : rules) { - if (!out_proxy_bypass_rules->AddRuleFromString(rule)) + if (!out_proxy_bypass_rules->AddRuleFromString(rule)) { + mojo::debug::ScopedMessageErrorCrashKey crash_key_value( + "AddRuleFromString fault"); + base::debug::DumpWithoutCrashing(); return false; + } } return true; } @@ -51,8 +57,12 @@ return false; for (const auto& proxy : proxies) { net::ProxyServer proxy_server = net::PacResultElementToProxyServer(proxy); - if (!proxy_server.is_valid()) + if (!proxy_server.is_valid()) { + mojo::debug::ScopedMessageErrorCrashKey crash_key_value( + "!proxy_server.is_valid()"); + base::debug::DumpWithoutCrashing(); return false; + } out_proxy_list->AddProxyServer(proxy_server); } return true;
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json index 7235a06..d170b86 100644 --- a/testing/buildbot/chromium.chromiumos.json +++ b/testing/buildbot/chromium.chromiumos.json
@@ -5669,9 +5669,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5828.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5829.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 116.0.5828.0", + "description": "Run with ash-chrome version 116.0.5829.0", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -5682,8 +5682,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v116.0.5828.0", - "revision": "version:116.0.5828.0" + "location": "lacros_version_skew_tests_v116.0.5829.0", + "revision": "version:116.0.5829.0" } ], "dimension_sets": [ @@ -5834,9 +5834,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5828.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5829.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 116.0.5828.0", + "description": "Run with ash-chrome version 116.0.5829.0", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -5847,8 +5847,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v116.0.5828.0", - "revision": "version:116.0.5828.0" + "location": "lacros_version_skew_tests_v116.0.5829.0", + "revision": "version:116.0.5829.0" } ], "dimension_sets": [ @@ -5981,9 +5981,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5828.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5829.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 116.0.5828.0", + "description": "Run with ash-chrome version 116.0.5829.0", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -5994,8 +5994,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v116.0.5828.0", - "revision": "version:116.0.5828.0" + "location": "lacros_version_skew_tests_v116.0.5829.0", + "revision": "version:116.0.5829.0" } ], "dimension_sets": [
diff --git a/testing/buildbot/chromium.coverage.json b/testing/buildbot/chromium.coverage.json index 5d2b261..d8d827d0 100644 --- a/testing/buildbot/chromium.coverage.json +++ b/testing/buildbot/chromium.coverage.json
@@ -25493,9 +25493,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5828.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5829.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 116.0.5828.0", + "description": "Run with ash-chrome version 116.0.5829.0", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -25506,8 +25506,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v116.0.5828.0", - "revision": "version:116.0.5828.0" + "location": "lacros_version_skew_tests_v116.0.5829.0", + "revision": "version:116.0.5829.0" } ], "dimension_sets": [ @@ -25658,9 +25658,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5828.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5829.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 116.0.5828.0", + "description": "Run with ash-chrome version 116.0.5829.0", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -25671,8 +25671,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v116.0.5828.0", - "revision": "version:116.0.5828.0" + "location": "lacros_version_skew_tests_v116.0.5829.0", + "revision": "version:116.0.5829.0" } ], "dimension_sets": [ @@ -25805,9 +25805,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5828.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5829.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 116.0.5828.0", + "description": "Run with ash-chrome version 116.0.5829.0", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -25818,8 +25818,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v116.0.5828.0", - "revision": "version:116.0.5828.0" + "location": "lacros_version_skew_tests_v116.0.5829.0", + "revision": "version:116.0.5829.0" } ], "dimension_sets": [
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json index 24db1695..612331e 100644 --- a/testing/buildbot/chromium.fyi.json +++ b/testing/buildbot/chromium.fyi.json
@@ -38426,9 +38426,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5828.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5829.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 116.0.5828.0", + "description": "Run with ash-chrome version 116.0.5829.0", "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, @@ -38438,8 +38438,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v116.0.5828.0", - "revision": "version:116.0.5828.0" + "location": "lacros_version_skew_tests_v116.0.5829.0", + "revision": "version:116.0.5829.0" } ], "dimension_sets": [ @@ -38591,9 +38591,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5828.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5829.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 116.0.5828.0", + "description": "Run with ash-chrome version 116.0.5829.0", "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, @@ -38603,8 +38603,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v116.0.5828.0", - "revision": "version:116.0.5828.0" + "location": "lacros_version_skew_tests_v116.0.5829.0", + "revision": "version:116.0.5829.0" } ], "dimension_sets": [ @@ -38738,9 +38738,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5828.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5829.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 116.0.5828.0", + "description": "Run with ash-chrome version 116.0.5829.0", "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, @@ -38750,8 +38750,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v116.0.5828.0", - "revision": "version:116.0.5828.0" + "location": "lacros_version_skew_tests_v116.0.5829.0", + "revision": "version:116.0.5829.0" } ], "dimension_sets": [ @@ -40215,9 +40215,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5828.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5829.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 116.0.5828.0", + "description": "Run with ash-chrome version 116.0.5829.0", "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, @@ -40227,8 +40227,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v116.0.5828.0", - "revision": "version:116.0.5828.0" + "location": "lacros_version_skew_tests_v116.0.5829.0", + "revision": "version:116.0.5829.0" } ], "dimension_sets": [ @@ -40380,9 +40380,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5828.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5829.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 116.0.5828.0", + "description": "Run with ash-chrome version 116.0.5829.0", "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, @@ -40392,8 +40392,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v116.0.5828.0", - "revision": "version:116.0.5828.0" + "location": "lacros_version_skew_tests_v116.0.5829.0", + "revision": "version:116.0.5829.0" } ], "dimension_sets": [ @@ -40527,9 +40527,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5828.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5829.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 116.0.5828.0", + "description": "Run with ash-chrome version 116.0.5829.0", "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, @@ -40539,8 +40539,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v116.0.5828.0", - "revision": "version:116.0.5828.0" + "location": "lacros_version_skew_tests_v116.0.5829.0", + "revision": "version:116.0.5829.0" } ], "dimension_sets": [ @@ -41275,9 +41275,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5828.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5829.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 116.0.5828.0", + "description": "Run with ash-chrome version 116.0.5829.0", "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, @@ -41287,8 +41287,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v116.0.5828.0", - "revision": "version:116.0.5828.0" + "location": "lacros_version_skew_tests_v116.0.5829.0", + "revision": "version:116.0.5829.0" } ], "dimension_sets": [
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json index 6a51f841..c2a51b6c 100644 --- a/testing/buildbot/chromium.memory.json +++ b/testing/buildbot/chromium.memory.json
@@ -18080,12 +18080,12 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5828.0/test_ash_chrome", + "--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5829.0/test_ash_chrome", "--test-launcher-print-test-stdio=always", "--combine-ash-logs-on-bots", "--asan-symbolize-output" ], - "description": "Run with ash-chrome version 116.0.5828.0", + "description": "Run with ash-chrome version 116.0.5829.0", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -18096,8 +18096,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v116.0.5828.0", - "revision": "version:116.0.5828.0" + "location": "lacros_version_skew_tests_v116.0.5829.0", + "revision": "version:116.0.5829.0" } ], "dimension_sets": [ @@ -18265,12 +18265,12 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5828.0/test_ash_chrome", + "--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5829.0/test_ash_chrome", "--test-launcher-print-test-stdio=always", "--combine-ash-logs-on-bots", "--asan-symbolize-output" ], - "description": "Run with ash-chrome version 116.0.5828.0", + "description": "Run with ash-chrome version 116.0.5829.0", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -18281,8 +18281,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v116.0.5828.0", - "revision": "version:116.0.5828.0" + "location": "lacros_version_skew_tests_v116.0.5829.0", + "revision": "version:116.0.5829.0" } ], "dimension_sets": [ @@ -18427,12 +18427,12 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5828.0/test_ash_chrome", + "--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5829.0/test_ash_chrome", "--test-launcher-print-test-stdio=always", "--combine-ash-logs-on-bots", "--asan-symbolize-output" ], - "description": "Run with ash-chrome version 116.0.5828.0", + "description": "Run with ash-chrome version 116.0.5829.0", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -18443,8 +18443,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v116.0.5828.0", - "revision": "version:116.0.5828.0" + "location": "lacros_version_skew_tests_v116.0.5829.0", + "revision": "version:116.0.5829.0" } ], "dimension_sets": [
diff --git a/testing/buildbot/variants.pyl b/testing/buildbot/variants.pyl index 76432ce..1b19ba8 100644 --- a/testing/buildbot/variants.pyl +++ b/testing/buildbot/variants.pyl
@@ -22,16 +22,16 @@ }, 'LACROS_VERSION_SKEW_CANARY': { 'args': [ - '--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5828.0/test_ash_chrome', + '--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5829.0/test_ash_chrome', ], - 'description': 'Run with ash-chrome version 116.0.5828.0', + 'description': 'Run with ash-chrome version 116.0.5829.0', 'identifier': 'Lacros version skew testing ash canary', 'swarming': { 'cipd_packages': [ { 'cipd_package': 'chromium/testing/linux-ash-chromium/x86_64/ash.zip', - 'location': 'lacros_version_skew_tests_v116.0.5828.0', - 'revision': 'version:116.0.5828.0', + 'location': 'lacros_version_skew_tests_v116.0.5829.0', + 'revision': 'version:116.0.5829.0', }, ], },
diff --git a/testing/libfuzzer/getting_started.md b/testing/libfuzzer/getting_started.md index be4a1fa..6879da3c 100644 --- a/testing/libfuzzer/getting_started.md +++ b/testing/libfuzzer/getting_started.md
@@ -8,70 +8,78 @@ ## Getting started -### Setting up your build environment +### Simple Example -Generate build files by using the `use_libfuzzer` [GN] argument together with a -sanitizer. Pick the [GN config] that corresponds to the DUT you're deploying to: +Before writing any code let us look at a simple +examples of a test that uses input fuzzing. The test is setup to exercise the +[`CreateFnmatchQuery`](https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/ash/extensions/file_manager/search_by_pattern.h;drc=4bc4bcef0ab5581a5a27cea986296739582243a6) +function. The role of this function is to take a user query and produce +a case-insensitive pattern that matches file names containing the +query in them. For example, for a query "1abc" the function generates +"\*1[aA][bB][cC]\*". Unlike a traditional test, an input fuzzing test does not +care about the output of the tested function. Instead it verifies that that no +matter what string the user enters `CreateFnmatchQuery` does not do something +unexpected, such as a crash, overriding a memory region, etc. The test +[create_fnmatch_query_fuzzer.cc](https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/ash/extensions/file_manager/create_fnmatch_query_fuzzer.cc;drc=1f5a5af3eb1bbdf9e4566c3e6d2051e68de112eb) +is shown below: -```bash -# AddressSanitizer is the default config we recommend testing with. -# Linux: -tools/mb/mb.py gen -m chromium.fuzz -b 'Libfuzzer Upload Linux ASan' out/libfuzzer -# Chrome OS: -tools/mb/mb.py gen -m chromium.fuzz -b 'Libfuzzer Upload Chrome OS ASan' out/libfuzzer -# Mac: -tools/mb/mb.py gen -m chromium.fuzz -b 'Libfuzzer Upload Mac ASan' out/libfuzzer -# Windows: -python tools\mb\mb.py gen -m chromium.fuzz -b "Libfuzzer Upload Windows ASan" out\libfuzzer +```cpp +#include <stddef.h> +#include <stdint.h> + +#include <string> + +#include "chrome/browser/ash/extensions/file_manager/search_by_pattern.h" + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + std::string str = std::string(reinterpret_cast<const char*>(data), size); + extensions::CreateFnmatchQuery(str); + return 0; +} ``` -If testing things locally these are the recommended configurations +The code starts by including `stddef.h` for `size_t` definition, `stdint.h` +for `uint8_t` definition, `string` for `std::string` definition and finally +the file where `extensions::CreateFnmatchQuery` function is defined. Next +it declares and defines the `LLVMFuzzerTestOneInput` function, which is +the function called by the testing framework. The function is supplied with two +arguments, a pointer to an array of bytes, and the size of the array. These +bytes are generated by the fuzzing test harness and their specific values +are irrelevant. The job of the test is to convert those bytes to input +parameters of the tested function. In our case bytes are converted +to a `std::string` and given to the `CreateFnmatchQuery` function. If +the function completes its job and the code successfully returns, the +`LLVMFuzzerTestOneInput` function returns 0, signaling a successful execution. -```bash -# AddressSanitizer is the default config we recommend testing with. -# Linux: -tools/mb/mb.py gen -m chromium.fuzz -b 'Libfuzzer Local Linux ASan' out/libfuzzer -# Chrome OS: -tools/mb/mb.py gen -m chromium.fuzz -b 'Libfuzzer Local Chrome OS ASan' out/libfuzzer -# Mac: -tools/mb/mb.py gen -m chromium.fuzz -b 'Libfuzzer Local Mac ASan' out/libfuzzer -# Windows: -python tools\mb\mb.py gen -m chromium.fuzz -b "Libfuzzer Local Windows ASan" out\libfuzzer +The above pattern is typical to fuzzing tests. You create a +`LLVMFuzzerTestOneInput` function. You then write code that uses the provided +random bytes to form input parameters to the function you intend to test. Next, +you call the function, and if it successfully completes, return 0. + +To run this test we need to create a `fuzzer_test` target in the appropriate +`BUILD.gn` file. For the above example, the target is defined as + +```python +fuzzer_test("create_fnmatch_query_fuzzer") { + sources = [ "extensions/file_manager/create_fnmatch_query_fuzzer.cc" ] + deps = [ + ":ash", + "//base", + "//chrome/browser", + "//components/exo/wayland:ui_controls_protocol", + "//components/exo/wayland:weston_test", + ] +} ``` - -*** note -**Note:** The above invocations may set `use_remoteexec` or `use_rbe` to true. -However, these args aren't compatible on local workstations yet. So if you run -into reclient errors when building locally, remove both those args and set -`use_goma` instead. - -You can also invoke [AFL] by using the `use_afl` GN argument, but we -recommend libFuzzer for local development. Running libFuzzer locally doesn't -require any special configuration and gives quick, meaningful output for speed, -coverage, and other parameters. -*** - -It’s possible to run fuzz targets without sanitizers, but not recommended, as -sanitizers help to detect errors which may not result in a crash otherwise. -`use_libfuzzer` is supported in the following sanitizer configurations. - -| GN Argument | Description | Supported OS | -|-------------|-------------|--------------| -| `is_asan=true` | Enables [AddressSanitizer] to catch problems like buffer overruns. | Linux, Windows, Mac, Chrome OS | -| `is_msan=true` | Enables [MemorySanitizer] to catch problems like uninitialized reads<sup>\[[\*](reference.md#MSan)\]</sup>. | Linux | -| `is_ubsan_security=true` | Enables [UndefinedBehaviorSanitizer] to catch<sup>\[[\*](reference.md#UBSan)\]</sup> undefined behavior like integer overflow.| Linux | - -For more on builder and sanitizer configurations, see the [Integration -Reference] page. - -*** note -**Hint**: Fuzz targets are built with minimal symbols by default. You can adjust -the symbol level by setting the `symbol_level` attribute. -*** +The source field typically specified just the file that contains the test. The +dependencies are specific to the tested function. Here we are listing them for +the completeness. In your test all but `//base` dependencies are unlikely to be +required. ### Creating your first fuzz target -After you set up your build environment, you can create your first fuzz target: +Having seen a concrete example, let us describe the generic flow of steps to +create a new fuzzing test. 1. In the same directory as the code you are going to fuzz (or next to the tests for that code), create a new `<my_fuzzer>.cc` file. @@ -112,21 +120,91 @@ target. *** +Once you created your first fuzz target, in order to run it, you must set up +your build environment. This is described next. + +### Setting up your build environment + +Generate build files by using the `use_libfuzzer` [GN] argument together with a +sanitizer. Rather than generating a GN build configuration by hand, we recommend +that you run the meta-builder tool using [GN config] that corresponds to the +operating system of the DUT you're deploying to: + +```bash +# AddressSanitizer is the default config we recommend testing with. +# Linux: +tools/mb/mb.py gen -m chromium.fuzz -b 'Libfuzzer Upload Linux ASan' out/libfuzzer +# Chrome OS: +tools/mb/mb.py gen -m chromium.fuzz -b 'Libfuzzer Upload Chrome OS ASan' out/libfuzzer +# Mac: +tools/mb/mb.py gen -m chromium.fuzz -b 'Libfuzzer Upload Mac ASan' out/libfuzzer +# Windows: +python tools\mb\mb.py gen -m chromium.fuzz -b "Libfuzzer Upload Windows ASan" out\libfuzzer +``` + +If testing things locally these are the recommended configurations + +```bash +# AddressSanitizer is the default config we recommend testing with. +# Linux: +tools/mb/mb.py gen -m chromium.fuzz -b 'Libfuzzer Local Linux ASan' out/libfuzzer +# Chrome OS: +tools/mb/mb.py gen -m chromium.fuzz -b 'Libfuzzer Local Chrome OS ASan' out/libfuzzer +# Mac: +tools/mb/mb.py gen -m chromium.fuzz -b 'Libfuzzer Local Mac ASan' out/libfuzzer +# Windows: +python tools\mb\mb.py gen -m chromium.fuzz -b "Libfuzzer Local Windows ASan" out\libfuzzer +``` + +[`tools/mb/mb.py`](https://source.chromium.org/chromium/chromium/src/+/main:tools/mb/mb.py;drc=c771c017eca9a6a859d245be54c511acafdc9867) +is "a wrapper script for GN that [..] generate[s] build files for sets of +canned configurations." The `-m` flag selects the builder group, while the +`-b` flag selects a specific builder in the builder group. The `out/libfuzzer` +is the directory to which GN configuration is written. If you wish, you can +inspect the generated config by running `gn args out/libfuzzer`, once the +`mb.py` script is done. + +*** note +**Note:** The above invocations may set `use_remoteexec` or `use_rbe` to true. +However, these args aren't compatible on local workstations yet. So if you run +into reclient errors when building locally, remove both those args and set +`use_goma` instead. + +You can also invoke [AFL] by using the `use_afl` GN argument, but we +recommend libFuzzer for local development. Running libFuzzer locally doesn't +require any special configuration and gives quick, meaningful output for speed, +coverage, and other parameters. +*** + +It’s possible to run fuzz targets without sanitizers, but not recommended, as +sanitizers help to detect errors which may not result in a crash otherwise. +`use_libfuzzer` is supported in the following sanitizer configurations. + +| GN Argument | Description | Supported OS | +|-------------|-------------|--------------| +| `is_asan=true` | Enables [AddressSanitizer] to catch problems like buffer overruns. | Linux, Windows, Mac, Chrome OS | +| `is_msan=true` | Enables [MemorySanitizer] to catch problems like uninitialized reads<sup>\[[\*](reference.md#MSan)\]</sup>. | Linux | +| `is_ubsan_security=true` | Enables [UndefinedBehaviorSanitizer] to catch<sup>\[[\*](reference.md#UBSan)\]</sup> undefined behavior like integer overflow.| Linux | + +For more on builder and sanitizer configurations, see the [Integration +Reference] page. + +*** note +**Hint**: Fuzz targets are built with minimal symbols by default. You can adjust +the symbol level by setting the `symbol_level` attribute. +*** + ### Running the fuzz target -After you create your fuzz target, build it with autoninja and run it locally. In -most cases you don't want to commit your locally generated corpus, so save it -somewhere like `/tmp/corpus`. +After you create your fuzz target, build it with autoninja and run it locally. +To make this example concrete, we are going to use the existing +`create_fnmatch_query_fuzzer` target. ```bash # Build the fuzz target. -autoninja -C out/libfuzzer url_parse_fuzzer -# Create an empty corpus directory. -mkdir /tmp/corpus +autoninja -C chrome/browser/ash:create_fnmatch_query_fuzzer # Run the fuzz target. -./out/libfuzzer/url_parse_fuzzer /tmp/corpus -# If have other corpus directories, pass their paths as well: -./out/libfuzzer/url_parse_fuzzer /tmp/corpus seed_corpus_dir_1 seed_corpus_dir_N +./out/libfuzzer/create_fnmatch_query_fuzzer ``` Your fuzz target should produce output like this:
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index 6d78f4c1..f4cb4c40 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -792,11 +792,26 @@ ], "experiments": [ { + "name": "Enabled_Dogfood", + "enable_features": [ + "ArcVmmSwapPolicy", + "ArcvmSwapoutKeyboardShortcut" + ], + "min_os_version": "15485.0.0" + } + ] + }, + { + "platforms": [ + "chromeos" + ], + "experiments": [ + { "name": "Enabled", "enable_features": [ "ArcVmmSwapPolicy" ], - "min_os_version": "15474.2.0" + "min_os_version": "15485.0.0" } ] } @@ -870,6 +885,26 @@ ] } ], + "AsyncCacheLock": [ + { + "platforms": [ + "android", + "chromeos", + "chromeos_lacros", + "linux", + "mac", + "windows" + ], + "experiments": [ + { + "name": "Enabled", + "enable_features": [ + "AsyncCacheLock" + ] + } + ] + } + ], "AsyncDnsLinux": [ { "platforms": [ @@ -10170,6 +10205,21 @@ ] } ], + "PdfOcr": [ + { + "platforms": [ + "chromeos" + ], + "experiments": [ + { + "name": "Enabled", + "enable_features": [ + "PdfOcr" + ] + } + ] + } + ], "PdfUseSkiaRenderer": [ { "platforms": [ @@ -10997,6 +11047,9 @@ "name": "Enabled", "enable_features": [ "ProcessPerSiteUpToMainFrameThreshold" + ], + "disable_features": [ + "AllowDevToolsMainThreadDebuggerForMultipleMainFrames" ] } ] @@ -12671,25 +12724,14 @@ ], "experiments": [ { - "name": "FindRegistrationImprovements_20230222", + "name": "FindReg_20230609", "enable_features": [ + "ServiceWorkerFetchResponseCallbackUseHighPriority", "ServiceWorkerMergeFindRegistrationForClientUrl", + "ServiceWorkerRegistrationCache", "ServiceWorkerScopeCache", "ServiceWorkerStorageControlOnThreadPool", "ServiceWorkerStorageControlResponseUseHighPriority" - ], - "disable_features": [ - "SpeculativeServiceWorkerStartup" - ] - }, - { - "name": "FindRegistrationImprovements_20221130", - "enable_features": [ - "ServiceWorkerStorageControlOnThreadPool", - "ServiceWorkerStorageControlResponseUseHighPriority" - ], - "disable_features": [ - "SpeculativeServiceWorkerStartup" ] } ]
diff --git a/third_party/blink/public/mojom/service_worker/service_worker.mojom b/third_party/blink/public/mojom/service_worker/service_worker.mojom index d1250c6..3470b82 100644 --- a/third_party/blink/public/mojom/service_worker/service_worker.mojom +++ b/third_party/blink/public/mojom/service_worker/service_worker.mojom
@@ -27,6 +27,7 @@ import "third_party/blink/public/mojom/service_worker/service_worker_fetch_response_callback.mojom"; import "third_party/blink/public/mojom/service_worker/service_worker_object.mojom"; import "third_party/blink/public/mojom/service_worker/service_worker_registration.mojom"; +import "third_party/blink/public/mojom/service_worker/service_worker_router_rule.mojom"; import "third_party/blink/public/mojom/storage_key/storage_key.mojom"; import "url/mojom/origin.mojom"; import "url/mojom/url.mojom"; @@ -112,6 +113,13 @@ // On success, |error| is kNone without |error_msg| set. // Otherwise, |error| and |error_msg| describe the failure. ClaimClients() => (ServiceWorkerErrorType error, string? error_msg); + + // Experimental feature. + // Registers the service worker router rules, which are evaluated before + // the regular navigation path. i.e. evaluated before the service worker + // fetch handler is invoked. The method may only be called once. + // https://github.com/yoshisatoyanagisawa/service-worker-static-routing-api + RegisterRouter(ServiceWorkerRouterRules rules) => (); }; struct ExtendableMessageEvent {
diff --git a/third_party/blink/renderer/core/dom/child_node_part.h b/third_party/blink/renderer/core/dom/child_node_part.h index 6e6f8f68..1e00d4a6 100644 --- a/third_party/blink/renderer/core/dom/child_node_part.h +++ b/third_party/blink/renderer/core/dom/child_node_part.h
@@ -22,7 +22,7 @@ // Implementation of the ChildNodePart class, which is part of the DOM Parts // API. A ChildNodePart stores a reference to a range of nodes within the // children of a single parent |Node| in the DOM tree. -class CORE_EXPORT ChildNodePart : public Part { +class CORE_EXPORT ChildNodePart : public PartRoot { DEFINE_WRAPPERTYPEINFO(); public: @@ -54,11 +54,12 @@ return HeapVector<Member<Node>>(); } // TODO(crbug.com/1453291) Implement this method. - HeapVector<Member<Part>> getParts() const { + HeapVector<Member<Part>> getParts() override { return HeapVector<Member<Part>>(); } + // TODO(crbug.com/1453291) Implement this method. - DocumentPart* clone() const { return nullptr; } + PartRoot* root() const override { return nullptr; } // TODO(crbug.com/1453291) Implement this method. void replaceChildren(const HeapVector<Member<V8UnionNodeOrString>>& nodes) {}
diff --git a/third_party/blink/renderer/core/dom/child_node_part.idl b/third_party/blink/renderer/core/dom/child_node_part.idl index f1eafa70a..228e94a 100644 --- a/third_party/blink/renderer/core/dom/child_node_part.idl +++ b/third_party/blink/renderer/core/dom/child_node_part.idl
@@ -5,12 +5,10 @@ // https://github.com/tbondwilkinson/dom-parts [RuntimeEnabled=DOMPartsAPI,Exposed=Window] -interface ChildNodePart : Part { +interface ChildNodePart : PartRoot { constructor(Node previousSibling, Node nextSibling, optional NodePartInit init = {}); readonly attribute Node previousSibling; readonly attribute Node nextSibling; readonly attribute FrozenArray<Node> children; - FrozenArray<Part> getParts(); - ChildNodePart clone(); void replaceChildren((Node or DOMString)... nodes); };
diff --git a/third_party/blink/renderer/core/dom/document_part.cc b/third_party/blink/renderer/core/dom/document_part.cc index 10e5c5d..1bade56a 100644 --- a/third_party/blink/renderer/core/dom/document_part.cc +++ b/third_party/blink/renderer/core/dom/document_part.cc
@@ -8,8 +8,8 @@ #include "third_party/blink/renderer/bindings/core/v8/v8_union_document_documentfragment.h" #include "third_party/blink/renderer/core/dom/document.h" #include "third_party/blink/renderer/core/dom/document_fragment.h" -#include "third_party/blink/renderer/core/dom/part_root.h" #include "third_party/blink/renderer/platform/bindings/exception_state.h" +#include "third_party/blink/renderer/platform/bindings/script_wrappable.h" namespace blink {
diff --git a/third_party/blink/renderer/core/dom/document_part.h b/third_party/blink/renderer/core/dom/document_part.h index 9476584..cda1051 100644 --- a/third_party/blink/renderer/core/dom/document_part.h +++ b/third_party/blink/renderer/core/dom/document_part.h
@@ -8,6 +8,7 @@ #include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/core/dom/part_root.h" #include "third_party/blink/renderer/platform/bindings/script_wrappable.h" +#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h" #include "third_party/blink/renderer/platform/heap/garbage_collected.h" #include "third_party/blink/renderer/platform/heap/member.h" @@ -15,10 +16,11 @@ class Document; class DocumentFragment; +class Part; class V8UnionDocumentOrDocumentFragment; // Implementation of the DocumentPart class, which is part of the DOM Parts API. -// A DocumentPart represents the PartRoot for a |Document| object. +// A DocumentPart holds the parts for a Document or DocumentFragment object. class CORE_EXPORT DocumentPart : public PartRoot { DEFINE_WRAPPERTYPEINFO(); @@ -38,7 +40,13 @@ void Trace(Visitor*) const override; // DocumentPart API + // TODO(crbug.com/1453291) Implement this method. + PartRoot* root() const override { return nullptr; } DocumentPart* clone() const; + // TODO(crbug.com/1453291) Implement this method. + HeapVector<Member<Part>> getParts() override { + return HeapVector<Member<Part>>(); + } private: Member<Document> document_;
diff --git a/third_party/blink/renderer/core/dom/node_part.h b/third_party/blink/renderer/core/dom/node_part.h index 50e4c1c..854aa84 100644 --- a/third_party/blink/renderer/core/dom/node_part.h +++ b/third_party/blink/renderer/core/dom/node_part.h
@@ -13,6 +13,8 @@ namespace blink { +class PartRoot; + // Implementation of the NodePart class, which is part of the DOM Parts API. // A NodePart stores a reference to a single |Node| in the DOM tree. class CORE_EXPORT NodePart : public Part { @@ -34,6 +36,8 @@ // NodePart API Node* node() const { return node_; } + // TODO(crbug.com/1453291) Implement this method. + PartRoot* root() const override { return nullptr; } private: Member<Node> node_;
diff --git a/third_party/blink/renderer/core/dom/part.h b/third_party/blink/renderer/core/dom/part.h index eef6fdfc..adb1284 100644 --- a/third_party/blink/renderer/core/dom/part.h +++ b/third_party/blink/renderer/core/dom/part.h
@@ -25,10 +25,9 @@ ~Part() override = default; // Part API + virtual PartRoot* root() const = 0; // TODO(crbug.com/1453291) Implement this method. - PartRoot* root() const { return nullptr; } - // TODO(crbug.com/1453291) Implement this method. HeapVector<String> metadata() const { return HeapVector<String>(); } void disconnect() {}
diff --git a/third_party/blink/renderer/core/dom/part_root.h b/third_party/blink/renderer/core/dom/part_root.h index 39dd7336..430eece 100644 --- a/third_party/blink/renderer/core/dom/part_root.h +++ b/third_party/blink/renderer/core/dom/part_root.h
@@ -5,34 +5,27 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_DOM_PART_ROOT_H_ #define THIRD_PARTY_BLINK_RENDERER_CORE_DOM_PART_ROOT_H_ +#include "third_party/blink/renderer/bindings/core/v8/v8_part_root.h" #include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/core/dom/part.h" -#include "third_party/blink/renderer/platform/bindings/script_wrappable.h" #include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h" +#include "third_party/blink/renderer/platform/heap/garbage_collected.h" +#include "third_party/blink/renderer/platform/heap/member.h" namespace blink { // Implementation of the PartRoot class, which is part of the DOM Parts API. -// A PartRoot can exist for a |Document| or |DocumentFragment|, and this the -// entrypoint for the |getParts()| interface, which queries for contained parts. -class CORE_EXPORT PartRoot : public ScriptWrappable { +// A PartRoot adds getParts to Part. +class CORE_EXPORT PartRoot : public Part { DEFINE_WRAPPERTYPEINFO(); public: + PartRoot() = default; PartRoot(const PartRoot&) = delete; ~PartRoot() override = default; - void Trace(Visitor* visitor) const override { - ScriptWrappable::Trace(visitor); - } - // PartRoot API - - // TODO(crbug.com/1453291) Implement this method. - HeapVector<Member<Part>> getParts() { return HeapVector<Member<Part>>(); } - - protected: - PartRoot() = default; + virtual HeapVector<Member<Part>> getParts() = 0; }; } // namespace blink
diff --git a/third_party/blink/renderer/core/dom/part_root.idl b/third_party/blink/renderer/core/dom/part_root.idl index 99b4342..5859930 100644 --- a/third_party/blink/renderer/core/dom/part_root.idl +++ b/third_party/blink/renderer/core/dom/part_root.idl
@@ -5,6 +5,6 @@ // https://github.com/tbondwilkinson/dom-parts/blob/main/README.md [RuntimeEnabled=DOMPartsAPI,Exposed=Window] -interface PartRoot { +interface PartRoot : Part { FrozenArray<Part> getParts(); };
diff --git a/third_party/blink/renderer/core/inspector/main_thread_debugger.cc b/third_party/blink/renderer/core/inspector/main_thread_debugger.cc index 3e4c70b..afe62a4 100644 --- a/third_party/blink/renderer/core/inspector/main_thread_debugger.cc +++ b/third_party/blink/renderer/core/inspector/main_thread_debugger.cc
@@ -31,9 +31,11 @@ #include "third_party/blink/renderer/core/inspector/main_thread_debugger.h" #include <memory> +#include <set> #include "base/feature_list.h" #include "base/synchronization/lock.h" +#include "base/unguessable_token.h" #include "build/chromeos_buildflags.h" #include "third_party/blink/public/common/features.h" #include "third_party/blink/renderer/bindings/core/v8/binding_security.h" @@ -346,14 +348,14 @@ return true; } - size_t num_main_frames = 0; + std::set<base::UnguessableToken> browsing_context_group_tokens; for (auto& page : Page::OrdinaryPages()) { if (page->MainFrame() && page->MainFrame()->IsOutermostMainFrame()) { - ++num_main_frames; + browsing_context_group_tokens.insert(page->BrowsingContextGroupToken()); } } - if (num_main_frames > 1) { + if (browsing_context_group_tokens.size() > 1) { String message = String( "DevTools debugger is disabled because it is attached to a process " "that hosts multiple top-level frames, where DevTools debugger doesn't "
diff --git a/third_party/blink/renderer/core/intersection_observer/intersection_geometry.cc b/third_party/blink/renderer/core/intersection_observer/intersection_geometry.cc index 31a6a0a..d864dc4 100644 --- a/third_party/blink/renderer/core/intersection_observer/intersection_geometry.cc +++ b/third_party/blink/renderer/core/intersection_observer/intersection_geometry.cc
@@ -333,8 +333,7 @@ RootAndTarget root_and_target(root_node, target_element); if (ShouldUseCachedRects()) { - CHECK(!RootIsImplicit() || - RuntimeEnabledFeatures::IntersectionOptimizationEnabled()); + CHECK(!RootIsImplicit()); // Cached rects can only be used if there are no scrollable objects in the // hierarchy between target and root (a scrollable root is ok). The reason // is that a scroll change in an intermediate scroller would change the
diff --git a/third_party/blink/renderer/core/intersection_observer/intersection_observation.cc b/third_party/blink/renderer/core/intersection_observer/intersection_observation.cc index e33cdd2a..1703015 100644 --- a/third_party/blink/renderer/core/intersection_observer/intersection_observation.cc +++ b/third_party/blink/renderer/core/intersection_observer/intersection_observation.cc
@@ -39,11 +39,8 @@ // should be -1, but since last_threshold_index_ is unsigned, we use a // different sentinel value. last_threshold_index_(kMaxThresholdIndex - 1) { - if (!observer.RootIsImplicit() || - RuntimeEnabledFeatures::IntersectionOptimizationEnabled()) { - // TODO(crbug.com/1400495): Avoid unique_ptr for IntersectionOptimization. + if (!observer.RootIsImplicit()) cached_rects_ = std::make_unique<IntersectionGeometry::CachedRects>(); - } } int64_t IntersectionObservation::ComputeIntersection( @@ -67,8 +64,7 @@ [this](unsigned geometry_flags) { return IntersectionGeometry( observer_->root(), *Target(), observer_->RootMargin(), - observer_->thresholds(), observer_->TargetMargin(), geometry_flags, - cached_rects_.get()); + observer_->thresholds(), observer_->TargetMargin(), geometry_flags); }, compute_flags, monotonic_time); }
diff --git a/third_party/blink/renderer/core/intersection_observer/intersection_observer_test.cc b/third_party/blink/renderer/core/intersection_observer/intersection_observer_test.cc index 934ba5d..152fdcc5 100644 --- a/third_party/blink/renderer/core/intersection_observer/intersection_observer_test.cc +++ b/third_party/blink/renderer/core/intersection_observer/intersection_observer_test.cc
@@ -1126,59 +1126,6 @@ } } -TEST_P(IntersectionObserverTest, CachedRectsImplicitRoot) { - WebView().MainFrameViewWidget()->Resize(gfx::Size(800, 600)); - SimRequest main_resource("https://example.com/", "text/html"); - SimRequest iframe_resource("https://example.com/iframe.html", "text/html"); - LoadURL("https://example.com/"); - main_resource.Complete(R"HTML( - <div id="target-in-main">Hello, world!</div> - <iframe src="iframe.html" style="width:200px; height:100px"></iframe> - <div id='spacer' style='height:2000px'></div> - )HTML"); - iframe_resource.Complete(R"HTML( - <div id='target-in-frame'>Hello, world!</div> - <div id='spacer' style='height:2000px'></div> - )HTML"); - - auto do_nothing = base::DoNothingAs<void( - const HeapVector<Member<IntersectionObserverEntry>>&)>(); - IntersectionObserver* observer_in_main = IntersectionObserver::Create( - {}, {}, &GetDocument(), do_nothing, LocalFrameUkmAggregator::kLayout); - Document* iframe_document = To<WebLocalFrameImpl>(MainFrame().FirstChild()) - ->GetFrame() - ->GetDocument(); - Element* target_in_main = GetDocument().getElementById("target-in-main"); - DummyExceptionStateForTesting exception_state; - observer_in_main->observe(target_in_main, exception_state); - ASSERT_FALSE(exception_state.HadException()); - - IntersectionObserver* observer_in_frame = IntersectionObserver::Create( - {}, {}, iframe_document, do_nothing, LocalFrameUkmAggregator::kLayout); - Element* target_in_frame = iframe_document->getElementById("target-in-frame"); - observer_in_frame->observe(target_in_frame, exception_state); - ASSERT_FALSE(exception_state.HadException()); - - IntersectionObservation* observation_in_main = - target_in_main->IntersectionObserverData()->GetObservationFor( - *observer_in_main); - EXPECT_FALSE(observation_in_main->CanUseCachedRectsForTesting()); - IntersectionObservation* observation_in_frame = - target_in_frame->IntersectionObserverData()->GetObservationFor( - *observer_in_frame); - EXPECT_FALSE(observation_in_frame->CanUseCachedRectsForTesting()); - - // Generate initial notifications and populate cache. - Compositor().BeginFrame(); - test::RunPendingTasks(); - - if (RuntimeEnabledFeatures::IntersectionOptimizationEnabled()) { - EXPECT_TRUE(observation_in_main->CanUseCachedRectsForTesting()); - } else { - EXPECT_FALSE(observation_in_main->CanUseCachedRectsForTesting()); - } -} - TEST_P(IntersectionObserverTest, MinScrollDeltaToUpdateThresholdZero) { if (!RuntimeEnabledFeatures::IntersectionOptimizationEnabled()) { return;
diff --git a/third_party/blink/renderer/core/layout/build.gni b/third_party/blink/renderer/core/layout/build.gni index 074fe4e8..8e84e8e 100644 --- a/third_party/blink/renderer/core/layout/build.gni +++ b/third_party/blink/renderer/core/layout/build.gni
@@ -315,6 +315,8 @@ "ng/inline/ng_line_truncator.h", "ng/inline/ng_line_utils.cc", "ng/inline/ng_line_utils.h", + "ng/inline/ng_line_widths.cc", + "ng/inline/ng_line_widths.h", "ng/inline/ng_logical_line_item.cc", "ng/inline/ng_logical_line_item.h", "ng/inline/ng_offset_mapping.cc", @@ -749,6 +751,7 @@ "ng/inline/ng_line_breaker_test.cc", "ng/inline/ng_line_break_candidate_test.cc", "ng/inline/ng_line_info_list_test.cc", + "ng/inline/ng_line_widths_test.cc", "ng/inline/ng_offset_mapping_test.cc", "ng/inline/ng_paragraph_line_breaker_test.cc", "ng/inline/ng_physical_line_box_fragment_test.cc",
diff --git a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_item.cc b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_item.cc index 2daa1cf..588a5bf 100644 --- a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_item.cc +++ b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_item.cc
@@ -227,8 +227,9 @@ GridTrackSizingDirection track_direction, bool has_synthesized_baseline) { // Alignment fallback is only possible when baseline alignment is specified. - if (!IsBaselineSpecifiedForDirection(track_direction)) + if (!IsBaselineSpecified(track_direction)) { return; + } auto CanParticipateInBaselineAlignment = [&]() -> bool { // "If baseline alignment is specified on a grid item whose size in that
diff --git a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_item.h b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_item.h index ab6bf3d8..6d45f68 100644 --- a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_item.h +++ b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_item.h
@@ -56,38 +56,37 @@ is_block_axis_overflow_safe); } - bool IsBaselineAlignedForDirection( - GridTrackSizingDirection track_direction) const { - // TODO(ethavar): Baseline alignment for subgrids is dependent on - // accumulating the baseline in `ComputeSubgridContributionSize`. - if (has_subgridded_columns || has_subgridded_rows || - is_subgridded_to_parent_grid) { + bool IsBaselineAligned(GridTrackSizingDirection track_direction) const { + const bool is_for_columns = track_direction == kForColumns; + const bool has_subgridded_axis = + is_for_columns ? has_subgridded_columns : has_subgridded_rows; + + if (has_subgridded_axis) { return false; } - return (track_direction == kForColumns) - ? (InlineAxisAlignment() == AxisEdge::kFirstBaseline || - InlineAxisAlignment() == AxisEdge::kLastBaseline) - : (BlockAxisAlignment() == AxisEdge::kFirstBaseline || - BlockAxisAlignment() == AxisEdge::kLastBaseline); + + const auto axis_alignment = + is_for_columns ? InlineAxisAlignment() : BlockAxisAlignment(); + return (axis_alignment == AxisEdge::kFirstBaseline || + axis_alignment == AxisEdge::kLastBaseline); } - bool IsBaselineSpecifiedForDirection( - GridTrackSizingDirection track_direction) const { - // TODO(ethavar): Baseline alignment for subgrids is dependent on - // accumulating the baseline in `ComputeSubgridContributionSize`. - if (has_subgridded_columns || has_subgridded_rows || - is_subgridded_to_parent_grid) { + bool IsBaselineSpecified(GridTrackSizingDirection track_direction) const { + const bool is_for_columns = track_direction == kForColumns; + const bool has_subgridded_axis = + is_for_columns ? has_subgridded_columns : has_subgridded_rows; + + if (has_subgridded_axis) { return false; } - return (track_direction == kForColumns) - ? (inline_axis_alignment == AxisEdge::kFirstBaseline || - inline_axis_alignment == AxisEdge::kLastBaseline) - : (block_axis_alignment == AxisEdge::kFirstBaseline || - block_axis_alignment == AxisEdge::kLastBaseline); + + const auto axis_alignment = + is_for_columns ? inline_axis_alignment : block_axis_alignment; + return (axis_alignment == AxisEdge::kFirstBaseline || + axis_alignment == AxisEdge::kLastBaseline); } - bool IsLastBaselineSpecifiedForDirection( - GridTrackSizingDirection track_direction) const { + bool IsLastBaselineSpecified(GridTrackSizingDirection track_direction) const { return (track_direction == kForColumns) ? inline_axis_alignment == AxisEdge::kLastBaseline : block_axis_alignment == AxisEdge::kLastBaseline;
diff --git a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc index 3996a93..333fc6a 100644 --- a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc +++ b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc
@@ -539,8 +539,7 @@ bool must_create_baselines = false; for (auto& grid_item : sizing_node.grid_items) { - must_create_baselines |= - grid_item.IsBaselineSpecifiedForDirection(track_direction); + must_create_baselines |= grid_item.IsBaselineSpecified(track_direction); auto& range_indices = grid_item.RangeIndices(track_direction); range_builder.EnsureTrackCoverage(grid_item.StartLine(track_direction), @@ -1000,6 +999,28 @@ return is_for_columns ? kForColumns : kForRows; } +LayoutUnit GetExtraMarginForBaseline( + const NGBoxStrut& margins, + const NGSubgriddedItemData& subgridded_item, + GridTrackSizingDirection track_direction, + WritingMode writing_mode) { + const auto& track_collection = (track_direction == kForColumns) + ? subgridded_item.Columns(writing_mode) + : subgridded_item.Rows(writing_mode); + const auto& [begin_set_index, end_set_index] = + subgridded_item->SetIndices(track_collection.Direction()); + + const LayoutUnit extra_margin = + (subgridded_item->BaselineGroup(track_direction) == BaselineGroup::kMajor) + ? track_collection.StartExtraMargin(begin_set_index) + : track_collection.EndExtraMargin(end_set_index); + + return extra_margin + + (subgridded_item->IsLastBaselineSpecified(track_direction) + ? margins.block_end + : margins.block_start); +} + } // namespace LayoutUnit NGGridLayoutAlgorithm::GetLogicalBaseline( @@ -1063,13 +1084,14 @@ if (track_baseline == LayoutUnit::Min()) return; - const auto item_margins = + const LayoutUnit extra_margin = GetExtraMarginForBaseline( ComputeMarginsFor(space, item_style, - grid_item->BaselineWritingDirection(track_direction)); + grid_item->BaselineWritingDirection(track_direction)), + subgridded_item, track_direction, writing_mode); - // Determine the delta between the baselines; subtract out the start margin - // so it doesn't get added a second time at the end of this method. - baseline_shim = track_baseline - baseline - item_margins.block_start; + // Determine the delta between the baselines; subtract out the margin so it + // doesn't get added a second time at the end of this method. + baseline_shim = track_baseline - baseline - extra_margin; }; auto SubgridContributionSize = [&](bool is_min_content) -> LayoutUnit { @@ -1115,11 +1137,11 @@ const auto content_size = is_min_content ? result.sizes.min_size : result.sizes.max_size; - if (grid_item->IsBaselineAlignedForDirection(track_direction)) { + if (grid_item->IsBaselineAligned(track_direction)) { CalculateBaselineShim(GetSynthesizedLogicalBaseline( content_size, grid_item->BaselineWritingDirection(track_direction).IsFlippedLines(), - grid_item->IsLastBaselineSpecifiedForDirection(track_direction))); + grid_item->IsLastBaselineSpecified(track_direction))); } return content_size + baseline_shim; }; @@ -1168,10 +1190,10 @@ grid_item->BaselineWritingDirection(track_direction), To<NGPhysicalBoxFragment>(result->PhysicalFragment())); - if (grid_item->IsBaselineAlignedForDirection(track_direction)) { + if (grid_item->IsBaselineAligned(track_direction)) { CalculateBaselineShim(GetLogicalBaseline( baseline_fragment, - grid_item->IsLastBaselineSpecifiedForDirection(track_direction))); + grid_item->IsLastBaselineSpecified(track_direction))); } return baseline_fragment.BlockSize() + baseline_shim; }; @@ -1495,11 +1517,11 @@ } void NGGridLayoutAlgorithm::ComputeGridItemBaselines( + const NGGridLayoutSubtree& layout_subtree, const NGGridSizingSubtree& sizing_subtree, GridTrackSizingDirection track_direction, SizingConstraint sizing_constraint) const { auto& sizing_data = sizing_subtree.SubtreeRootData(); - auto& track_collection = sizing_data.layout_data.SizingCollection(track_direction); @@ -1507,16 +1529,34 @@ return; } + const auto writing_mode = ConstraintSpace().GetWritingMode(); + track_collection.ResetBaselines(); + + auto next_subgrid_subtree = layout_subtree.FirstChild(); for (auto& grid_item : sizing_data.grid_items) { - if (!grid_item.IsBaselineSpecifiedForDirection(track_direction) || + if (!grid_item.IsBaselineSpecified(track_direction) || !grid_item.IsConsideredForSizing(track_direction)) { continue; } - LogicalRect unused_grid_area; + NGGridLayoutSubtree subgrid_layout_subtree; + if (grid_item.IsSubgrid()) { + DCHECK(next_subgrid_subtree); + subgrid_layout_subtree = next_subgrid_subtree; + next_subgrid_subtree = next_subgrid_subtree.NextSibling(); + } + + const auto subgridded_item = + grid_item.is_subgridded_to_parent_grid + ? sizing_subtree.LookupSubgriddedItemData(grid_item) + : NGSubgriddedItemData(grid_item, sizing_subtree.LayoutData(), + writing_mode); + + LogicalRect unused_containing_grid_area; const auto space = CreateConstraintSpaceForLayout( - grid_item, sizing_data.layout_data, &unused_grid_area); + *subgridded_item, subgridded_item.ParentLayoutData(), + &unused_containing_grid_area, std::move(subgrid_layout_subtree)); // Skip this item if we aren't able to resolve our inline size. const auto& item_style = grid_item.node.Style(); @@ -1539,27 +1579,29 @@ !baseline_fragment.FirstBaseline().has_value(); grid_item.SetAlignmentFallback(track_direction, has_synthesized_baseline); - if (!grid_item.IsBaselineAlignedForDirection(track_direction)) + if (!grid_item.IsBaselineAligned(track_direction)) { continue; + } - const auto margins = - ComputeMarginsFor(space, item_style, baseline_writing_direction); + const LayoutUnit extra_margin = GetExtraMarginForBaseline( + ComputeMarginsFor(space, item_style, baseline_writing_direction), + subgridded_item, track_direction, writing_mode); + const bool is_last_baseline = - grid_item.IsLastBaselineSpecifiedForDirection(track_direction); + grid_item.IsLastBaselineSpecified(track_direction); const LayoutUnit baseline = - (is_last_baseline ? margins.block_end : margins.block_start) + - GetLogicalBaseline(baseline_fragment, is_last_baseline); + extra_margin + GetLogicalBaseline(baseline_fragment, is_last_baseline); // "If a box spans multiple shared alignment contexts, then it participates // in first/last baseline alignment within its start-most/end-most shared // alignment context along that axis" // https://www.w3.org/TR/css-align-3/#baseline-sharing-group + const auto& [begin_set_index, end_set_index] = + grid_item.SetIndices(track_direction); if (grid_item.BaselineGroup(track_direction) == BaselineGroup::kMajor) { - track_collection.SetMajorBaseline( - grid_item.SetIndices(track_direction).begin, baseline); + track_collection.SetMajorBaseline(begin_set_index, baseline); } else { - track_collection.SetMinorBaseline( - grid_item.SetIndices(track_direction).end - 1, baseline); + track_collection.SetMinorBaseline(end_set_index - 1, baseline); } } } @@ -1764,9 +1806,6 @@ : grid_available_size_.block_size, GutterSize(track_direction)); - // Cache baselines, as these contributions can influence track sizing - ComputeGridItemBaselines(sizing_subtree, track_direction, sizing_constraint); - // 2. Resolve intrinsic track sizing functions to absolute lengths. if (track_collection.HasIntrinsicTrack()) { ResolveIntrinsicTrackSizes(sizing_subtree, track_direction, @@ -1869,6 +1908,10 @@ GridTrackSizingDirection track_direction, SizingConstraint sizing_constraint, bool* opt_needs_additional_pass) const { + ComputeBaselineAlignment(NGGridLayoutSubtree(sizing_tree.FinalizeTree()), + NGGridSizingSubtree(sizing_tree), + /* opt_subgrid_data */ kNoSubgriddedItemData, + track_direction, sizing_constraint); CompleteTrackSizingAlgorithm(NGGridSizingSubtree(sizing_tree), /* opt_subgrid_data */ kNoSubgriddedItemData, track_direction, sizing_constraint, @@ -1876,22 +1919,35 @@ } void NGGridLayoutAlgorithm::ComputeBaselineAlignment( + const NGGridLayoutSubtree& layout_subtree, const NGGridSizingSubtree& sizing_subtree, const NGSubgriddedItemData& opt_subgrid_data, const absl::optional<GridTrackSizingDirection>& opt_track_direction, SizingConstraint sizing_constraint) const { DCHECK(sizing_subtree); - auto& sizing_node = sizing_subtree.SubtreeRootData(); + auto& layout_data = sizing_subtree.LayoutData(); auto ComputeOrRecreateBaselines = [&](GridTrackSizingDirection track_direction) { - if (sizing_node.layout_data.HasSubgriddedAxis(track_direction)) { - // TODO(ikilpatrick): Recreate the subgrid track collection. + if (layout_data.HasSubgriddedAxis(track_direction)) { DCHECK(opt_subgrid_data.IsSubgrid()); + // Recreate the subgrid track collection if there are baselines which + // need to be inherited. + const bool is_for_columns_in_parent = + opt_subgrid_data->is_parallel_with_root_grid + ? track_direction == kForColumns + : track_direction == kForRows; + const auto& parent_track_collection = is_for_columns_in_parent + ? opt_subgrid_data.Columns() + : opt_subgrid_data.Rows(); + if (parent_track_collection.HasBaselines()) { + layout_data.SetTrackCollection(CreateSubgridTrackCollection( + opt_subgrid_data, track_direction)); + } } else { - ComputeGridItemBaselines(sizing_subtree, track_direction, - sizing_constraint); + ComputeGridItemBaselines(layout_subtree, sizing_subtree, + track_direction, sizing_constraint); } }; @@ -1902,21 +1958,25 @@ ComputeOrRecreateBaselines(kForRows); } + auto next_layout_subtree = layout_subtree.FirstChild(); ForEachSubgrid(sizing_subtree, [&](const NGGridLayoutAlgorithm& subgrid_algorithm, const NGGridSizingSubtree& subgrid_subtree, const NGSubgriddedItemData& subgrid_data) { + DCHECK(next_layout_subtree); subgrid_algorithm.ComputeBaselineAlignment( - subgrid_subtree, subgrid_data, + next_layout_subtree, subgrid_subtree, subgrid_data, RelativeDirectionFilterInSubgrid(opt_track_direction, *subgrid_data), sizing_constraint); + next_layout_subtree = next_layout_subtree.NextSibling(); }); } void NGGridLayoutAlgorithm::CompleteFinalBaselineAlignment( const NGGridSizingTree& sizing_tree) const { - ComputeBaselineAlignment(NGGridSizingSubtree(sizing_tree), + ComputeBaselineAlignment(NGGridLayoutSubtree(sizing_tree.FinalizeTree()), + NGGridSizingSubtree(sizing_tree), /* opt_subgrid_data */ kNoSubgriddedItemData, /* opt_track_direction */ absl::nullopt, SizingConstraint::kLayout); @@ -3434,8 +3494,9 @@ auto BaselineOffset = [&](GridTrackSizingDirection track_direction, LayoutUnit size) -> LayoutUnit { - if (!grid_item.IsBaselineAlignedForDirection(track_direction)) + if (!grid_item.IsBaselineAligned(track_direction)) { return LayoutUnit(); + } NGBoxFragment baseline_fragment( grid_item.BaselineWritingDirection(track_direction), @@ -3446,7 +3507,7 @@ Baseline(layout_data, grid_item, track_direction) - GetLogicalBaseline( baseline_fragment, - grid_item.IsLastBaselineSpecifiedForDirection(track_direction)); + grid_item.IsLastBaselineSpecified(track_direction)); if (grid_item.BaselineGroup(track_direction) == BaselineGroup::kMajor) return baseline_delta;
diff --git a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.h b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.h index 65e11391..73cdf2c 100644 --- a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.h +++ b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.h
@@ -114,7 +114,8 @@ // Determines the major/minor alignment baselines for each row/column based on // each item in |grid_items|, and stores the results in |track_collection|. - void ComputeGridItemBaselines(const NGGridSizingSubtree& sizing_subtree, + void ComputeGridItemBaselines(const NGGridLayoutSubtree& layout_subtree, + const NGGridSizingSubtree& sizing_subtree, GridTrackSizingDirection track_direction, SizingConstraint sizing_constraint) const; @@ -161,6 +162,7 @@ // Performs the final baseline alignment pass of a grid sizing subtree. void ComputeBaselineAlignment( + const NGGridLayoutSubtree& layout_subtree, const NGGridSizingSubtree& sizing_subtree, const NGSubgriddedItemData& opt_subgrid_data, const absl::optional<GridTrackSizingDirection>& opt_track_direction,
diff --git a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_sizing_tree.h b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_sizing_tree.h index 6c6f3f6..b438887 100644 --- a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_sizing_tree.h +++ b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_sizing_tree.h
@@ -64,6 +64,11 @@ : parent_layout_data_->Columns(); } + const NGGridLayoutData& ParentLayoutData() const { + DCHECK(parent_layout_data_); + return *parent_layout_data_; + } + private: const GridItemData* item_data_in_parent_{nullptr}; const NGGridLayoutData* parent_layout_data_{nullptr};
diff --git a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_track_collection.cc b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_track_collection.cc index ff92069..9a81b24 100644 --- a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_track_collection.cc +++ b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_track_collection.cc
@@ -673,26 +673,27 @@ // Copy the sets geometry and adjust its offsets to accommodate the subgrid's // margin, border, scrollbar, padding, and gutter size. + const auto subgrid_gutter_size_delta = subgrid_gutter_size - gutter_size_; + + const bool is_for_columns = subgrid_track_direction == kForColumns; + const auto subgrid_margin_start = + is_for_columns ? subgrid_margin.inline_start : subgrid_margin.block_start; + + const auto subgrid_border_scrollbar_padding_start = + is_for_columns ? subgrid_border_scrollbar_padding.inline_start + : subgrid_border_scrollbar_padding.block_start; + + const auto subgrid_margin_border_scrollbar_padding_start = + subgrid_margin_start + subgrid_border_scrollbar_padding_start; + const auto subgrid_margin_border_scrollbar_padding_end = + is_for_columns ? subgrid_margin.inline_end + + subgrid_border_scrollbar_padding.inline_end + : subgrid_margin.block_end + + subgrid_border_scrollbar_padding.block_end; + + // Accumulate the extra margin from the spanned sets in the parent track + // collection and this subgrid's margins and gutter size delta. { - const auto subgrid_gutter_size_delta = subgrid_gutter_size - gutter_size_; - - const bool is_for_columns = subgrid_track_direction == kForColumns; - const auto subgrid_margin_start = is_for_columns - ? subgrid_margin.inline_start - : subgrid_margin.block_start; - - const auto subgrid_border_scrollbar_padding_start = - is_for_columns ? subgrid_border_scrollbar_padding.inline_start - : subgrid_border_scrollbar_padding.block_start; - - const auto subgrid_margin_border_scrollbar_padding_end = - is_for_columns ? subgrid_margin.inline_end + - subgrid_border_scrollbar_padding.inline_end - : subgrid_margin.block_end + - subgrid_border_scrollbar_padding.block_end; - - // Accumulate the extra margin from the spanned sets in the parent track - // collection and this subgrid's margins and gutter size delta. subgrid_track_collection.accumulated_gutter_size_delta_ = subgrid_gutter_size_delta + accumulated_gutter_size_delta_; @@ -703,7 +704,7 @@ // Opposite direction subgrids adjust extra margin from the opposite side. subgrid_track_collection.accumulated_start_extra_margin_ = - subgrid_margin_start + subgrid_border_scrollbar_padding_start + + subgrid_margin_border_scrollbar_padding_start + (is_opposite_direction_in_root_grid ? EndExtraMargin(end_set_index) : StartExtraMargin(begin_set_index)); @@ -801,12 +802,28 @@ subgrid_baselines.major.ReserveInitialCapacity(set_span_size); subgrid_baselines.minor.ReserveInitialCapacity(set_span_size); + // Adjust the baselines to accommodate the subgrid extra margins. for (wtf_size_t i = 0; i < set_span_size; ++i) { + LayoutUnit major_adjust = + (i == 0) ? subgrid_margin_border_scrollbar_padding_start + : subgrid_gutter_size_delta / 2; + LayoutUnit minor_adjust = + (i == set_span_size - 1) ? subgrid_margin_border_scrollbar_padding_end + : subgrid_gutter_size_delta / 2; + if (is_opposite_direction_in_root_grid) { + std::swap(major_adjust, minor_adjust); + } const wtf_size_t current_index = is_opposite_direction_in_root_grid - ? end_set_index - i + 1 + ? end_set_index - i - 1 : begin_set_index + i; - subgrid_baselines.major.emplace_back(baselines_->major[current_index]); - subgrid_baselines.minor.emplace_back(baselines_->minor[current_index]); + subgrid_baselines.major.emplace_back(baselines_->major[current_index] - + major_adjust); + subgrid_baselines.minor.emplace_back(baselines_->minor[current_index] - + minor_adjust); + } + + if (is_opposite_direction_in_root_grid) { + std::swap(subgrid_baselines.major, subgrid_baselines.minor); } subgrid_track_collection.baselines_ = std::move(subgrid_baselines);
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.cc index 79e1067..60a6d14 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.cc +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.cc
@@ -289,6 +289,24 @@ } template <typename OffsetMappingBuilder> +inline void +NGInlineItemsBuilderTemplate<OffsetMappingBuilder>::DidAppendForcedBreak() { + // Bisecting available widths can't handle multiple logical paragraphs, so + // forced break should disable it. See `NGParagraphLineBreaker`. + is_bisect_line_break_disabled_ = true; +} + +template <typename OffsetMappingBuilder> +inline void +NGInlineItemsBuilderTemplate<OffsetMappingBuilder>::DidAppendTextReusing( + const NGInlineItem& item) { + is_block_level_ &= item.IsBlockLevel(); + if (item.IsForcedLineBreak()) { + DidAppendForcedBreak(); + } +} + +template <typename OffsetMappingBuilder> bool NGInlineItemsBuilderTemplate<OffsetMappingBuilder>::AppendTextReusing( const NGInlineNodeData& original_data, LayoutText* layout_text) { @@ -435,7 +453,7 @@ // itself may be reused. if (item.StartOffset() == start) { items_->push_back(item); - is_block_level_ &= item.IsBlockLevel(); + DidAppendTextReusing(item); continue; } @@ -465,7 +483,7 @@ #endif items_->push_back(adjusted_item); - is_block_level_ &= adjusted_item.IsBlockLevel(); + DidAppendTextReusing(adjusted_item); } return true; } @@ -956,9 +974,7 @@ } } - // Bisecting available widths can't handle multiple logical paragraphs, so - // forced break should disable it. See `NGParagraphLineBreaker`. - is_bisect_line_break_disabled_ = true; + DidAppendForcedBreak(); } template <typename OffsetMappingBuilder>
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.h b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.h index 713b038..09b4c52 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.h +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.h
@@ -224,6 +224,9 @@ void ExitAndEnterSvgTextChunk(LayoutText& layout_text); void EnterSvgTextChunk(const ComputedStyle* style); + void DidAppendTextReusing(const NGInlineItem& item); + void DidAppendForcedBreak(); + void RemoveTrailingCollapsibleSpaceIfExists(); void RemoveTrailingCollapsibleSpace(NGInlineItem*);
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.h b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.h index 3525b7a1..a9619e6 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.h +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.h
@@ -61,6 +61,8 @@ } private: + friend class NGLineWidthsTest; + unsigned PositionLeadingFloats(NGExclusionSpace*, NGPositionedFloatVector*); NGPositionedFloat PositionFloat(LayoutUnit origin_block_bfc_offset, LayoutObject* floating_object,
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_line_widths.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_line_widths.cc new file mode 100644 index 0000000..78b3cae0 --- /dev/null +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_line_widths.cc
@@ -0,0 +1,88 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/renderer/core/layout/ng/inline/ng_line_widths.h" + +#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.h" +#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h" +#include "third_party/blink/renderer/platform/fonts/shaping/shape_result.h" + +namespace blink { + +bool NGLineWidths::Set(const NGInlineNode& node, + base::span<const NGLayoutOpportunity> opportunities) { + // Set the default width if no exclusions. + DCHECK_GE(opportunities.size(), 1u); + const NGLayoutOpportunity& first_opportunity = opportunities.front(); + if (opportunities.size() == 1) { + DCHECK(!first_opportunity.HasShapeExclusions()); + default_width_ = first_opportunity.rect.InlineSize(); + DCHECK(!num_excluded_lines_); + return true; + } + + // This class supports only single simple exclusion. + if (opportunities.size() > 2 || first_opportunity.HasShapeExclusions()) { + return false; + } + + // Check if all lines have the same line heights. + const ComputedStyle& block_style = node.Style(); + const Font& block_font = block_style.GetFont(); + const SimpleFontData* primary_font = block_font.PrimaryFont(); + DCHECK(primary_font); + const NGInlineItemsData& items_data = node.ItemsData(/*is_first_line*/ false); + // `::first-line` is not supported. + DCHECK_EQ(&items_data, &node.ItemsData(true)); + const HeapVector<NGInlineItem>& items = items_data.items; + for (const NGInlineItem& item : items) { + switch (item.Type()) { + case NGInlineItem::kText: { + const ShapeResult* shape_result = item.TextShapeResult(); + DCHECK(shape_result); + if (shape_result->PrimaryFont() != primary_font || + shape_result->HasFallbackFonts()) { + return false; + } + break; + } + case NGInlineItem::kOpenTag: { + DCHECK(item.Style()); + const ComputedStyle& style = *item.Style(); + if (style.GetFont().PrimaryFont() != primary_font || + style.VerticalAlign() != EVerticalAlign::kBaseline) { + return false; + } + break; + } + default: + break; + } + } + + // All lines have the same line height. Compute the line height. + const FontBaseline baseline_type = block_style.GetFontBaseline(); + NGInlineBoxState box; + box.ComputeTextMetrics(block_style, block_font, baseline_type); + const LayoutUnit line_height = box.metrics.LineHeight(); + if (line_height <= LayoutUnit()) { + return false; + } + + // Compute the number of lines that have the exclusion. + const NGLayoutOpportunity& last_opportunity = opportunities.back(); + DCHECK(!last_opportunity.HasShapeExclusions()); + default_width_ = last_opportunity.rect.InlineSize(); + const LayoutUnit exclusion_block_size = + last_opportunity.rect.BlockStartOffset() - + first_opportunity.rect.BlockStartOffset(); + DCHECK_GT(exclusion_block_size, LayoutUnit()); + const int num_excluded_lines = (exclusion_block_size / line_height).Ceil(); + DCHECK_GT(num_excluded_lines, 0); + num_excluded_lines_ = num_excluded_lines; + excluded_width_ = first_opportunity.rect.InlineSize(); + return true; +} + +} // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_line_widths.h b/third_party/blink/renderer/core/layout/ng/inline/ng_line_widths.h new file mode 100644 index 0000000..0363d8c --- /dev/null +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_line_widths.h
@@ -0,0 +1,48 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_LINE_WIDTHS_H_ +#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_LINE_WIDTHS_H_ + +#include "base/containers/span.h" +#include "third_party/blink/renderer/core/core_export.h" +#include "third_party/blink/renderer/core/layout/ng/exclusions/ng_layout_opportunity.h" +#include "third_party/blink/renderer/platform/geometry/layout_unit.h" +#include "third_party/blink/renderer/platform/wtf/forward.h" + +namespace blink { + +class NGInlineNode; + +// +// This class computes the line width of each line for _simple_ nodes without +// actually laying them out. +// +class CORE_EXPORT NGLineWidths { + STACK_ALLOCATED(); + + public: + // Returns the width of a line. The `index` is 0-based line index. + LayoutUnit operator[](wtf_size_t index) const; + + // Compute the line widths. Returns `false` if the `node` is not _simple_. + bool Set(const NGInlineNode& node, + base::span<const NGLayoutOpportunity> opportunities); + + private: + LayoutUnit default_width_; + LayoutUnit excluded_width_; + wtf_size_t num_excluded_lines_ = 0; +}; + +inline LayoutUnit NGLineWidths::operator[](wtf_size_t index) const { + if (UNLIKELY(index < num_excluded_lines_)) { + return excluded_width_; + } + return default_width_; +} + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_LINE_WIDTHS_H_
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_line_widths_test.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_line_widths_test.cc new file mode 100644 index 0000000..77ef6e5 --- /dev/null +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_line_widths_test.cc
@@ -0,0 +1,181 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/renderer/core/layout/ng/inline/ng_line_widths.h" + +#include "testing/gmock/include/gmock/gmock.h" +#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_child_layout_context.h" +#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.h" +#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h" +#include "third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h" +#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h" +#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h" + +namespace blink { + +namespace { + +LayoutUnit FragmentWidth(const NGInlineNode& node) { + const NGPhysicalBoxFragment* fragment = + node.GetLayoutBox()->GetPhysicalFragment(0); + return fragment->Size().width; +} + +} // namespace + +class NGLineWidthsTest : public RenderingTest { + public: + absl::optional<NGLineWidths> ComputeLineWidths(NGInlineNode node) { + const LayoutUnit width = FragmentWidth(node); + NGConstraintSpace space = ConstraintSpaceForAvailableSize(width); + const ComputedStyle& style = node.Style(); + NGBoxFragmentBuilder container_builder(node, &style, space, + style.GetWritingDirection()); + NGSimpleInlineChildLayoutContext context(node, &container_builder); + NGInlineLayoutAlgorithm algorithm(node, space, /*break_token*/ nullptr, + /*column_spanner_path*/ nullptr, + &context); + NGExclusionSpace exclusion_space(space.ExclusionSpace()); + NGPositionedFloatVector leading_floats; + algorithm.PositionLeadingFloats(&exclusion_space, &leading_floats); + const LayoutOpportunityVector& opportunities = + exclusion_space.AllLayoutOpportunities( + {space.BfcOffset().line_offset, /*bfc_block_offset*/ LayoutUnit()}, + space.AvailableSize().inline_size); + NGLineWidths line_width; + if (line_width.Set(node, opportunities)) { + return line_width; + } + return absl::nullopt; + } + + protected: +}; + +struct LineWidthsData { + std::vector<int> widths; + const char* html; +} line_widths_data[] = { + // It should be computable if no floats. + {{100, 100}, R"HTML( + <div id="target">0123 5678</div> + )HTML"}, + {{100, 100}, R"HTML( + <div id="target">0123 <b>5</b>678</div> + )HTML"}, + // Single left/right float should be computable. + {{70, 100}, R"HTML( + <div id="target"> + <div class="left"></div> + 0123 5678 + </div> + )HTML"}, + {{70, 100}, R"HTML( + <div id="target"> + <div class="right"></div> + 0123 5678 + </div> + )HTML"}, + {{70, 100}, R"HTML( + <div id="target" style="line-height: 15px"> + <div class="left" style="height: 11px"></div> + 0123 5678 + </div> + )HTML"}, + // The 2nd line is also narrow if the float is taller than one line. + {{70, 70, 100}, R"HTML( + <div id="target"> + <div class="left" style="height: 11px"></div> + 0123 5678 + </div> + )HTML"}, + {{70, 70, 100}, R"HTML( + <div id="target" style="line-height: 15px"> + <div class="left" style="height: 16px"></div> + 0123 5678 + </div> + )HTML"}, + // Multiple floats are computable if they produce single exclusion. + {{40, 100}, R"HTML( + <div id="target"> + <div class="left"></div> + <div class="left"></div> + 0123 5678 + </div> + )HTML"}, + // ...but not computable if they produce multiple exclusions. + {{}, R"HTML( + <div id="target"> + <div class="left" style="height: 20px"></div> + <div class="left"></div> + 0123 5678 + </div> + )HTML"}, + // Different fonts/`vertical-align` are not computable. + {{}, R"HTML( + <div id="target"> + <div class="left"></div> + 0123 5678 <b>0123</b> 5678 + </div> + )HTML"}, + {{}, R"HTML( + <div id="target"> + <div class="left"></div> + 0123 5678 <span style="vertical-align: top">0</span>123 5678 + </div> + )HTML"}, + // Fallback fonts are also not computable. + {{}, R"HTML( + <div id="target"> + <div class="left"></div> + 0123 5678 \u3040 + </div> + )HTML"}, +}; +class NGLineWidthsDataTest + : public NGLineWidthsTest, + public testing::WithParamInterface<LineWidthsData> {}; +INSTANTIATE_TEST_SUITE_P(NGLineWidthsTest, + NGLineWidthsDataTest, + testing::ValuesIn(line_widths_data)); + +TEST_P(NGLineWidthsDataTest, Data) { + const auto& data = GetParam(); + LoadAhem(); + SetBodyInnerHTML(String::Format(R"HTML( + <!DOCTYPE html> + <style> + #target { + font-family: Ahem; + font-size: 10px; + width: 100px; + } + .left { + float: left; + width: 30px; + height: 10px; + } + .right { + float: right; + width: 30px; + height: 10px; + } + </style> + %s + )HTML", + data.html)); + const NGInlineNode target = GetInlineNodeByElementId("target"); + const absl::optional<NGLineWidths> line_widths = ComputeLineWidths(target); + if (!line_widths) { + EXPECT_EQ(data.widths.size(), 0u); + return; + } + std::vector<int> actual_widths; + for (wtf_size_t i = 0; i < data.widths.size(); ++i) { + actual_widths.push_back((*line_widths)[i].ToInt()); + } + EXPECT_THAT(actual_widths, data.widths); +} + +} // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_paragraph_line_breaker_test.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_paragraph_line_breaker_test.cc index e3e2c90b..7d98347 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_paragraph_line_breaker_test.cc +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_paragraph_line_breaker_test.cc
@@ -116,6 +116,29 @@ EXPECT_FALSE(AttemptParagraphBalancing(target)); } +TEST_F(NGParagraphLineBreakerTest, IsDisabledByForcedBreakReusing) { + SetBodyInnerHTML(R"HTML( + <!DOCTYPE html> + <style> + #target { + font-size: 10px; + width: 10ch; + white-space: pre; + } + </style> + <div id="target">1234 6789 +1234 + </div> + )HTML"); + const NGInlineNode target = GetInlineNodeByElementId("target"); + Element* target_node = To<Element>(target.GetDOMNode()); + target_node->AppendChild(GetDocument().createTextNode(" 6789")); + UpdateAllLifecyclePhasesForTest(); + EXPECT_TRUE(target.IsBisectLineBreakDisabled()); + EXPECT_FALSE(target.IsScoreLineBreakDisabled()); + EXPECT_FALSE(AttemptParagraphBalancing(target)); +} + TEST_F(NGParagraphLineBreakerTest, IsDisabledByInitialLetter) { SetBodyInnerHTML(R"HTML( <!DOCTYPE html>
diff --git a/third_party/blink/renderer/modules/BUILD.gn b/third_party/blink/renderer/modules/BUILD.gn index 40d530b..50f07a2 100644 --- a/third_party/blink/renderer/modules/BUILD.gn +++ b/third_party/blink/renderer/modules/BUILD.gn
@@ -606,6 +606,7 @@ "service_worker/service_worker_container_test.cc", "service_worker/service_worker_event_queue_test.cc", "service_worker/service_worker_installed_scripts_manager_test.cc", + "service_worker/service_worker_router_type_converter_test.cc", "service_worker/thread_safe_script_container_test.cc", "service_worker/web_embedded_worker_impl_test.cc", "service_worker/web_service_worker_fetch_context_impl_test.cc",
diff --git a/third_party/blink/renderer/modules/accessibility/DEPS b/third_party/blink/renderer/modules/accessibility/DEPS index 0deb9d661..bb2920e0 100644 --- a/third_party/blink/renderer/modules/accessibility/DEPS +++ b/third_party/blink/renderer/modules/accessibility/DEPS
@@ -6,8 +6,6 @@ "+third_party/blink/renderer/modules/media_controls", "+third_party/blink/renderer/modules/modules_export.h", "+third_party/blink/renderer/modules/permissions", - "+ui/accessibility/accessibility_features.h", - "+ui/accessibility/accessibility_switches.h", "+ui/accessibility/ax_action_data.h", "+ui/accessibility/ax_common.h", "+ui/accessibility/ax_enum_util.h",
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc index 6c763880..ca581cd 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc +++ b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc
@@ -1638,6 +1638,13 @@ if (node->IsPseudoElement()) { DeferTreeUpdate(&AXObjectCacheImpl::EnsureMarkDirtyWithCleanLayout, node); } + if (layout_object->Style() && + !layout_object->Style()->IsContentVisibilityVisible()) { + // If a content-visibility: auto/hidden node is removed, remove the entire + // subtree because any AXObject descendants are now invalid, and there + // will not be any other signals to hook for invalidation or removal. + RemoveSubtreeWhenSafe(node); + } if (IsA<HTMLImageElement>(node)) { // If an image is removed, ensure its entire subtree is deleted as there // may have been children supplied via a map. @@ -2183,6 +2190,17 @@ return; } + // If the node is the root of a display locked subtree, and it already had an + // AXObject, its entire subtree needs to be invalidated. Now that it has + // layout, its subtree will be rebuilt using AXLayoutObject rather than + // AXNodeObject. + if (node->GetLayoutObject() && node->GetLayoutObject()->Style() && + !node->GetLayoutObject()->Style()->IsContentVisibilityVisible() && + node_object_mapping_.Contains(node)) { + RemoveSubtreeWithFlatTraversal(node, /* remove_root */ false, + /* notify_parent */ false); + } + DeferTreeUpdate( &AXObjectCacheImpl::UpdateCacheAfterNodeIsAttachedWithCleanLayout, node); }
diff --git a/third_party/blink/renderer/modules/accessibility/blink_ax_tree_source.cc b/third_party/blink/renderer/modules/accessibility/blink_ax_tree_source.cc index fb7950f..c58f2fe5 100644 --- a/third_party/blink/renderer/modules/accessibility/blink_ax_tree_source.cc +++ b/third_party/blink/renderer/modules/accessibility/blink_ax_tree_source.cc
@@ -19,8 +19,6 @@ #include "third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h" #include "third_party/blink/renderer/modules/accessibility/ax_selection.h" #include "third_party/blink/renderer/platform/heap/collection_support/heap_deque.h" -#include "ui/accessibility/accessibility_features.h" -#include "ui/accessibility/accessibility_switches.h" #include "ui/accessibility/ax_common.h" #include "ui/accessibility/ax_enum_util.h" #include "ui/accessibility/ax_role_properties.h"
diff --git a/third_party/blink/renderer/modules/remote_objects/remote_object.cc b/third_party/blink/renderer/modules/remote_objects/remote_object.cc index 0993ec9..54160a8 100644 --- a/third_party/blink/renderer/modules/remote_objects/remote_object.cc +++ b/third_party/blink/renderer/modules/remote_objects/remote_object.cc
@@ -6,7 +6,6 @@ #include <tuple> -#include "base/metrics/histogram_macros.h" #include "base/numerics/safe_conversions.h" #include "gin/converter.h" #include "third_party/blink/public/web/blink.h" @@ -19,21 +18,6 @@ namespace { -// Used to specify what kind of error was encountered during Java bridge method -// invocation. -// Note: these values are logged to UMA. Entries should not be renumbered and -// numeric values should never be reused. Please keep in sync with -// "JavaJsBridgeMethodInvocationError" in -// src/tools/metrics/histograms/enums.xml. -enum class JavaJsBridgeMethodInvocationError { - kAsConstructorDisallowed, - kNonexistentMethod, - kOnNonInjectedObjectDisallowed, - kErrorMessage, - // Magic constant used by the histogram macros. - kMaxValue = kErrorMessage, -}; - const char kMethodInvocationAsConstructorDisallowed[] = "Java bridge method can't be invoked as a constructor"; const char kMethodInvocationNonexistentMethod[] = @@ -336,9 +320,6 @@ // This is not a constructor. Throw and return. isolate->ThrowException(v8::Exception::Error( V8String(isolate, kMethodInvocationAsConstructorDisallowed))); - UMA_HISTOGRAM_ENUMERATION( - "Blink.JavaJsBridge.MethodInvocationError", - JavaJsBridgeMethodInvocationError::kAsConstructorDisallowed); return; } @@ -347,9 +328,6 @@ // Someone messed with the |this| pointer. Throw and return. isolate->ThrowException(v8::Exception::Error( V8String(isolate, kMethodInvocationOnNonInjectedObjectDisallowed))); - UMA_HISTOGRAM_ENUMERATION( - "Blink.JavaJsBridge.MethodInvocationError", - JavaJsBridgeMethodInvocationError::kOnNonInjectedObjectDisallowed); return; } @@ -368,9 +346,6 @@ if (cached_method->IsUndefined()) { isolate->ThrowException(v8::Exception::Error( V8String(isolate, kMethodInvocationNonexistentMethod))); - UMA_HISTOGRAM_ENUMERATION( - "Blink.JavaJsBridge.MethodInvocationError", - JavaJsBridgeMethodInvocationError::kNonexistentMethod); return; } @@ -394,8 +369,6 @@ String message = String::Format("%s : ", kMethodInvocationErrorMessage) + RemoteInvocationErrorToString(result->error); isolate->ThrowException(v8::Exception::Error(V8String(isolate, message))); - UMA_HISTOGRAM_ENUMERATION("Blink.JavaJsBridge.MethodInvocationError", - JavaJsBridgeMethodInvocationError::kErrorMessage); return; }
diff --git a/third_party/blink/renderer/modules/service_worker/BUILD.gn b/third_party/blink/renderer/modules/service_worker/BUILD.gn index f953086..0052a031 100644 --- a/third_party/blink/renderer/modules/service_worker/BUILD.gn +++ b/third_party/blink/renderer/modules/service_worker/BUILD.gn
@@ -52,6 +52,8 @@ "service_worker_module_tree_client.h", "service_worker_registration.cc", "service_worker_registration.h", + "service_worker_router_type_converter.cc", + "service_worker_router_type_converter.h", "service_worker_script_cached_metadata_handler.cc", "service_worker_script_cached_metadata_handler.h", "service_worker_thread.cc",
diff --git a/third_party/blink/renderer/modules/service_worker/DEPS b/third_party/blink/renderer/modules/service_worker/DEPS index e22e4f6..67318e1 100644 --- a/third_party/blink/renderer/modules/service_worker/DEPS +++ b/third_party/blink/renderer/modules/service_worker/DEPS
@@ -10,6 +10,7 @@ "+third_party/blink/renderer/modules/event_target_modules.h", "+third_party/blink/renderer/modules/modules_export.h", "+third_party/blink/renderer/modules/service_worker", + "+third_party/liburlpattern", ] specific_include_rules = {
diff --git a/third_party/blink/renderer/modules/service_worker/OWNERS b/third_party/blink/renderer/modules/service_worker/OWNERS index 970e7ea..01f3934 100644 --- a/third_party/blink/renderer/modules/service_worker/OWNERS +++ b/third_party/blink/renderer/modules/service_worker/OWNERS
@@ -1,2 +1,4 @@ file://content/browser/service_worker/OWNERS +per-file *_type_converter*.*=set noparent +per-file *_type_converter*.*=file://ipc/SECURITY_OWNERS
diff --git a/third_party/blink/renderer/modules/service_worker/install_event.cc b/third_party/blink/renderer/modules/service_worker/install_event.cc index c95d2b6..33fb158 100644 --- a/third_party/blink/renderer/modules/service_worker/install_event.cc +++ b/third_party/blink/renderer/modules/service_worker/install_event.cc
@@ -4,15 +4,40 @@ #include "third_party/blink/renderer/modules/service_worker/install_event.h" +#include "third_party/blink/public/mojom/service_worker/service_worker_router_rule.mojom-blink.h" #include "third_party/blink/public/platform/web_security_origin.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise.h" +#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h" +#include "third_party/blink/renderer/bindings/core/v8/v8_throw_dom_exception.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_union_routerrule_routerrulesequence.h" #include "third_party/blink/renderer/core/execution_context/execution_context.h" +#include "third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h" +#include "third_party/blink/renderer/modules/service_worker/service_worker_router_type_converter.h" +#include "third_party/blink/renderer/platform/bindings/exception_code.h" #include "third_party/blink/renderer/platform/bindings/script_state.h" #include "third_party/blink/renderer/platform/bindings/v8_throw_exception.h" namespace blink { +namespace { + +void DidRegisterRouter(ScriptPromiseResolver* resolver) { + if (!resolver->GetExecutionContext() || + resolver->GetExecutionContext()->IsContextDestroyed()) { + return; + } + resolver->Resolve(); +} + +ScriptPromise ParseErrorPromise(ScriptState* script_state) { + return ScriptPromise::Reject( + script_state, V8ThrowException::CreateTypeError( + script_state->GetIsolate(), + "Failed to parse a rule. Possibly syntax error.")); +} + +} // namespace + InstallEvent* InstallEvent::Create(const AtomicString& type, const ExtendableEventInit* event_init) { return MakeGarbageCollected<InstallEvent>(type, event_init); @@ -45,9 +70,47 @@ ScriptPromise InstallEvent::registerRouter( ScriptState* script_state, const V8UnionRouterRuleOrRouterRuleSequence* v8_rules) { - return ScriptPromise::Reject( - script_state, V8ThrowException::CreateTypeError( - script_state->GetIsolate(), "Not implemented yet")); + ServiceWorkerGlobalScope* global_scope = + To<ServiceWorkerGlobalScope>(ExecutionContext::From(script_state)); + if (!global_scope) { + return ScriptPromise::Reject( + script_state, + V8ThrowDOMException::CreateOrDie(script_state->GetIsolate(), + DOMExceptionCode::kInvalidStateError, + "No ServiceWorkerGlobalScope.")); + } + if (did_register_router_) { + return ScriptPromise::Reject( + script_state, V8ThrowException::CreateTypeError( + script_state->GetIsolate(), + "registerRouter is called multiple times.")); + } + did_register_router_ = true; + + blink::ServiceWorkerRouterRules rules; + if (v8_rules->IsRouterRule()) { + auto r = mojo::ConvertTo<absl::optional<blink::ServiceWorkerRouterRule>>( + v8_rules->GetAsRouterRule()); + if (!r) { + return ParseErrorPromise(script_state); + } + rules.rules.emplace_back(*r); + } else { + CHECK(v8_rules->IsRouterRuleSequence()); + for (const blink::RouterRule* rule : v8_rules->GetAsRouterRuleSequence()) { + auto r = + mojo::ConvertTo<absl::optional<blink::ServiceWorkerRouterRule>>(rule); + if (!r) { + return ParseErrorPromise(script_state); + } + rules.rules.emplace_back(*r); + } + } + + auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state); + global_scope->GetServiceWorkerHost()->RegisterRouter( + rules, WTF::BindOnce(&DidRegisterRouter, WrapPersistent(resolver))); + return resolver->Promise(); } } // namespace blink
diff --git a/third_party/blink/renderer/modules/service_worker/install_event.h b/third_party/blink/renderer/modules/service_worker/install_event.h index ec49479..ee41456 100644 --- a/third_party/blink/renderer/modules/service_worker/install_event.h +++ b/third_party/blink/renderer/modules/service_worker/install_event.h
@@ -40,6 +40,7 @@ protected: const int event_id_; + bool did_register_router_ = false; }; } // namespace blink
diff --git a/third_party/blink/renderer/modules/service_worker/install_event.idl b/third_party/blink/renderer/modules/service_worker/install_event.idl index 5601028e..33146c1 100644 --- a/third_party/blink/renderer/modules/service_worker/install_event.idl +++ b/third_party/blink/renderer/modules/service_worker/install_event.idl
@@ -10,5 +10,5 @@ constructor(DOMString type, optional ExtendableEventInit eventInitDict = {}); // Experimental // https://github.com/yoshisatoyanagisawa/service-worker-static-routing-api - [RuntimeEnabled=ServiceWorkerRouter, CallWith=ScriptState] Promise<undefined> registerRouter((RouterRule or sequence<RouterRule>) rules); + [RuntimeEnabled=ServiceWorkerStaticRouter, CallWith=ScriptState] Promise<undefined> registerRouter((RouterRule or sequence<RouterRule>) rules); };
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_router_type_converter.cc b/third_party/blink/renderer/modules/service_worker/service_worker_router_type_converter.cc new file mode 100644 index 0000000..1342bb7f --- /dev/null +++ b/third_party/blink/renderer/modules/service_worker/service_worker_router_type_converter.cc
@@ -0,0 +1,102 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/renderer/modules/service_worker/service_worker_router_type_converter.h" + +#include "third_party/blink/renderer/bindings/modules/v8/v8_router_condition.h" +#include "third_party/blink/renderer/bindings/modules/v8/v8_router_rule.h" +#include "third_party/blink/renderer/bindings/modules/v8/v8_router_source_enum.h" +#include "third_party/blink/renderer/bindings/modules/v8/v8_router_url_pattern_condition.h" +#include "third_party/blink/renderer/platform/wtf/text/string_utf8_adaptor.h" +#include "third_party/liburlpattern/parse.h" +#include "third_party/liburlpattern/pattern.h" + +namespace { + +absl::optional<blink::ServiceWorkerRouterCondition> +RouterUrlPatternConditionToBlink( + blink::RouterUrlPatternCondition* v8_condition) { + if (!v8_condition) { + // No UrlCondition configured. + return absl::nullopt; + } + if (v8_condition->urlPattern().empty()) { + // No URLPattern configured. + return absl::nullopt; + } + // TODO(crbug.com/1371756): unify the code with manifest_parser.cc + WTF::StringUTF8Adaptor utf8(v8_condition->urlPattern()); + auto parse_result = liburlpattern::Parse( + base::StringPiece(utf8.data(), utf8.size()), + [](base::StringPiece input) { return std::string(input); }); + if (!parse_result.ok()) { + return absl::nullopt; + } + std::vector<liburlpattern::Part> part_list; + for (auto& part : parse_result.value().PartList()) { + // We don't allow custom regex for security reasons as this will be used + // in the browser process. + if (part.type == liburlpattern::PartType::kRegex) { + DLOG(INFO) << "regex URLPattern is not allowed as Router Condition"; + return absl::nullopt; + } + part_list.push_back(std::move(part)); + } + blink::ServiceWorkerRouterCondition condition; + condition.type = + blink::ServiceWorkerRouterCondition::ConditionType::kUrlPattern; + blink::UrlPattern url_pattern; + url_pattern.pathname = std::move(part_list); + condition.url_pattern = std::move(url_pattern); + return condition; +} + +absl::optional<blink::ServiceWorkerRouterSource> RouterSourceEnumToBlink( + blink::V8RouterSourceEnum v8_source_enum) { + if (v8_source_enum != blink::V8RouterSourceEnum::Enum::kNetwork) { + return absl::nullopt; + } + blink::ServiceWorkerRouterSource source; + source.type = blink::ServiceWorkerRouterSource::SourceType::kNetwork; + source.network_source.emplace(); + return source; +} + +} // namespace + +namespace mojo { + +absl::optional<blink::ServiceWorkerRouterRule> +TypeConverter<absl::optional<blink::ServiceWorkerRouterRule>, + blink::RouterRule*>::Convert(const blink::RouterRule* input) { + if (!input) { + return absl::nullopt; + } + + blink::ServiceWorkerRouterRule rule; + absl::optional<blink::ServiceWorkerRouterCondition> condition = + RouterUrlPatternConditionToBlink(input->condition()); + if (!condition) { + return absl::nullopt; + } + absl::optional<blink::ServiceWorkerRouterSource> source = + RouterSourceEnumToBlink(input->source()); + if (!source) { + return absl::nullopt; + } + + // TODO(crbug.com/1371756): support multiple conditions and sources. + // i.e. support full form shown in + // https://github.com/yoshisatoyanagisawa/service-worker-static-routing-api/blob/main/final-form.md + // + // https://github.com/yoshisatoyanagisawa/service-worker-static-routing-api/blob/main/README.md + // explains the first step. It does not cover cases sequence of conditions or + // sources are set. The current IDL has been implemented for this level, but + // the mojo IPC has been implemented to support the final form. + rule.conditions.emplace_back(*condition); + rule.sources.emplace_back(*source); + return rule; +} + +} // namespace mojo
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_router_type_converter.h b/third_party/blink/renderer/modules/service_worker/service_worker_router_type_converter.h new file mode 100644 index 0000000..148aa80 --- /dev/null +++ b/third_party/blink/renderer/modules/service_worker/service_worker_router_type_converter.h
@@ -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. + +#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_SERVICE_WORKER_SERVICE_WORKER_ROUTER_TYPE_CONVERTER_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_SERVICE_WORKER_SERVICE_WORKER_ROUTER_TYPE_CONVERTER_H_ + +#include "mojo/public/cpp/bindings/type_converter.h" +#include "third_party/abseil-cpp/absl/types/optional.h" +#include "third_party/blink/public/mojom/service_worker/service_worker_router_rule.mojom-blink.h" +#include "third_party/blink/renderer/modules/modules_export.h" + +namespace blink { + +class RouterRule; + +} // namespace blink + +namespace mojo { + +template <> +struct MODULES_EXPORT + TypeConverter<absl::optional<blink::ServiceWorkerRouterRule>, + blink::RouterRule*> { + static absl::optional<blink::ServiceWorkerRouterRule> Convert( + const blink::RouterRule* input); +}; + +} // namespace mojo + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_SERVICE_WORKER_SERVICE_WORKER_ROUTER_TYPE_CONVERTER_H_
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_router_type_converter_test.cc b/third_party/blink/renderer/modules/service_worker/service_worker_router_type_converter_test.cc new file mode 100644 index 0000000..37437af4 --- /dev/null +++ b/third_party/blink/renderer/modules/service_worker/service_worker_router_type_converter_test.cc
@@ -0,0 +1,77 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/renderer/modules/service_worker/service_worker_router_type_converter.h" + +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/renderer/bindings/modules/v8/v8_router_rule.h" +#include "third_party/blink/renderer/bindings/modules/v8/v8_router_source_enum.h" +#include "third_party/blink/renderer/bindings/modules/v8/v8_router_url_pattern_condition.h" +#include "third_party/liburlpattern/parse.h" +#include "third_party/liburlpattern/pattern.h" + +namespace blink { + +namespace { + +TEST(ServiceWorkerRouterTypeConverterTest, Basic) { + constexpr const char kFakeUrlPattern[] = "/fake"; + auto* idl_rule = blink::RouterRule::Create(); + auto* idl_url_pattern = blink::RouterUrlPatternCondition::Create(); + idl_url_pattern->setUrlPattern(kFakeUrlPattern); + idl_rule->setCondition(idl_url_pattern); + idl_rule->setSource(blink::V8RouterSourceEnum::Enum::kNetwork); + + blink::ServiceWorkerRouterRule expected_rule; + blink::ServiceWorkerRouterCondition expected_condition; + expected_condition.type = + blink::ServiceWorkerRouterCondition::ConditionType::kUrlPattern; + blink::UrlPattern expected_url_pattern; + auto parse_result = liburlpattern::Parse( + kFakeUrlPattern, + [](base::StringPiece input) { return std::string(input); }); + ASSERT_TRUE(parse_result.ok()); + expected_url_pattern.pathname = parse_result.value().PartList(); + expected_condition.url_pattern = std::move(expected_url_pattern); + expected_rule.conditions.emplace_back(expected_condition); + blink::ServiceWorkerRouterSource expected_source; + expected_source.type = blink::ServiceWorkerRouterSource::SourceType::kNetwork; + expected_source.network_source.emplace(); + expected_rule.sources.emplace_back(expected_source); + + auto blink_rule = + mojo::ConvertTo<absl::optional<blink::ServiceWorkerRouterRule>>(idl_rule); + EXPECT_TRUE(blink_rule.has_value()); + EXPECT_EQ(expected_rule, *blink_rule); +} + +TEST(ServiceWorkerRouterTypeConverterTest, EmptyUrlPatternShouldBeNullopt) { + constexpr const char kFakeUrlPattern[] = ""; + auto* idl_rule = blink::RouterRule::Create(); + auto* idl_url_pattern = blink::RouterUrlPatternCondition::Create(); + idl_url_pattern->setUrlPattern(kFakeUrlPattern); + idl_rule->setCondition(idl_url_pattern); + idl_rule->setSource(blink::V8RouterSourceEnum::Enum::kNetwork); + + auto blink_rule = + mojo::ConvertTo<absl::optional<blink::ServiceWorkerRouterRule>>(idl_rule); + EXPECT_FALSE(blink_rule.has_value()); +} + +TEST(ServiceWorkerRouterTypeConverterTest, RegexpUrlPatternShouldBeNullopt) { + constexpr const char kFakeUrlPattern[] = "/fake/(\\\\d+)"; + auto* idl_rule = blink::RouterRule::Create(); + auto* idl_url_pattern = blink::RouterUrlPatternCondition::Create(); + idl_url_pattern->setUrlPattern(kFakeUrlPattern); + idl_rule->setCondition(idl_url_pattern); + idl_rule->setSource(blink::V8RouterSourceEnum::Enum::kNetwork); + + auto blink_rule = + mojo::ConvertTo<absl::optional<blink::ServiceWorkerRouterRule>>(idl_rule); + EXPECT_FALSE(blink_rule.has_value()); +} + +} // namespace + +} // namespace blink
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_buffer.idl b/third_party/blink/renderer/modules/webgpu/gpu_buffer.idl index 4df0faf..0cd9ca65 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_buffer.idl +++ b/third_party/blink/renderer/modules/webgpu/gpu_buffer.idl
@@ -4,6 +4,8 @@ // https://gpuweb.github.io/gpuweb/ +typedef unsigned long long GPUSize64Out; + [ Exposed(Window WebGPU, DedicatedWorker WebGPU), SecureContext @@ -18,7 +20,7 @@ [CallWith=Isolate] void unmap(); [CallWith=Isolate] void destroy(); - readonly attribute GPUSize64 size; + readonly attribute GPUSize64Out size; readonly attribute GPUBufferUsageFlags usage; readonly attribute GPUBufferMapState mapState; };
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_sampler_descriptor.idl b/third_party/blink/renderer/modules/webgpu/gpu_sampler_descriptor.idl index 08af733..b06159e 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_sampler_descriptor.idl +++ b/third_party/blink/renderer/modules/webgpu/gpu_sampler_descriptor.idl
@@ -12,7 +12,7 @@ GPUFilterMode minFilter = "nearest"; GPUMipmapFilterMode mipmapFilter = "nearest"; float lodMinClamp = 0; - float lodMaxClamp = 0xffffffff; + float lodMaxClamp = 32; GPUCompareFunction compare; [Clamp] unsigned short maxAnisotropy = 1; };
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc b/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc index f5a4b50..fa90162c 100644 --- a/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc +++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc
@@ -654,6 +654,16 @@ return PositionForOffset(offset, adjust_mid_cluster); } +bool ShapeResult::HasFallbackFonts() const { + const SimpleFontData* primary_font = PrimaryFont(); + for (const scoped_refptr<RunInfo>& run : runs_) { + if (run->font_data_ != primary_font) { + return true; + } + } + return false; +} + void ShapeResult::GetRunFontData(Vector<RunFontData>* font_data) const { for (const auto& run : runs_) { font_data->push_back(
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_result.h b/third_party/blink/renderer/platform/fonts/shaping/shape_result.h index 1ae453f..41708913 100644 --- a/third_party/blink/renderer/platform/fonts/shaping/shape_result.h +++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result.h
@@ -159,6 +159,7 @@ unsigned NumCharacters() const { return num_characters_; } unsigned NumGlyphs() const { return num_glyphs_; } const SimpleFontData* PrimaryFont() const { return primary_font_.get(); } + bool HasFallbackFonts() const; // TODO(eae): Remove start_x and return value once ShapeResultBuffer has been // removed.
diff --git a/third_party/blink/renderer/platform/graphics/video_frame_resource_provider.cc b/third_party/blink/renderer/platform/graphics/video_frame_resource_provider.cc index 9a645ae..1f844fb 100644 --- a/third_party/blink/renderer/platform/graphics/video_frame_resource_provider.cc +++ b/third_party/blink/renderer/platform/graphics/video_frame_resource_provider.cc
@@ -48,8 +48,8 @@ } resource_updater_ = std::make_unique<media::VideoResourceUpdater>( - nullptr, media_context_provider, shared_bitmap_reporter, - resource_provider_.get(), settings_.use_stream_video_draw_quad, + media_context_provider, shared_bitmap_reporter, resource_provider_.get(), + settings_.use_stream_video_draw_quad, settings_.resource_settings.use_gpu_memory_buffer_resources, settings_.resource_settings.use_r16_texture, max_texture_size); }
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5 index 7675efc..06fe799 100644 --- a/third_party/blink/renderer/platform/runtime_enabled_features.json5 +++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -3225,8 +3225,9 @@ public: true, }, { - name: "ServiceWorkerRouter", + name: "ServiceWorkerStaticRouter", base_feature: "none", + public: true, }, { name: "SharedArrayBuffer",
diff --git a/third_party/blink/renderer/platform/text/writing_mode_utils.h b/third_party/blink/renderer/platform/text/writing_mode_utils.h index 89ff05fc..bf7c002 100644 --- a/third_party/blink/renderer/platform/text/writing_mode_utils.h +++ b/third_party/blink/renderer/platform/text/writing_mode_utils.h
@@ -173,8 +173,9 @@ block_end)) {} Value InlineStart() const { return logical_.InlineStart(); } - Value BlockStart() const { return logical_.BlockStart(); } + Value InlineEnd() const { return logical_.InlineEnd(); } + Value BlockEnd() const { return logical_.BlockEnd(); } private: LogicalToLogical(WritingDirectionMode to_writing_direction,
diff --git a/third_party/blink/renderer/platform/wtf/text/atomic_string.h b/third_party/blink/renderer/platform/wtf/text/atomic_string.h index 9df540d..f932d708 100644 --- a/third_party/blink/renderer/platform/wtf/text/atomic_string.h +++ b/third_party/blink/renderer/platform/wtf/text/atomic_string.h
@@ -160,9 +160,6 @@ TextCaseSensitivity case_sensitivity = kTextCaseSensitive) const { return string_.StartsWith(prefix, case_sensitivity); } - bool StartsWithIgnoringCase(const StringView& prefix) const { - return string_.StartsWithIgnoringCase(prefix); - } bool StartsWithIgnoringASCIICase(const StringView& prefix) const { return string_.StartsWithIgnoringASCIICase(prefix); }
diff --git a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py index 1528d4f..7fa2fa0d 100755 --- a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py +++ b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
@@ -1875,6 +1875,19 @@ 'base::StringPiece16', 'base::i18n::UTF16CharIterator', ] + }, + { + 'paths': [ + 'third_party/blink/renderer/modules/service_worker/service_worker_router_type_converter.cc', + 'third_party/blink/renderer/modules/service_worker/service_worker_router_type_converter_test.cc', + # TODO(crbug.com/1371756): consolidate code using liburlpattern. + # Especially, consolidate manifest and this code. + ], + 'allowed': [ + 'liburlpattern::Parse', + 'liburlpattern::Part', + 'liburlpattern::PartType', + ] } ]
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 e0e7dab..1e4fbdb 100644 --- a/third_party/blink/tools/blinkpy/web_tests/port/base.py +++ b/third_party/blink/tools/blinkpy/web_tests/port/base.py
@@ -1578,6 +1578,11 @@ @memoized def args_for_test(self, test_name): args = self._lookup_virtual_test_args(test_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) + pac_url = self.extract_wpt_pac(test_name) if pac_url is not None: args.append("--proxy-pac-url=" + pac_url) @@ -1595,10 +1600,6 @@ 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 @@ -2558,7 +2559,7 @@ def _get_blocked_tests_for_threaded_compositing_testing(self): path = self._filesystem.join(self.web_tests_dir(), 'SmokeTests/SingleThreadedTests') - return self._filesystem.read_text_file(path).split('\n') + return set(self._filesystem.read_text_file(path).split('\n')) def _is_in_allowlist_for_threaded_compositing(self, test_name): # We currently only turn on threaded compositing tests for Linux @@ -2570,15 +2571,15 @@ block_list = self._get_blocked_tests_for_threaded_compositing_testing() + if test_name in block_list: + return False + # We apply the setting of a base test to all of its virtual versions base_name = self.lookup_virtual_test_base(test_name) if base_name: if base_name in block_list: return False - if test_name in block_list: - return False - return True def build_path(self, *comps): @@ -2724,7 +2725,13 @@ self.platforms = [x.lower() for x in platforms] self.bases = bases self.exclusive_tests = exclusive_tests - self.args = args + self.args = sorted(args) + # always put --enable-threaded-compositing at the end of list, so that after appending + # this parameter due to crrev.com/c/4599846, we do not need to restart content shell + # if the parameter set is same. + if ENABLE_THREADED_COMPOSITING_FLAG in self.args: + self.args.remove(ENABLE_THREADED_COMPOSITING_FLAG) + self.args.append(ENABLE_THREADED_COMPOSITING_FLAG) def __repr__(self): return "VirtualTestSuite('%s', %s, %s, %s)" % (self.full_prefix,
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index 97e1285c..92273e4 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -3525,9 +3525,7 @@ crbug.com/764235 external/wpt/css/css-grid/alignment/grid-baseline-justify-001.html [ Failure ] # [css-subgrid] -crbug.com/618969 external/wpt/css/css-grid/subgrid/baseline-001.html [ Failure ] crbug.com/618969 external/wpt/css/css-grid/subgrid/line-names-007.html [ Failure ] -crbug.com/618969 external/wpt/css/css-grid/subgrid/subgrid-baseline-001.html [ Failure ] crbug.com/618969 external/wpt/css/css-grid/subgrid/subgrid-baseline-002.html [ Failure ] # [css-animations] @@ -5528,8 +5526,6 @@ crbug.com/1244896 fast/mediacapturefromelement/CanvasCaptureMediaStream-set-size-too-large.html [ Failure Pass Timeout ] # Sheriff 2022-04-07 -crbug.com/1314314 [ Debug Linux ] virtual/percent-based-scrolling/fast/scrolling/scrollbars/mouse-autoscrolling-on-deleted-scrollbar.html [ Crash Failure Pass Timeout ] -crbug.com/1314314 [ Release Win ] virtual/percent-based-scrolling/fast/scrolling/scrollbars/mouse-autoscrolling-on-deleted-scrollbar.html [ Crash Failure Pass Timeout ] crbug.com/1314323 [ Win ] virtual/compositor-threaded-percent-based-scrolling/fast/scrolling/wheel-scrolling-over-custom-scrollbar.html [ Crash Failure Pass Timeout ] # Sheriff 2022-04-08 @@ -5746,11 +5742,9 @@ crbug.com/1358383 [ Mac ] fast/scrolling/scrollbars/scrollbar-rtl-manipulation.html [ Failure ] crbug.com/1358383 virtual/compositor_threaded_scrollbar_scrolling/fast/scrolling/scrollbars/mouse-scrolling-on-root-scrollbar-thumb.html [ Failure ] crbug.com/1358383 virtual/threaded-prefer-compositing/fast/scrolling/scrollbars/mouse-scrolling-on-root-scrollbar-thumb.html [ Failure ] -[ Linux ] virtual/percent-based-scrolling/fast/scrolling/scrollbars/touch-scrolling-on-root-scrollbar.html [ Pass ] virtual/main-threaded-percent-based-scrolling/fast/scrolling/scrollbars/touch-scrolling-on-root-scrollbar.html [ Pass ] virtual/compositor-threaded-percent-based-scrolling/fast/scrolling/scrollbars/touch-scrolling-on-root-scrollbar.html [ Pass ] virtual/fractional-scroll-offsets/fast/scrolling/scrollbars/touch-scrolling-on-root-scrollbar.html [ Pass ] -[ Mac ] virtual/percent-based-scrolling/fast/scrolling/scrollbars/scrollbar-rtl-manipulation.html [ Pass ] [ Mac ] virtual/main-threaded-percent-based-scrolling/fast/scrolling/scrollbars/scrollbar-rtl-manipulation.html [ Pass ] [ Mac ] virtual/compositor-threaded-percent-based-scrolling/fast/scrolling/scrollbars/scrollbar-rtl-manipulation.html [ Pass ] [ Mac ] virtual/fractional-scroll-offsets/fast/scrolling/scrollbars/scrollbar-rtl-manipulation.html [ Pass ] @@ -5913,7 +5907,6 @@ crbug.com/1370050 http/tests/devtools/sources/debugger-ui/debugger-save-to-temp-var.js [ Crash Failure Pass Timeout ] -crbug.com/1279220 [ Win10.20h2 ] virtual/percent-based-scrolling/fast/scrolling/scrollbars/touch-scrolling-on-root-scrollbar.html [ Pass Timeout ] crbug.com/1279220 [ Linux ] fast/scrolling/non-composited-scroller-in-position-fixed-scroller.html [ Failure Pass ] # Temporarily disable to land DevTools changes
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites index 2bc59385..ec62348 100644 --- a/third_party/blink/web_tests/VirtualTestSuites +++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -466,7 +466,7 @@ { "prefix": "percent-based-scrolling", "platforms": ["Linux", "Mac", "Win"], - "bases": ["fast/scrolling/scrollbars"], + "bases": [], "args": ["--enable-features=WindowsScrollingPersonality", "--enable-threaded-compositing", "--enable-prefer-compositing-to-lcd-text"], @@ -485,8 +485,7 @@ "prefix": "compositor-threaded-percent-based-scrolling", "platforms": ["Linux", "Mac", "Win"], "bases": ["fast/events/wheel", - "fast/scrolling", - "virtual/percent-based-scrolling"], + "fast/scrolling"], "args": ["--enable-features=WindowsScrollingPersonality", "--enable-threaded-compositing", "--enable-prefer-compositing-to-lcd-text"],
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/subgrid/subgrid-baseline-005.html b/third_party/blink/web_tests/external/wpt/css/css-grid/subgrid/subgrid-baseline-005.html new file mode 100644 index 0000000..455439f7 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-grid/subgrid/subgrid-baseline-005.html
@@ -0,0 +1,79 @@ +<!DOCTYPE html> +<link rel="help" href="https://drafts.csswg.org/css-grid-2/"> +<style> +.item { + inline-size: 40px; + box-sizing: border-box; + border: solid 5px hotpink; + line-height: 0; + margin-block-start: 3px; + margin-block-end: 5px; +} +.small { + width: 20px; + height: 20px; + border: solid 5px cyan; +} +.first { + align-self: baseline; +} +.last { + align-self: last baseline; +} +span { + width: 20px; + height: 20px; + box-sizing: border-box; + border: solid 5px orange; + display: inline-block; +} +</style> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/check-layout-th.js"></script> +<body onload="checkLayout('.item')"> + +<div style="position: relative; display: grid; grid-template: 150px 150px 150px / 100px 100px 100px 100px;"> + <div style="display: grid; + gap: 10px; + grid-column: 1 / span 2; + grid-row: 1 / span 3; + grid-template: subgrid / subgrid; + margin-block-start: 5px; margin-block-end: 10px; + border: solid black 5px; + padding-block-start: 10px; padding-block-end: 20px;"> + <div style="display: grid; + gap: 20px; + grid-column: 1 / span 2; + grid-row: 1 / span 2; + grid-template: subgrid / subgrid; + margin-block-start: 3px; margin-block-end: 7px; + border: solid black 5px; + padding-block-start: 5px; padding-block-end: 10px;"> + <div data-offset-y="36" class="item first"> + <span></span><br><span></span> + </div> + <div data-offset-y="85" class="item last"> + <span></span><br><span></span> + </div> + <div data-offset-y="163" class="item first"> + <span></span><br><span></span> + </div> + <div data-offset-y="218" class="item last"> + <span></span><br><span></span> + </div> + </div> + <div data-offset-y="308" class="item first"> + <span></span><br><span></span> + </div> + <div data-offset-y="360" class="item last"> + <span></span><br><span></span> + </div> + </div> + <div data-offset-y="41" class="item small first"></div> + <div data-offset-y="110" class="item small last"></div> + <div data-offset-y="168" class="item small first"></div> + <div data-offset-y="243" class="item small last"></div> + <div data-offset-y="313" class="item small first"></div> + <div data-offset-y="385" class="item small last"></div> +</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/subgrid/subgrid-baseline-006.html b/third_party/blink/web_tests/external/wpt/css/css-grid/subgrid/subgrid-baseline-006.html new file mode 100644 index 0000000..23d2b3b --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-grid/subgrid/subgrid-baseline-006.html
@@ -0,0 +1,79 @@ +<!DOCTYPE html> +<link rel="help" href="https://drafts.csswg.org/css-grid-2/"> +<style> +.item { + inline-size: 40px; + box-sizing: border-box; + border: solid 5px hotpink; + line-height: 0; + margin-block-start: 3px; + margin-block-end: 5px; +} +.small { + width: 30px; + height: 30px; + border: solid 5px cyan; +} +.first { + align-self: baseline; +} +.last { + align-self: last baseline; +} +span { + width: 20px; + height: 20px; + box-sizing: border-box; + border: solid 5px orange; + display: inline-block; +} +</style> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/check-layout-th.js"></script> +<body onload="checkLayout('.item')"> + +<div style="writing-mode: vertical-rl; width: 600px; position: relative; display: grid; grid-template: 150px 150px 150px / 100px 100px 100px 100px;"> + <div style="display: grid; + gap: 10px; + grid-column: 1 / span 2; + grid-row: 1 / span 3; + grid-template: subgrid / subgrid; + margin-block-start: 5px; margin-block-end: 10px; + border: solid black 5px; + padding-block-start: 10px; padding-block-end: 20px;"> + <div style="display: grid; + gap: 20px; + grid-column: 1 / span 2; + grid-row: 1 / span 2; + grid-template: subgrid / subgrid; + margin-block-start: 3px; margin-block-end: 7px; + border: solid black 5px; + padding-block-start: 5px; padding-block-end: 10px;"> + <div data-offset-x="514" class="item first"> + <span></span><br><span></span> + </div> + <div data-offset-x="465" class="item last"> + <span></span><br><span></span> + </div> + <div data-offset-x="387" class="item first"> + <span></span><br><span></span> + </div> + <div data-offset-x="332" class="item last"> + <span></span><br><span></span> + </div> + </div> + <div data-offset-x="242" class="item first"> + <span></span><br><span></span> + </div> + <div data-offset-x="190" class="item last"> + <span></span><br><span></span> + </div> + </div> + <div data-offset-x="534" class="item small first"></div> + <div data-offset-x="465" class="item small last"></div> + <div data-offset-x="407" class="item small first"></div> + <div data-offset-x="332" class="item small last"></div> + <div data-offset-x="262" class="item small first"></div> + <div data-offset-x="190" class="item small last"></div> +</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/subgrid/subgrid-baseline-007.html b/third_party/blink/web_tests/external/wpt/css/css-grid/subgrid/subgrid-baseline-007.html new file mode 100644 index 0000000..f8477be --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-grid/subgrid/subgrid-baseline-007.html
@@ -0,0 +1,85 @@ +<!DOCTYPE html> +<link rel="help" href="https://drafts.csswg.org/css-grid-2/"> +<style> +.item { + inline-size: 40px; + box-sizing: border-box; + border: solid 5px hotpink; + line-height: 0; + margin-block-start: 3px; + margin-block-end: 5px; +} +.small { + width: 20px; + height: 20px; + border: solid 5px cyan; +} +.first { + align-self: baseline; +} +.last { + align-self: last baseline; +} +.item.small.first { + block-size: 50px; +} +.item.small.last { + block-size: 100px; +} +span { + width: 20px; + height: 20px; + box-sizing: border-box; + border: solid 5px orange; + display: inline-block; +} +</style> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/check-layout-th.js"></script> +<body onload="checkLayout('.item')"> + +<div style="position: relative; display: grid; grid-template: auto auto auto / 100px 100px 100px 100px;"> + <div style="display: grid; + gap: 10px; + grid-column: 1 / span 2; + grid-row: 1 / span 3; + grid-template: subgrid / subgrid; + margin-block-start: 5px; margin-block-end: 10px; + border: solid black 5px; + padding-block-start: 10px; padding-block-end: 20px;"> + <div style="display: grid; + gap: 20px; + grid-column: 1 / span 2; + grid-row: 1 / span 2; + grid-template: subgrid / subgrid; + margin-block-start: 3px; margin-block-end: 7px; + border: solid black 5px; + padding-block-start: 5px; padding-block-end: 10px;"> + <div data-offset-y="36" class="item first"> + <span></span><br><span></span> + </div> + <div data-offset-y="58" class="item last"> + <span></span><br><span></span> + </div> + <div data-offset-y="151" class="item first"> + <span></span><br><span></span> + </div> + <div data-offset-y="181" class="item last"> + <span></span><br><span></span> + </div> + </div> + <div data-offset-y="291" class="item first"> + <span></span><br><span></span> + </div> + <div data-offset-y="321" class="item last"> + <span></span><br><span></span> + </div> + </div> + <div data-offset-y="11" class="item small first"></div> + <div data-offset-y="3" class="item small last"></div> + <div data-offset-y="126" class="item small first"></div> + <div data-offset-y="126" class="item small last"></div> + <div data-offset-y="266" class="item small first"></div> + <div data-offset-y="266" class="item small last"></div> +</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/subgrid/subgrid-baseline-008.html b/third_party/blink/web_tests/external/wpt/css/css-grid/subgrid/subgrid-baseline-008.html new file mode 100644 index 0000000..1ef2359 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-grid/subgrid/subgrid-baseline-008.html
@@ -0,0 +1,85 @@ +<!DOCTYPE html> +<link rel="help" href="https://drafts.csswg.org/css-grid-2/"> +<style> +.item { + inline-size: 40px; + box-sizing: border-box; + border: solid 5px hotpink; + line-height: 0; + margin-block-start: 3px; + margin-block-end: 5px; +} +.small { + width: 20px; + height: 20px; + border: solid 5px cyan; +} +.first { + align-self: baseline; +} +.last { + align-self: last baseline; +} +.item.small.first { + block-size: 50px; +} +.item.small.last { + block-size: 100px; +} +span { + width: 20px; + height: 20px; + box-sizing: border-box; + border: solid 5px orange; + display: inline-block; +} +</style> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/check-layout-th.js"></script> +<body onload="checkLayout('.item')"> + +<div style="writing-mode: vertical-rl; width: 600px; position: relative; display: grid; grid-template: auto auto auto / 100px 100px 100px 100px;"> + <div style="display: grid; + gap: 10px; + grid-column: 1 / span 2; + grid-row: 1 / span 3; + grid-template: subgrid / subgrid; + margin-block-start: 5px; margin-block-end: 10px; + border: solid black 5px; + padding-block-start: 10px; padding-block-end: 20px;"> + <div style="display: grid; + gap: 20px; + grid-column: 1 / span 2; + grid-row: 1 / span 2; + grid-template: subgrid / subgrid; + margin-block-start: 3px; margin-block-end: 7px; + border: solid black 5px; + padding-block-start: 5px; padding-block-end: 10px;"> + <div data-offset-x="514" class="item first"> + <span></span><br><span></span> + </div> + <div data-offset-x="428" class="item last"> + <span></span><br><span></span> + </div> + <div data-offset-x="325" class="item first"> + <span></span><br><span></span> + </div> + <div data-offset-x="234" class="item last"> + <span></span><br><span></span> + </div> + </div> + <div data-offset-x="131" class="item first"> + <span></span><br><span></span> + </div> + <div data-offset-x="40" class="item last"> + <span></span><br><span></span> + </div> + </div> + <div data-offset-x="524" class="item small first"></div> + <div data-offset-x="393" class="item small last"></div> + <div data-offset-x="335" class="item small first"></div> + <div data-offset-x="199" class="item small last"></div> + <div data-offset-x="141" class="item small first"></div> + <div data-offset-x="5" class="item small last"></div> +</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/subgrid/subgrid-baseline-009.html b/third_party/blink/web_tests/external/wpt/css/css-grid/subgrid/subgrid-baseline-009.html new file mode 100644 index 0000000..b7bf46d --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-grid/subgrid/subgrid-baseline-009.html
@@ -0,0 +1,83 @@ +<!DOCTYPE html> +<link rel="help" href="https://drafts.csswg.org/css-grid-2/"> +<style> +.item { + writing-mode: vertical-rl; + block-size: 80px; + box-sizing: border-box; + border: solid 5px hotpink; + line-height: 0; + margin-block-start: 10px; + margin-block-end: 15px; +} +.small { + width: 20px; + height: 20px; + border: solid 5px cyan; +} +.first { + justify-self: baseline; +} +.last { + justify-self: last baseline; +} +span { + width: 20px; + height: 20px; + box-sizing: border-box; + border: solid 5px orange; + display: inline-block; +} +</style> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/check-layout-th.js"></script> +<body onload="checkLayout('.item')"> + +<div style="width: 600px; position: relative; display: grid; grid-auto-flow: column; grid-template: 100px 100px 100px 100px / auto auto auto;"> + <div style="display: grid; + grid-auto-flow: column; + gap: 10px; + grid-column: 1 / span 3; + grid-row: 1 / span 2; + grid-template: subgrid / subgrid; + margin-inline-start: 5px; margin-inline-end: 10px; + border: solid black 5px; + padding-inline-start: 10px; padding-inline-end: 20px;"> + <div style="display: grid; + direction: rtl; + grid-auto-flow: column; + gap: 20px; + grid-column: 1 / span 2; + grid-row: 1 / span 2; + grid-template: subgrid / subgrid; + margin-inline-start: 3px; margin-inline-end: 7px; + border: solid black 5px; + padding-inline-start: 5px; padding-inline-end: 10px;"> + <div data-offset-x="292" class="item first"> + <span></span><br><span></span> + </div> + <div data-offset-x="237" class="item last"> + <span></span><br><span></span> + </div> + <div data-offset-x="112" class="item first"> + <span></span><br><span></span> + </div> + <div data-offset-x="57" class="item last"> + <span></span><br><span></span> + </div> + </div> + <div data-offset-x="475" class="item first"> + <span></span><br><span></span> + </div> + <div data-offset-x="420" class="item last"> + <span></span><br><span></span> + </div> + </div> + <div data-offset-x="177" class="item small first"></div> + <div data-offset-x="102" class="item small last"></div> + <div data-offset-x="357" class="item small first"></div> + <div data-offset-x="282" class="item small last"></div> + <div data-offset-x="540" class="item small first"></div> + <div data-offset-x="465" class="item small last"></div> +</div>
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/service-worker-fetch-async-stacks.js b/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/service-worker-fetch-async-stacks.js index 453c5f75..2b16d381 100644 --- a/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/service-worker-fetch-async-stacks.js +++ b/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/service-worker-fetch-async-stacks.js
@@ -16,6 +16,16 @@ }; dp.Target.onAttachedToTarget(onAttached); + // Enable the debugger before registering a service worker so that + // the debugger can be attached even when the + // AllowDevToolsMainThreadDebuggerForMultipleMainFrames feature is disabled. + // When the feature is disabled, a renderer disallows the debugger when + // there are multiple browsing contexts. The following code will create a + // new browsing context, so enabling the debugger after registering a service + // worker will fail. Enabling the debugger earlier works around the issue. + // TODO(https://crbug.com/1434900): Remove this workaround. + await dp.Debugger.enable(); + await dp.ServiceWorker.enable(); await session.navigate('resources/service-worker-fetch.html'); testRunner.log('Navigated, registering service worker');
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt index b70a1dc..1c3a7d3 100644 --- a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt +++ b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
@@ -1260,14 +1260,12 @@ method replaceWith method substringData setter data -interface ChildNodePart : Part +interface ChildNodePart : PartRoot attribute @@toStringTag getter children getter nextSibling getter previousSibling - method clone method constructor - method getParts method replaceChildren interface Clipboard : EventTarget attribute @@toStringTag @@ -6760,7 +6758,7 @@ getter root method constructor method disconnect -interface PartRoot +interface PartRoot : Part attribute @@toStringTag method constructor method getParts
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/css-content-visibility/accessibility/content-visibility-accessibility-001.html b/third_party/blink/web_tests/wpt_internal/display-lock/css-content-visibility/accessibility/content-visibility-accessibility-001.html index bd185585e..7e6e0a77 100644 --- a/third_party/blink/web_tests/wpt_internal/display-lock/css-content-visibility/accessibility/content-visibility-accessibility-001.html +++ b/third_party/blink/web_tests/wpt_internal/display-lock/css-content-visibility/accessibility/content-visibility-accessibility-001.html
@@ -72,10 +72,9 @@ target.getBoundingClientRect(); axTarget = axElementById("target"); - // Now #target is not locked, but expect the same 9 children ("target" text node, 4 whitespace - // nodes between divs, and 4 div nodes). That's because the nodes already exist, they were - // updated to become ignored but they are still included in the tree. - t.step(() => { assert_equals(axTarget.childrenCount, 9, "Children count when not locked"); }); + // Now #target is not locked, expect 5 children ("target" text node, 4 divs). + // This is the same as it would be if content-visibility had never been used. + t.step(() => { assert_equals(axTarget.childrenCount, 5, "Children count when not locked"); }); for (let i = 0; i < axTarget.childrenCount; ++i) { const axChild = axTarget.childAtIndex(i);
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/css-content-visibility/accessibility/content-visibility-accessibility-002.html b/third_party/blink/web_tests/wpt_internal/display-lock/css-content-visibility/accessibility/content-visibility-accessibility-002.html index f1266eb..6e28e6d 100644 --- a/third_party/blink/web_tests/wpt_internal/display-lock/css-content-visibility/accessibility/content-visibility-accessibility-002.html +++ b/third_party/blink/web_tests/wpt_internal/display-lock/css-content-visibility/accessibility/content-visibility-accessibility-002.html
@@ -45,18 +45,13 @@ requestAnimationFrame(() => requestAnimationFrame(() => { // The ax object for #target got replaced since the layout object changed, so use the new ax object. axTarget = axElementById("target"); - // It's still the same 5 children, but the non-whitespace nodes became unignored. - // Note whitespace nodes would not be there if the subtree was not hidden in first place, the total would be 3 children. - t.step(() => { assert_equals(axTarget.childrenCount, 5); }); + // There are now 3 children, as the whitespace nodes are no longer included in the tree. + // This is the same as it would be if content-visibility had never been used. + t.step(() => { assert_equals(axTarget.childrenCount, 3); }); t.step(() => { assert_equals(axTarget.name, "Label"); }); for (let i = 0; i < axTarget.childrenCount; ++i) { const axChild = axTarget.childAtIndex(i); - if (i == 0 || axChild == axElementById("child") || axChild == axElementById("target_label")) { - t.step(() => { assert_false(axChild.isIgnored, "After update, isIgnored is false on non-whitespace child #" + i); }); - } else { - // These are the whitespace nodes - t.step(() => { assert_true(axChild.isIgnored, "After update, isIgnored is true on whitespace child #" + i); }); - } + t.step(() => { assert_false(axChild.isIgnored, "After update, isIgnored is false on child #" + i); }); } t.done(); }));
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/css-content-visibility/accessibility/content-visibility-accessibility-003.html b/third_party/blink/web_tests/wpt_internal/display-lock/css-content-visibility/accessibility/content-visibility-accessibility-003.html index 99e00c7f..2dd5682 100644 --- a/third_party/blink/web_tests/wpt_internal/display-lock/css-content-visibility/accessibility/content-visibility-accessibility-003.html +++ b/third_party/blink/web_tests/wpt_internal/display-lock/css-content-visibility/accessibility/content-visibility-accessibility-003.html
@@ -42,13 +42,10 @@ // Wait for the next frame for the ax object to be recreated. requestAnimationFrame(() => { requestAnimationFrame(() => { - axHidden = axElementById("hidden"); - // #hidden is now unlocked and saved as a normal AXLayoutObject, but it still has the same - // three child nodes. The whitespace node is still present because it was already created, - // but it's marked as ignored - t.step(() => { assert_equals(axHidden.childrenCount, 3, "Children count after activation"); }); - const axChild = axHidden.childAtIndex(2); - t.step(() => { assert_true(axChild.isIgnored, "After update, isIgnored is true on whitespace node"); }); + let axHidden = axElementById("hidden"); + // Now #target is not locked, expect 2 children (no whitespace node). + // This is the same as it would be if content-visibility had never been used. + t.step(() => { assert_equals(axHidden.childrenCount, 2, "Children count after activation"); }); t.done(); }); });
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/css-content-visibility/accessibility/content-visibility-accessibility-003a.html b/third_party/blink/web_tests/wpt_internal/display-lock/css-content-visibility/accessibility/content-visibility-accessibility-003a.html index 504035ab..ca8056ee 100644 --- a/third_party/blink/web_tests/wpt_internal/display-lock/css-content-visibility/accessibility/content-visibility-accessibility-003a.html +++ b/third_party/blink/web_tests/wpt_internal/display-lock/css-content-visibility/accessibility/content-visibility-accessibility-003a.html
@@ -31,9 +31,9 @@ const listener = (e) => { if (!e.skipped) { let axHidden = axElementById("hidden"); - t.step(() => { assert_equals(axHidden.childrenCount, 3, "Children count after activation"); }); - const axChild = axHidden.childAtIndex(2); - t.step(() => { assert_true(axChild.isIgnored, "After update, isIgnored is true on whitespace node"); }); + // Now #target is not locked, expect 2 children (no whitespace node). + // This is the same as it would be if content-visibility had never been used. + t.step(() => { assert_equals(axHidden.childrenCount, 2, "Children count after activation"); }); t.done(); } };
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/css-content-visibility/accessibility/content-visibility-accessibility-003b.html b/third_party/blink/web_tests/wpt_internal/display-lock/css-content-visibility/accessibility/content-visibility-accessibility-003b.html index 01958da..8fe5062 100644 --- a/third_party/blink/web_tests/wpt_internal/display-lock/css-content-visibility/accessibility/content-visibility-accessibility-003b.html +++ b/third_party/blink/web_tests/wpt_internal/display-lock/css-content-visibility/accessibility/content-visibility-accessibility-003b.html
@@ -31,9 +31,9 @@ const listener = (e) => { if (!e.skipped) { let axHidden = axElementById("hidden"); - t.step(() => { assert_equals(axHidden.childrenCount, 3, "Children count after activation"); }); - const axChild = axHidden.childAtIndex(2); - t.step(() => { assert_true(axChild.isIgnored, "After update, isIgnored is true on whitespace node"); }); + // Now #target is not locked, expect 2 children (no whitespace node). + // This is the same as it would be if content-visibility had never been used. + t.step(() => { assert_equals(axHidden.childrenCount, 2, "Children count after activation"); }); t.done(); } };
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/css-content-visibility/accessibility/content-visibility-accessibility-003c.html b/third_party/blink/web_tests/wpt_internal/display-lock/css-content-visibility/accessibility/content-visibility-accessibility-003c.html index 93fa18d..0b5afda 100644 --- a/third_party/blink/web_tests/wpt_internal/display-lock/css-content-visibility/accessibility/content-visibility-accessibility-003c.html +++ b/third_party/blink/web_tests/wpt_internal/display-lock/css-content-visibility/accessibility/content-visibility-accessibility-003c.html
@@ -43,12 +43,9 @@ requestAnimationFrame(() => { requestAnimationFrame(() => { axHidden = axElementById("hidden"); - // #hidden is now unlocked and saved as a normal AXLayoutObject, but it still has the same - // three child nodes. The whitespace node is still present because it was already created, - // but it's marked as ignored - t.step(() => { assert_equals(axHidden.childrenCount, 3, "Children count after activation"); }); - const axChild = axHidden.childAtIndex(2); - t.step(() => { assert_true(axChild.isIgnored, "After update, isIgnored is true on whitespace node"); }); + // Now #target is not locked, expect 2 children (no whitespace node). + // This is the same as it would be if content-visibility had never been used. + t.step(() => { assert_equals(axHidden.childrenCount, 2, "Children count after activation"); }); t.done(); }); });
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/css-content-visibility/accessibility/content-visibility-accessibility-004.html b/third_party/blink/web_tests/wpt_internal/display-lock/css-content-visibility/accessibility/content-visibility-accessibility-004.html index 2629f2d..b7bb2392 100644 --- a/third_party/blink/web_tests/wpt_internal/display-lock/css-content-visibility/accessibility/content-visibility-accessibility-004.html +++ b/third_party/blink/web_tests/wpt_internal/display-lock/css-content-visibility/accessibility/content-visibility-accessibility-004.html
@@ -43,12 +43,9 @@ requestAnimationFrame(() => { requestAnimationFrame(() => { axHidden = axElementById("hidden"); - // #hidden is now unlocked and saved as a normal AXLayoutObject, but it still has the same - // three child nodes. The whitespace node is still present because it was already created, - // but it's marked as ignored - t.step(() => { assert_equals(axHidden.childrenCount, 3, "Children count after activation"); }); - const axChild = axHidden.childAtIndex(2); - t.step(() => { assert_true(axChild.isIgnored, "After update, isIgnored is true on whitespace node"); }); + // There are now 2 children, as the whitespace nodes are no longer included in the tree. + // This is the same as it would be if content-visibility had never been used. + t.step(() => { assert_equals(axHidden.childrenCount, 2, "Children count after activation"); }); t.done(); }); });
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/css-content-visibility/accessibility/content-visibility-accessibility-005.html b/third_party/blink/web_tests/wpt_internal/display-lock/css-content-visibility/accessibility/content-visibility-accessibility-005.html index 159dcf6a..79996c8 100644 --- a/third_party/blink/web_tests/wpt_internal/display-lock/css-content-visibility/accessibility/content-visibility-accessibility-005.html +++ b/third_party/blink/web_tests/wpt_internal/display-lock/css-content-visibility/accessibility/content-visibility-accessibility-005.html
@@ -47,15 +47,11 @@ requestAnimationFrame(() => { // Frame 3. requestAnimationFrame(() => { // Frame 4. axHidden = axElementById("hidden"); - // #hidden is now unlocked and saved as a normal AXLayoutObject but it still has the same - // three child nodes. The whitespace node is still present because it was already created, - // but it's marked as ignored + // There are now 2 children, as the whitespace nodes are no longer included in the tree. + // This is the same as it would be if content-visibility had never been used. t.step(() => { - assert_equals(axHidden.childrenCount, 3, "Child count after activation"); + assert_equals(axHidden.childrenCount, 2, "Child count after activation"); }); - const axChild = axHidden.childAtIndex(2); - t.step(() => { - assert_true(axChild.isIgnored, "After update, isIgnored is true on whitespace node"); }); t.done(); }); });
diff --git a/third_party/closure_compiler/externs/file_manager_private.js b/third_party/closure_compiler/externs/file_manager_private.js index 503434c..28d7a69 100644 --- a/third_party/closure_compiler/externs/file_manager_private.js +++ b/third_party/closure_compiler/externs/file_manager_private.js
@@ -458,7 +458,8 @@ */ chrome.fileManagerPrivate.BulkPinStage = { STOPPED: 'stopped', - PAUSED: 'paused', + PAUSED_OFFLINE: 'paused_offline', + PAUSED_BATTERY_SAVER: 'paused_battery_saver', GETTING_FREE_SPACE: 'getting_free_space', LISTING_FILES: 'listing_files', SYNCING: 'syncing',
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index e1c470ba..25c56c0 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -55146,13 +55146,6 @@ </int> </enum> -<enum name="JavaJsBridgeMethodInvocationError"> - <int value="0" label="MethodInvocationAsConstructorDisallowed"/> - <int value="1" label="MethodInvocationNonexistentMethod"/> - <int value="2" label="MethodInvocationOnNonInjectedObjectDisallowed"/> - <int value="3" label="MethodInvocationErrorMessage"/> -</enum> - <enum name="JavaScriptDialogDismissalCause"> <int value="0" label="Tab closed">The tab owning the dialog was closed</int> <int value="1" label="New dialog"> @@ -59571,6 +59564,7 @@ label="OptimizationGuideInstallWideModelStore:enabled"/> <int value="-1776351704" label="DesktopPWAsOmniboxInstall:disabled"/> <int value="-1775842908" label="EnableOAuthIpp:disabled"/> + <int value="-1774921110" label="ServiceWorkerStaticRouter:enabled"/> <int value="-1774818943" label="VrWebInputEditing:enabled"/> <int value="-1774290918" label="webview-shadow-dom-fenced-frames"/> <int value="-1773925297" label="TimedHtmlParserBudget:disabled"/> @@ -62402,6 +62396,7 @@ label="CrossOriginMediaPlaybackRequiresUserGesture:disabled"/> <int value="-296762162" label="ExoOrdinalMotion:enabled"/> <int value="-296493265" label="ProjectorAppDebug:enabled"/> + <int value="-296208832" label="ServiceWorkerStaticRouter:disabled"/> <int value="-296179618" label="CookiesWithoutSameSiteMustBeSecure:enabled"/> <int value="-295237704" label="EnableRemovingAllThirdPartyCookies:enabled"/> <int value="-293546827" label="HideIncognitoMediaMetadata:enabled"/> @@ -66226,6 +66221,7 @@ <int value="1719958026" label="QueryTiles:enabled"/> <int value="1720399117" label="SkiaGraphite:enabled"/> <int value="1721854955" label="EnableEdidBasedDisplayIds:disabled"/> + <int value="1722521465" label="CrosBatterySaverAlwaysOn:disabled"/> <int value="1722748383" label="EnableAppReinstallZeroState:disabled"/> <int value="1723601083" label="enable-app-window-controls"/> <int value="1724247189" label="StylusHandwriting:enabled"/> @@ -66650,6 +66646,7 @@ label="EnableBluetoothVerboseLogsForGooglers:enabled"/> <int value="1930901873" label="disable-sync-app-list"/> <int value="1931309368" label="fill-on-account-select:disabled"/> + <int value="1932038907" label="CrosBatterySaverAlwaysOn:enabled"/> <int value="1932204471" label="SyncPseudoUSSThemes:disabled"/> <int value="1932732886" label="OpenVR:enabled"/> <int value="1933282728" label="OmniboxUICuesForSearchHistoryMatches:enabled"/> @@ -100947,6 +100944,43 @@ <int value="4" label="The trigger is in monitor mode"/> </enum> +<enum name="SVCScalabilityMode"> + <int value="0" label="L1T1"/> + <int value="1" label="L1T2"/> + <int value="2" label="L1T3"/> + <int value="3" label="L2T1"/> + <int value="4" label="L2T2"/> + <int value="5" label="L2T3"/> + <int value="6" label="L3T1"/> + <int value="7" label="L3T2"/> + <int value="8" label="L3T3"/> + <int value="9" label="L2T1h"/> + <int value="10" label="L2T2h"/> + <int value="11" label="L2T3h"/> + <int value="12" label="S2T1"/> + <int value="13" label="S2T2"/> + <int value="14" label="S2T3"/> + <int value="15" label="S2T1h"/> + <int value="16" label="S2T2h"/> + <int value="17" label="S2T3h"/> + <int value="18" label="S3T1"/> + <int value="19" label="S3T2"/> + <int value="20" label="S3T3"/> + <int value="21" label="S3T1h"/> + <int value="22" label="S3T2h"/> + <int value="23" label="S3T3h"/> + <int value="24" label="L2T1Key"/> + <int value="25" label="L2T2Key"/> + <int value="26" label="L2T2KeyShift"/> + <int value="27" label="L2T3Key"/> + <int value="28" label="L2T3KeyShift"/> + <int value="29" label="L3T1Key"/> + <int value="30" label="L3T2Key"/> + <int value="31" label="L3T2KeyShift"/> + <int value="32" label="L3T3Key"/> + <int value="33" label="L3T3KeyShift"/> +</enum> + <enum name="SwapchainFormat"> <int value="0" label="B8G8R8A8"/> <int value="1" label="YUY2"/> @@ -108364,6 +108398,13 @@ <int value="18" label="OOP Video Decoder"/> </enum> +<enum name="VideoEncoderUseCase"> + <int value="0" label="CastMirroring"/> + <int value="1" label="MediaRecorder"/> + <int value="2" label="WebCodecs"/> + <int value="3" label="WebRTC"/> +</enum> + <enum name="VideoFormat"> <obsolete> Deprecated as of 05/2015. Substituted by VideoFramePixelFormat.
diff --git a/tools/metrics/histograms/metadata/ash/histograms.xml b/tools/metrics/histograms/metadata/ash/histograms.xml index 1791408..9d46c48 100644 --- a/tools/metrics/histograms/metadata/ash/histograms.xml +++ b/tools/metrics/histograms/metadata/ash/histograms.xml
@@ -5761,23 +5761,6 @@ </histogram> <histogram - name="Ash.Shelf.ShutdownConfirmationBubble.ActionDuration.{BubbleAction}" - units="ms" expires_after="2022-12-31"> - <owner>sherrilin@google.com</owner> - <owner>cros-lurs@google.com</owner> - <summary> - Track time delta between a bubble opened and an action taken on the shutdown - confirmation bubble. - </summary> - <token key="BubbleAction"> - <variant name="Cancel" summary="User clicked cancel button"/> - <variant name="Confirm" summary="User clicked confirm button"/> - <variant name="Dismiss" - summary="User dismissed the shutdown confirmation buble"/> - </token> -</histogram> - -<histogram name="Ash.Shelf.ShutdownConfirmationBubble.TimeToNextBoot.LoginShutdownToPowerUpDuration" units="seconds" expires_after="2023-09-10"> <owner>sherrilin@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/blink/histograms.xml b/tools/metrics/histograms/metadata/blink/histograms.xml index 78a8e52..0cb8d9a6a 100644 --- a/tools/metrics/histograms/metadata/blink/histograms.xml +++ b/tools/metrics/histograms/metadata/blink/histograms.xml
@@ -2227,13 +2227,6 @@ </summary> </histogram> -<histogram name="Blink.JavaJsBridge.MethodInvocationError" - enum="JavaJsBridgeMethodInvocationError" expires_after="2023-06-04"> - <owner>torne@chromium.org</owner> - <owner>src/android_webview/OWNERS</owner> - <summary>Records the Java/JS bridge method invocation errors.</summary> -</histogram> - <histogram base="true" name="Blink.JavascriptDocumentUpdate.UpdateTime" units="microseconds" expires_after="2023-09-10"> <!-- Name completed by histogram_suffixes name="BlinkUpdateTimePreFCPSuffixes" -->
diff --git a/tools/metrics/histograms/metadata/borealis/histograms.xml b/tools/metrics/histograms/metadata/borealis/histograms.xml index 23458c19..31804e5 100644 --- a/tools/metrics/histograms/metadata/borealis/histograms.xml +++ b/tools/metrics/histograms/metadata/borealis/histograms.xml
@@ -22,6 +22,16 @@ <histograms> +<histogram name="Borealis.Audio.UsedSubdevices" units="count" + expires_after="2023-11-09"> + <owner>normanbt@google.com</owner> + <owner>src/chrome/browser/ash/borealis/OWNERS</owner> + <summary> + The number of audio subdevices that are used by games that are running on + proton. This is recorded periodically when the game is running. + </summary> +</histogram> + <histogram name="Borealis.Disk.HighestDirtyPagesDaily" units="KiB" expires_after="2023-10-09"> <owner>danielng@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/net/histograms.xml b/tools/metrics/histograms/metadata/net/histograms.xml index a95b0cf1..ed902e10 100644 --- a/tools/metrics/histograms/metadata/net/histograms.xml +++ b/tools/metrics/histograms/metadata/net/histograms.xml
@@ -254,7 +254,7 @@ </histogram> <histogram name="HttpCache.IsNoStore{Type}" enum="Boolean" - expires_after="2023-07-27"> + expires_after="2024-06-13"> <owner>bashi@chromium.org</owner> <owner>blink-network-stack@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/optimization/histograms.xml b/tools/metrics/histograms/metadata/optimization/histograms.xml index c0621a28..cacce18 100644 --- a/tools/metrics/histograms/metadata/optimization/histograms.xml +++ b/tools/metrics/histograms/metadata/optimization/histograms.xml
@@ -35,6 +35,8 @@ <variants name="OptimizationTarget"> <variant name="ClientSidePhishing" summary="Client Side Phishing"/> + <variant name="ClientSidePhishingImageEmbedder" + summary="Client Side Phishing Image Embedder"/> <variant name="ContextualPageActionPriceTracking" summary="Contextual Page Action: Show price tracking"/> <variant name="GeolocationPermissions" summary="Geolocation permissions"/>
diff --git a/tools/metrics/histograms/metadata/sb_client/histograms.xml b/tools/metrics/histograms/metadata/sb_client/histograms.xml index d1fccb3..0f3f15b6 100644 --- a/tools/metrics/histograms/metadata/sb_client/histograms.xml +++ b/tools/metrics/histograms/metadata/sb_client/histograms.xml
@@ -675,6 +675,17 @@ </summary> </histogram> +<histogram name="SBClientPhishing.ImageEmbeddingModelVersionMatch" + enum="BooleanMatched" expires_after="2024-06-05"> + <owner>andysjlim@chromium.org</owner> + <owner>chrome-counter-abuse-alerts@google.com</owner> + <summary> + Logs whether the image embedding model version is matched or not so that the + correctly paired trigger and image embedidng model are sent together to the + renderer process + </summary> +</histogram> + <histogram name="SBClientPhishing.LocalModelDetectsPhishing" enum="BooleanIsPhishing" expires_after="2023-12-04"> <owner>drubery@chromium.org</owner> @@ -704,8 +715,8 @@ </histogram> <histogram name="SBClientPhishing.ModelDynamicUpdateSuccess" - enum="BooleanSuccess" expires_after="2023-12-04"> - <owner>drubery@chromium.org</owner> + enum="BooleanSuccess" expires_after="2024-06-08"> + <owner>andysjlim@chromium.org</owner> <owner>chrome-counter-abuse-alerts@google.com</owner> <summary> Records whether a dynamic update is successful or not. This is logged when a @@ -713,6 +724,17 @@ </summary> </histogram> +<histogram name="SBClientPhishing.ModelDynamicUpdateSuccess.ImageEmbedding" + enum="BooleanSuccess" expires_after="2024-05-23"> + <owner>andysjlim@chromium.org</owner> + <owner>chrome-counter-abuse-alerts@google.com</owner> + <summary> + Records whether a dynamic update of the image embedding model is successful + or not. This is logged when a new image embedding model is fetched, or on + each startup. + </summary> +</histogram> + <histogram name="SBClientPhishing.NetworkRequestDuration" units="ms" expires_after="2024-03-19"> <owner>andysjlim@chromium.org</owner>
diff --git a/tools/metrics/ukm/ukm.xml b/tools/metrics/ukm/ukm.xml index 85fed87..598b52d 100644 --- a/tools/metrics/ukm/ukm.xml +++ b/tools/metrics/ukm/ukm.xml
@@ -13515,6 +13515,113 @@ </metric> </event> +<event name="Media.VideoEncoderMetrics"> + <owner>hiroh@chromium.org</owner> + <owner>media-dev@chromium.org</owner> + <summary> + A record of encoding usage metrics in chrome, for example, for cast + mirroring and webcodecs. This is recorded in the end of each video encoding + session. + </summary> + <metric name="Height"> + <summary> + Integer value indicating the height of the encoded stream. This is + bucketed per 100 and capped by 8200. + </summary> + <aggregation> + <history> + <statistics> + <quantiles type="std-percentiles"/> + </statistics> + </history> + </aggregation> + </metric> + <metric name="IsHardware" enum="Boolean"> + <summary> + Boolean value indicating whether the encoder implementation is hardware + accelerated one or not. + </summary> + <aggregation> + <history> + <statistics> + <enumeration/> + </statistics> + </history> + </aggregation> + </metric> + <metric name="NumEncodedFrames"> + <summary> + Integer value indicating the number of the successfully encoded frames. + This is bucketed per 100. + </summary> + </metric> + <metric name="Profile" enum="VideoCodecProfile"> + <summary> + media::VideoCodecProfile enum value. The codec profile configured to + encode the video. + </summary> + <aggregation> + <history> + <statistics> + <enumeration/> + </statistics> + </history> + </aggregation> + </metric> + <metric name="Status" enum="EncoderStatus"> + <summary> + media::EncoderStatus::Codes enum value. The first error status code on + error, otherwise media::EncoderStatus::Codes::kOk. + </summary> + <aggregation> + <history> + <statistics> + <enumeration/> + </statistics> + </history> + </aggregation> + </metric> + <metric name="SVCMode" enum="SVCScalabilityMode"> + <summary> + Integer value indicating the SVC configuration of the encoding. The value + corresponds to media::SVCScalabilityMode. + </summary> + <aggregation> + <history> + <statistics> + <enumeration/> + </statistics> + </history> + </aggregation> + </metric> + <metric name="UseCase" enum="VideoEncoderUseCase"> + <summary> + Integer value indicating the video encoder use case. The value corresponds + to media:::mojom::VideoEncoderUseCase. + </summary> + <aggregation> + <history> + <statistics> + <enumeration/> + </statistics> + </history> + </aggregation> + </metric> + <metric name="Width"> + <summary> + Integer value indicating the width of the encoded stream. This is bucketed + per 100 and capped by 8200. + </summary> + <aggregation> + <history> + <statistics> + <quantiles type="std-percentiles"/> + </statistics> + </history> + </aggregation> + </metric> +</event> + <event name="Media.WatchTime"> <obsolete> Deprecated 8/2017 in favor Media.BasicPlayback
diff --git a/tools/traffic_annotation/summary/annotations.xml b/tools/traffic_annotation/summary/annotations.xml index 4fd62e7..89ed8f6 100644 --- a/tools/traffic_annotation/summary/annotations.xml +++ b/tools/traffic_annotation/summary/annotations.xml
@@ -375,7 +375,7 @@ <item id="ntp_custom_background" added_in_milestone="109" content_hash_code="08080082" os_list="linux,windows,chromeos" file_path="chrome/browser/search/background/ntp_custom_background_service.cc" /> <item id="iwa_policy_update_manifest" added_in_milestone="110" second_id="iwa_update_manifest_fetcher" content_hash_code="07d65fe9" os_list="chromeos" file_path="chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_policy_manager.cc" /> <item id="iwa_policy_signed_web_bundle" added_in_milestone="110" second_id="iwa_bundle_downloader" content_hash_code="00a27db9" os_list="chromeos" file_path="chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_policy_manager.cc" /> - <item id="quick_start_challenge_bytes_fetcher" added_in_milestone="110" content_hash_code="050ba600" os_list="chromeos" file_path="chrome/browser/ash/login/oobe_quick_start/second_device_auth_broker.cc" /> + <item id="quick_start_challenge_bytes_fetcher" added_in_milestone="110" content_hash_code="0546c0a2" os_list="chromeos" file_path="chrome/browser/ash/login/oobe_quick_start/second_device_auth_broker.cc" /> <item id="customization_document" added_in_milestone="110" content_hash_code="007a3dda" os_list="chromeos" file_path="chrome/browser/ash/customization/customization_document.cc" /> <item id="nearby_webrtc_connection" added_in_milestone="110" content_hash_code="070e1f72" os_list="chromeos" file_path="chrome/services/sharing/nearby/platform/webrtc.cc" /> <item id="fenced_frame_reporting_beacon" added_in_milestone="110" content_hash_code="03fd07f7" os_list="linux,windows,android,chromeos" file_path="content/browser/fenced_frame/fenced_frame_reporter.cc" />
diff --git a/ui/accessibility/ax_tree.cc b/ui/accessibility/ax_tree.cc index f59dd94..5a2da51 100644 --- a/ui/accessibility/ax_tree.cc +++ b/ui/accessibility/ax_tree.cc
@@ -27,7 +27,6 @@ #include "base/timer/elapsed_timer.h" #include "components/crash/core/common/crash_key.h" #include "ui/accessibility/accessibility_features.h" -#include "ui/accessibility/accessibility_switches.h" #include "ui/accessibility/ax_enums.mojom.h" #include "ui/accessibility/ax_event.h" #include "ui/accessibility/ax_language_detection.h"
diff --git a/ui/accessibility/platform/ax_fragment_root_win_unittest.cc b/ui/accessibility/platform/ax_fragment_root_win_unittest.cc index 7c6ee91..ba413e7 100644 --- a/ui/accessibility/platform/ax_fragment_root_win_unittest.cc +++ b/ui/accessibility/platform/ax_fragment_root_win_unittest.cc
@@ -11,7 +11,6 @@ #include "base/win/scoped_safearray.h" #include "base/win/scoped_variant.h" #include "testing/gtest/include/gtest/gtest.h" -#include "ui/accessibility/accessibility_switches.h" #include "ui/accessibility/platform/ax_platform_node_win.h" #include "ui/accessibility/platform/ax_platform_node_win_unittest.h" #include "ui/accessibility/platform/test_ax_node_wrapper.h"
diff --git a/ui/base/ui_base_features.cc b/ui/base/ui_base_features.cc index ed01cfd..a7a25be 100644 --- a/ui/base/ui_base_features.cc +++ b/ui/base/ui_base_features.cc
@@ -438,7 +438,7 @@ // Enables chrome color management wayland protocol for lacros. BASE_FEATURE(kLacrosColorManagement, "LacrosColorManagement", - base::FEATURE_DISABLED_BY_DEFAULT); + base::FEATURE_ENABLED_BY_DEFAULT); bool IsLacrosColorManagementEnabled() { return base::FeatureList::IsEnabled(kLacrosColorManagement);
diff --git a/ui/chromeos/file_manager_strings.grdp b/ui/chromeos/file_manager_strings.grdp index 1e53071..02c8771 100644 --- a/ui/chromeos/file_manager_strings.grdp +++ b/ui/chromeos/file_manager_strings.grdp
@@ -1780,6 +1780,9 @@ Preparing to sync Drive files... </message> <!-- TODO(b/276126188): Remove the translateable="false" when the copy has been landed on. --> + <message name="IDS_FILE_BROWSER_BULK_PINNING_BATTERY_SAVER_LABEL" translateable="false" desc="The text used when the device is in battery saver mode and has paused syncing."> + Battery saver mode on. Sync will resume when battery saver mode is turned off. + </message> <message name="IDS_FILE_BROWSER_BULK_PINNING_OFFLINE_LABEL" translateable="false" desc="The text used when the device is in an offline mode and has paused syncing."> You are currently offline. Sync will resume when the connection is back on. </message> @@ -1795,6 +1798,9 @@ <message name="IDS_FILE_BROWSER_BULK_PINNING_VIEW_STORAGE" translateable="false" desc="Text of the 'View storage' link displayed next to the error message when there is not enough space to enable the Google Drive bulk pinning feature"> View storage </message> + <message name="IDS_FILE_BROWSER_BULK_PINNING_BATTERY_SAVER" translateable="false" desc="Error message displayed when the Google Drive bulk pinning feature cannot be enabled because battery saver mode is active"> + Battery saver mode on. Try again when battery saver mode is turned off. + </message> <message name="IDS_FILE_BROWSER_BULK_PINNING_OFFLINE" translateable="false" desc="Error message displayed when the Google Drive bulk pinning feature cannot be enabled because of lack of internet connection"> You are currently offline. Try again when you are connected to the internet. </message>
diff --git a/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_BULK_PINNING_BATTERY_SAVER.png.sha1 b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_BULK_PINNING_BATTERY_SAVER.png.sha1 new file mode 100644 index 0000000..e54a1905 --- /dev/null +++ b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_BULK_PINNING_BATTERY_SAVER.png.sha1
@@ -0,0 +1 @@ +88e6541e7c74fdbb07969259479cb7564c0a3fe1 \ No newline at end of file
diff --git a/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_BULK_PINNING_BATTERY_SAVER_LABEL.png.sha1 b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_BULK_PINNING_BATTERY_SAVER_LABEL.png.sha1 new file mode 100644 index 0000000..8e3cc73 --- /dev/null +++ b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_BULK_PINNING_BATTERY_SAVER_LABEL.png.sha1
@@ -0,0 +1 @@ +6548f0874c7aa3bc47013bae4235773db45226b7 \ No newline at end of file
diff --git a/ui/file_manager/file_manager/BUILD.gn b/ui/file_manager/file_manager/BUILD.gn index 920ee8c..4ac47fa 100644 --- a/ui/file_manager/file_manager/BUILD.gn +++ b/ui/file_manager/file_manager/BUILD.gn
@@ -58,6 +58,7 @@ "foreground/images/common/ic_selected.svg", "foreground/images/files/ui/arrow_right.svg", "foreground/images/files/ui/back.svg", + "foreground/images/files/ui/bulk_pinning_battery_saver.svg", "foreground/images/files/ui/bulk_pinning_done.svg", "foreground/images/files/ui/bulk_pinning_offline.svg", "foreground/images/files/ui/check.svg",
diff --git a/ui/file_manager/file_manager/common/js/util.js b/ui/file_manager/file_manager/common/js/util.js index a4306d4..c0f3aff 100644 --- a/ui/file_manager/file_manager/common/js/util.js +++ b/ui/file_manager/file_manager/common/js/util.js
@@ -1586,21 +1586,21 @@ return false; } + const BulkPinStage = chrome.fileManagerPrivate.BulkPinStage; // If the stage is in progress and the bulk pinning preference is enabled, // then the cloud panel should not be visible. if (pref && - (stage === chrome.fileManagerPrivate.BulkPinStage.GETTING_FREE_SPACE || - stage === chrome.fileManagerPrivate.BulkPinStage.LISTING_FILES || - stage === chrome.fileManagerPrivate.BulkPinStage.SYNCING)) { + (stage === BulkPinStage.GETTING_FREE_SPACE || + stage === BulkPinStage.LISTING_FILES || + stage === BulkPinStage.SYNCING)) { return true; } - // The `PAUSED` stage represents the user being offline and the - // `NOT_ENOUGH_SPACE` represents the user not having enough space on disk - // to download. For the former the preference should still be enabled, - // however, for the latter the preference will have been disabled. - if ((stage === chrome.fileManagerPrivate.BulkPinStage.PAUSED && pref) || - stage === chrome.fileManagerPrivate.BulkPinStage.NOT_ENOUGH_SPACE) { + // For the PAUSED... states the preference should still be enabled, however, + // for the latter the preference will have been disabled. + if ((stage === BulkPinStage.PAUSED_OFFLINE && pref) || + (stage === BulkPinStage.PAUSED_BATTERY_SAVER && pref) || + stage === BulkPinStage.NOT_ENOUGH_SPACE) { return true; }
diff --git a/ui/file_manager/file_manager/containers/cloud_panel_container.ts b/ui/file_manager/file_manager/containers/cloud_panel_container.ts index e13cd80..b8dcd584 100644 --- a/ui/file_manager/file_manager/containers/cloud_panel_container.ts +++ b/ui/file_manager/file_manager/containers/cloud_panel_container.ts
@@ -97,12 +97,15 @@ } // If the bulk pinning is paused, this indicates that it is currently - // offline. This could be from either the network not being connected or - // cellular being disabled for syncing. - if (bulkPinProgress.stage === BulkPinStage.PAUSED) { + // offline or battery saver mode is active. + if (bulkPinProgress.stage === BulkPinStage.PAUSED_OFFLINE) { this.updatePanelType_(CloudPanelType.OFFLINE); return; } + if (bulkPinProgress.stage === BulkPinStage.PAUSED_BATTERY_SAVER) { + this.updatePanelType_(CloudPanelType.BATTERY_SAVER); + return; + } // Not enough space indicates the available local storage is insufficient to // store all the files required by the users My drive.
diff --git a/ui/file_manager/file_manager/containers/cloud_panel_container_unittest.ts b/ui/file_manager/file_manager/containers/cloud_panel_container_unittest.ts index 564f3f5..3244f9e 100644 --- a/ui/file_manager/file_manager/containers/cloud_panel_container_unittest.ts +++ b/ui/file_manager/file_manager/containers/cloud_panel_container_unittest.ts
@@ -312,20 +312,31 @@ // Pausing the bulk pinning operation does not update the attributes except // changing the type attribute to offline. store.dispatch(updateBulkPinProgress( - {...bulkPinning, pinnedBytes: 200, stage: BulkPinStage.PAUSED})); + {...bulkPinning, pinnedBytes: 200, stage: BulkPinStage.PAUSED_OFFLINE})); assertEquals( container!.updates, 2, 'Bulk pin state stage should increment updates to 2'); assertEquals(panel!.getAttribute('type'), 'offline'); assertFalse(panel!.hasAttribute('items')); assertFalse(panel!.hasAttribute('percentage')); + store.dispatch(updateBulkPinProgress({ + ...bulkPinning, + pinnedBytes: 200, + stage: BulkPinStage.PAUSED_BATTERY_SAVER, + })); + assertEquals( + container!.updates, 3, + 'Bulk pin state stage should increment updates to 3'); + assertEquals(panel!.getAttribute('type'), 'battery_saver'); + assertFalse(panel!.hasAttribute('items')); + assertFalse(panel!.hasAttribute('percentage')); // Switching back into `SYNCING` with new pinned bytes removes the type // attribute and updates the attributes. store.dispatch(updateBulkPinProgress({...bulkPinning, pinnedBytes: 300})); assertEquals( - container!.updates, 3, - 'Bulk pin state stage should increment updates to 3'); + container!.updates, 4, + 'Bulk pin state stage should increment updates to 4'); assertFalse(panel!.hasAttribute('type')); assertEquals(panel!.getAttribute('items'), '10'); assertEquals(panel!.getAttribute('percentage'), '30');
diff --git a/ui/file_manager/file_manager/foreground/css/file_manager_gm3.css b/ui/file_manager/file_manager/foreground/css/file_manager_gm3.css index 6deccea..5534e9a5 100644 --- a/ui/file_manager/file_manager/foreground/css/file_manager_gm3.css +++ b/ui/file_manager/file_manager/foreground/css/file_manager_gm3.css
@@ -1244,7 +1244,8 @@ /* Only display outlines for entries with thumbnails. */ #list-container.thumbnail-view li:has(.thumbnail) .inline-status .progress, -#list-container.thumbnail-view li.pinned:has(.thumbnail) .inline-status xf-icon[type=offline] { +#list-container.thumbnail-view li.pinned:has(.thumbnail) .inline-status xf-icon[type=offline], +#list-container.thumbnail-view li.cant-pin:has(.thumbnail) .inline-status xf-icon[type=cant-pin] { --xf-icon-color-outline: var(--cros-sys-app_base); }
diff --git a/ui/file_manager/file_manager/foreground/images/files/ui/bulk_pinning_battery_saver.svg b/ui/file_manager/file_manager/foreground/images/files/ui/bulk_pinning_battery_saver.svg new file mode 100644 index 0000000..7c5bcd29 --- /dev/null +++ b/ui/file_manager/file_manager/foreground/images/files/ui/bulk_pinning_battery_saver.svg
@@ -0,0 +1,3 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48"> + <path d="m38.1 38-3.6-3.6-16.2-16.2-2.9-2.9-8-8-2.8 2.9 7 7a10.8 10.8 0 0 0 2.7 21.2h18.5l5.1 5.1 2.8-2.8-2.6-2.7Zm-23.9-3.7a6.8 6.8 0 0 1 0-13.5h1l13.6 13.5Zm22.1-13.8a11.9 11.9 0 0 0-17.9-7.8l3 2.9a7.8 7.8 0 0 1 3.3-.7 7.9 7.9 0 0 1 7.9 7.6v2h3a5 5 0 0 1 5 4.9 4.9 4.9 0 0 1-1.7 3.7l2.8 2.8a9 9 0 0 0-5.3-15.4Z"/> +</svg> \ No newline at end of file
diff --git a/ui/file_manager/file_manager/foreground/images/files/ui/cant_pin.svg b/ui/file_manager/file_manager/foreground/images/files/ui/cant_pin.svg index 979a6f7d..e2832e5 100644 --- a/ui/file_manager/file_manager/foreground/images/files/ui/cant_pin.svg +++ b/ui/file_manager/file_manager/foreground/images/files/ui/cant_pin.svg
@@ -1 +1,4 @@ -<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="enable-background:new 0 0 16 16" viewBox="0 0 16 16"><path d="M2 6.2h12v3.6H2z"/><path d="M3 7.2h10v1.6H3z"/></svg> \ No newline at end of file +<svg id="cant_pin" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="enable-background:new 0 0 16 16" viewBox="0 0 16 16"> + <path d="M2 6.2h12v3.6H2z" style="fill: var(--xf-icon-color-outline, transparent);"/> + <path d="M3 7.2h10v1.6H3z" style="fill: var(--xf-icon-color);"/> +</svg> \ No newline at end of file
diff --git a/ui/file_manager/file_manager/foreground/js/constants.js b/ui/file_manager/file_manager/foreground/js/constants.js index 8612eeae..d70c1846 100644 --- a/ui/file_manager/file_manager/foreground/js/constants.js +++ b/ui/file_manager/file_manager/foreground/js/constants.js
@@ -131,6 +131,7 @@ ARCHIVE: 'archive', AUDIO: 'audio', BRUSCHETTA: 'bruschetta', + BULK_PINNING_BATTERY_SAVER: 'bulk_pinning_battery_saver', BULK_PINNING_DONE: 'bulk_pinning_done', BULK_PINNING_OFFLINE: 'bulk_pinning_offline', CAMERA_FOLDER: 'camera-folder',
diff --git a/ui/file_manager/file_manager/foreground/js/toolbar_controller.js b/ui/file_manager/file_manager/foreground/js/toolbar_controller.js index c2a1d50..fdcfdca 100644 --- a/ui/file_manager/file_manager/foreground/js/toolbar_controller.js +++ b/ui/file_manager/file_manager/foreground/js/toolbar_controller.js
@@ -575,7 +575,9 @@ updateBulkPinningFolderIndicator_(currentDirectory, stage) { if (currentDirectory?.rootType === VolumeManagerCommon.RootType.DRIVE && (stage === chrome.fileManagerPrivate.BulkPinStage.SYNCING || - stage === chrome.fileManagerPrivate.BulkPinStage.PAUSED)) { + stage === chrome.fileManagerPrivate.BulkPinStage.PAUSED_OFFLINE || + stage === + chrome.fileManagerPrivate.BulkPinStage.PAUSED_BATTERY_SAVER)) { this.cloudOfflineFolderIndicator_.hidden = false; return; } @@ -605,12 +607,18 @@ this.cloudStatusIcon_.setAttribute( 'type', constants.ICON_TYPES.CLOUD_ERROR); break; - case chrome.fileManagerPrivate.BulkPinStage.PAUSED: + case chrome.fileManagerPrivate.BulkPinStage.PAUSED_OFFLINE: this.cloudButtonIcon_.setAttribute( 'type', constants.ICON_TYPES.BULK_PINNING_OFFLINE); this.cloudStatusIcon_.removeAttribute('type'); this.cloudStatusIcon_.removeAttribute('size'); break; + case chrome.fileManagerPrivate.BulkPinStage.PAUSED_BATTERY_SAVER: + this.cloudButtonIcon_.setAttribute( + 'type', constants.ICON_TYPES.BULK_PINNING_BATTERY_SAVER); + this.cloudStatusIcon_.removeAttribute('type'); + this.cloudStatusIcon_.removeAttribute('size'); + break; default: this.cloudButtonIcon_.setAttribute('type', constants.ICON_TYPES.CLOUD); this.cloudStatusIcon_.removeAttribute('type');
diff --git a/ui/file_manager/file_manager/widgets/xf_bulk_pinning_dialog.ts b/ui/file_manager/file_manager/widgets/xf_bulk_pinning_dialog.ts index bd3d402..7ce5f1a 100644 --- a/ui/file_manager/file_manager/widgets/xf_bulk_pinning_dialog.ts +++ b/ui/file_manager/file_manager/widgets/xf_bulk_pinning_dialog.ts
@@ -20,6 +20,9 @@ // Currently offline. Cannot compute space requirement for the time being. OFFLINE, + // Currently not running due to battery saver mode active. + BATTERY_SAVER, + // Listing files and computing space requirements. LISTING, @@ -44,6 +47,7 @@ @query('cr-dialog') private $dialog_!: CrDialogElement; @query('#continue-button') private $button_!: CrButtonElement; @query('#offline-footer') private $offlineFooter_!: HTMLElement; + @query('#battery-saver-footer') private $batterySaverFooter_!: HTMLElement; @query('#listing-footer') private $listingFooter_!: HTMLElement; @query('#error-footer') private $errorFooter_!: HTMLElement; @query('#not-enough-space-footer') @@ -85,10 +89,14 @@ this.stage_ = bpp.stage; switch (bpp.stage) { - case BulkPinStage.PAUSED: + case BulkPinStage.PAUSED_OFFLINE: this.state = DialogState.OFFLINE; break; + case BulkPinStage.PAUSED_BATTERY_SAVER: + this.state = DialogState.BATTERY_SAVER; + break; + case BulkPinStage.GETTING_FREE_SPACE: case BulkPinStage.LISTING_FILES: this.state = DialogState.LISTING; @@ -119,6 +127,8 @@ set state(s: DialogState) { this.$offlineFooter_.style.display = s === DialogState.OFFLINE ? 'initial' : 'none'; + this.$batterySaverFooter_.style.display = + s === DialogState.BATTERY_SAVER ? 'initial' : 'none'; this.$listingFooter_.style.display = s === DialogState.LISTING ? 'flex' : 'none'; this.$errorFooter_.style.display = @@ -196,6 +206,9 @@ <div id="offline-footer" class="offline-footer"> ${str('BULK_PINNING_OFFLINE')} </div> + <div id="battery-saver-footer" class="battery-saver-footer"> + ${str('BULK_PINNING_BATTERY_SAVER')} + </div> <div id="listing-footer" class="normal-footer"> <files-spinner></files-spinner> ${str('BULK_PINNING_LISTING')} @@ -304,7 +317,7 @@ padding: 16px; } - .offline-footer { + .offline-footer, .battery-saver-footer { background-color: var(--cros-sys-surface_variant); border: 1px solid var(--cros-separator-color); border-radius: 0 0 12px 12px;
diff --git a/ui/file_manager/file_manager/widgets/xf_cloud_panel.ts b/ui/file_manager/file_manager/widgets/xf_cloud_panel.ts index 1881643..018b2f0 100644 --- a/ui/file_manager/file_manager/widgets/xf_cloud_panel.ts +++ b/ui/file_manager/file_manager/widgets/xf_cloud_panel.ts
@@ -21,6 +21,7 @@ */ export enum CloudPanelType { OFFLINE = 'offline', + BATTERY_SAVER = 'battery_saver', NOT_ENOUGH_SPACE = 'not_enough_space', } @@ -28,8 +29,8 @@ * The `<xf-cloud-panel>` represents the current state that the Drive bulk * pinning process is currently in. When files are being pinned and downloaded, * the `items` and `progress` attributes are used to signify that the panel is - * in progress. The `type` attribute can be used with `not_enough_space` and - * `offline` to signify possible error or paused states. + * in progress. The `type` attribute can be used with `not_enough_space`, + * `offline`, and `battery_saver` to signify possible error or paused states. */ @customElement('xf-cloud-panel') export class XfCloudPanel extends XfBase { @@ -205,6 +206,14 @@ ${str('DRIVE_BULK_PINNING_OFFLINE')} </div> </div> + <div class="static" id="progress-battery-saver"> + <xf-icon type="${ + constants.ICON_TYPES + .BULK_PINNING_BATTERY_SAVER}" size="large"></xf-icon> + <div class="status-description"> + ${str('DRIVE_BULK_PINNING_BATTERY_SAVER')} + </div> + </div> <div class="static" id="progress-not-enough-space"> <xf-icon type="${ constants.ICON_TYPES.ERROR_BANNER}" size="large"></xf-icon> @@ -254,6 +263,10 @@ display: none; } + :host(:not([type="battery_saver"])) #progress-battery-saver { + display: none; + } + :host(:not([type="not_enough_space"])) #progress-not-enough-space { display: none; } @@ -284,6 +297,10 @@ --xf-icon-color: var(--cros-sys-secondary); } + xf-icon[type="bulk_pinning_battery_saver"] { + --xf-icon-color: var(--cros-sys-secondary); + } + xf-icon[type="error_banner"] { --xf-icon-color: var(--cros-sys-error); }
diff --git a/ui/file_manager/file_manager/widgets/xf_icon.ts b/ui/file_manager/file_manager/widgets/xf_icon.ts index f7bf728..76470b5 100644 --- a/ui/file_manager/file_manager/widgets/xf_icon.ts +++ b/ui/file_manager/file_manager/widgets/xf_icon.ts
@@ -39,8 +39,8 @@ static get multiColor() { return { - [constants.ICON_TYPES.OFFLINE]: - svg`<use xlink:href="foreground/images/files/ui/offline.svg#offline"></use>`, + [constants.ICON_TYPES.CANT_PIN]: + svg`<use xlink:href="foreground/images/files/ui/cant_pin.svg#cant_pin"></use>`, [constants.ICON_TYPES.CLOUD_DONE]: svg`<use xlink:href="foreground/images/files/ui/cloud_done.svg#cloud_done"></use>`, [constants.ICON_TYPES.CLOUD_ERROR]: @@ -55,6 +55,8 @@ svg`<use xlink:href="foreground/images/files/ui/encrypted.svg#encrypted"></use>`, [constants.ICON_TYPES.ERROR]: svg`<use xlink:href="foreground/images/files/ui/error.svg#error"></use>`, + [constants.ICON_TYPES.OFFLINE]: + svg`<use xlink:href="foreground/images/files/ui/offline.svg#offline"></use>`, }; } @@ -194,10 +196,6 @@ -webkit-mask-image: url(../foreground/images/volumes/camera.svg); } - :host([type="cant-pin"]) span { - -webkit-mask-image: url(../foreground/images/files/ui/cant_pin.svg); - } - :host([type="computer"]) span { -webkit-mask-image: url(../foreground/images/volumes/computer.svg); } @@ -376,6 +374,10 @@ -webkit-mask-image: url(../foreground/images/files/ui/check.svg); } + :host([type="bulk_pinning_battery_saver"]) span { + -webkit-mask-image: url(../foreground/images/files/ui/bulk_pinning_battery_saver.svg); + } + :host([type="bulk_pinning_done"]) span { -webkit-mask-image: url(../foreground/images/files/ui/bulk_pinning_done.svg); }
diff --git a/ui/file_manager/integration_tests/file_manager/toolbar.js b/ui/file_manager/integration_tests/file_manager/toolbar.js index ac52847e..d490bfb 100644 --- a/ui/file_manager/integration_tests/file_manager/toolbar.js +++ b/ui/file_manager/integration_tests/file_manager/toolbar.js
@@ -586,7 +586,7 @@ await sendTestMessage({name: 'forceBulkPinningCalculateRequiredSpace'}); // Assert the stage is `PAUSED` and the cloud button is still hidden. - await remoteCall.waitForBulkPinningStage('Paused'); + await remoteCall.waitForBulkPinningStage('PausedOffline'); await remoteCall.waitForElement(appId, '#cloud-button[hidden]'); await remoteCall.waitForElement(appId, '#offline-folder-indicator[hidden]'); }; @@ -606,12 +606,13 @@ await sendTestMessage({name: 'setBulkPinningEnabledPref', enabled: true}); // Set the bulk pinning manager to enter offline mode. This will surface a - // `PAUSED` state which has a UI representation iff the pref is enabled. + // `PAUSED_OFFLINE` state which has a UI representation iff the pref is + // enabled. await sendTestMessage({name: 'setBulkPinningOnline', enabled: false}); - // Assert the stage is `PAUSED`, the cloud button is visible and the icon is - // the offline icon. - await remoteCall.waitForBulkPinningStage('Paused'); + // Assert the stage is `PAUSED_OFFLINE`, the cloud button is visible and the + // icon is the offline icon. + await remoteCall.waitForBulkPinningStage('PausedOffline'); await remoteCall.waitForElement(appId, '#cloud-button:not([hidden])'); await remoteCall.waitForElement( appId, '#offline-folder-indicator:not([hidden])');
diff --git a/ui/views/accessibility/view_ax_platform_node_delegate_win.cc b/ui/views/accessibility/view_ax_platform_node_delegate_win.cc index e08110e..ed1ce78 100644 --- a/ui/views/accessibility/view_ax_platform_node_delegate_win.cc +++ b/ui/views/accessibility/view_ax_platform_node_delegate_win.cc
@@ -14,7 +14,6 @@ #include "base/strings/utf_string_conversions.h" #include "base/win/windows_version.h" #include "third_party/iaccessible2/ia2_api_all.h" -#include "ui/accessibility/accessibility_switches.h" #include "ui/accessibility/ax_node_data.h" #include "ui/accessibility/ax_text_utils.h" #include "ui/accessibility/platform/ax_fragment_root_win.h"
diff --git a/ui/views/controls/textfield/textfield.cc b/ui/views/controls/textfield/textfield.cc index 2166ed4..7323629 100644 --- a/ui/views/controls/textfield/textfield.cc +++ b/ui/views/controls/textfield/textfield.cc
@@ -773,21 +773,18 @@ case ui::ET_GESTURE_TAP: { RequestFocusForGesture(event->details()); if (controller_ && controller_->HandleGestureEvent(this, *event)) { - selection_dragging_state_ = SelectionDraggingState::kNone; + StopSelectionDragging(); event->SetHandled(); return; } - + if (HandleGestureForSelectionDragging(event)) { + return; + } const size_t tap_pos = GetRenderText()->FindCursorPosition(event->location()).caret_pos(); const bool should_toggle_menu = event->details().tap_count() == 1 && GetSelectedRange() == gfx::Range(tap_pos); - if (selection_dragging_state_ != SelectionDraggingState::kNone) { - // Selection has already been set in the preceding ET_GESTURE_TAP_DOWN - // event, so handles should be shown without changing the selection. - // Just need to cancel selection dragging. - selection_dragging_state_ = SelectionDraggingState::kNone; - } else if (event->details().tap_count() == 1) { + if (event->details().tap_count() == 1) { // If tap is on the selection and touch handles are not present, // handles should be shown without changing selection. Otherwise, // cursor should be moved to the tap location. @@ -814,52 +811,45 @@ break; } case ui::ET_GESTURE_TAP_DOWN: { - if (::features::IsTouchTextEditingRedesignEnabled() && HasFocus()) { - if (event->details().tap_down_count() == 2) { - OnBeforeUserAction(); - SelectWordAt(event->location()); - OnAfterUserAction(); - } else if (event->details().tap_down_count() == 3) { - OnBeforeUserAction(); - SelectAll(false); - OnAfterUserAction(); - } else { - break; + if (HasFocus()) { + if (HandleGestureForSelectionDragging(event)) { + return; } - DestroyTouchSelection(); - selection_dragging_state_ = - SelectionDraggingState::kDraggingSelectionExtent; - event->SetHandled(); } break; } case ui::ET_GESTURE_LONG_PRESS: - if (!GetRenderText()->IsPointInSelection(event->location())) { + if (GetRenderText()->IsPointInSelection(event->location())) { + // If long-press happens on the selection, deactivate touch selection + // and try to initiate drag-drop. If drag-drop is not enabled, context + // menu will be shown. Event is not marked as handled to let Views + // handle drag-drop or context menu. + DestroyTouchSelection(); + StopSelectionDragging(); + initiating_drag_ = switches::IsTouchDragDropEnabled(); + break; + } else { // If long-press happens outside selection, select word and try to // activate touch selection. OnBeforeUserAction(); SelectWordAt(event->location()); OnAfterUserAction(); CreateTouchSelectionControllerAndNotifyIt(); - if (::features::IsTouchTextEditingRedesignEnabled()) { - selection_dragging_state_ = - SelectionDraggingState::kDraggingSelectionExtent; + + if (HandleGestureForSelectionDragging(event)) { + return; } - // If touch selection activated successfully, mark event as handled - // so that the regular context menu is not shown. - if (touch_selection_controller_) + + // If touch selection is activated, mark the event as handled so that + // the regular context menu is not shown. + if (touch_selection_controller_) { event->SetHandled(); - } else { - // If long-press happens on the selection, deactivate touch - // selection and try to initiate drag-drop. If drag-drop is not - // enabled, context menu will be shown. Event is not marked as - // handled to let Views handle drag-drop or context menu. - DestroyTouchSelection(); - initiating_drag_ = switches::IsTouchDragDropEnabled(); + return; + } } break; case ui::ET_GESTURE_LONG_TAP: - selection_dragging_state_ = SelectionDraggingState::kNone; + StopSelectionDragging(); // If touch selection is enabled, the context menu on long tap will be // shown by the |touch_selection_controller_|, hence we mark the event // handled so Views does not try to show context menu on it. @@ -868,63 +858,28 @@ break; case ui::ET_GESTURE_SCROLL_BEGIN: if (HasFocus()) { - if (::features::IsTouchTextEditingRedesignEnabled()) { - MaybeStartSelectionDragging(event); + if (HandleGestureForSelectionDragging(event)) { + return; } - if (selection_dragging_state_ == SelectionDraggingState::kNone) { - drag_start_location_x_ = event->location().x(); - drag_start_display_offset_ = - GetRenderText()->GetUpdatedDisplayOffset().x(); - show_touch_handles_after_scroll_ = - touch_selection_controller_ != nullptr; - // Deactivate touch selection controller when scrolling. - DestroyTouchSelection(); - } else { - // Create touch selection controller to show a magnifier when - // selection dragging. - CreateTouchSelectionControllerAndNotifyIt(); - show_touch_handles_after_scroll_ = true; - } + OnGestureScrollBegin(event->location().x()); event->SetHandled(); } break; case ui::ET_GESTURE_SCROLL_UPDATE: if (HasFocus()) { - // Switch from selection dragging to default scrolling behaviour if - // scroll update has multiple touch points. - if (selection_dragging_state_ != SelectionDraggingState::kNone && - event->details().touch_points() > 1) { - selection_dragging_state_ = SelectionDraggingState::kNone; - drag_start_location_x_ = event->location().x(); - drag_start_display_offset_ = - GetRenderText()->GetUpdatedDisplayOffset().x(); - DestroyTouchSelection(); - show_touch_handles_after_scroll_ = true; + if (HandleGestureForSelectionDragging(event)) { + return; } - switch (selection_dragging_state_) { - case SelectionDraggingState::kDraggingSelectionExtent: - MoveRangeSelectionExtent(event->location() + - selection_dragging_offset_); - break; - case SelectionDraggingState::kDraggingCursor: - MoveCursorTo(event->location(), false); - break; - case SelectionDraggingState::kNone: { - int new_display_offset = drag_start_display_offset_ + - event->location().x() - - drag_start_location_x_; - GetRenderText()->SetDisplayOffset(new_display_offset); - SchedulePaint(); - break; - } - } + GestureScroll(event->location().x()); event->SetHandled(); } break; case ui::ET_GESTURE_SCROLL_END: case ui::ET_SCROLL_FLING_START: + if (HandleGestureForSelectionDragging(event)) { + return; + } if (HasFocus()) { - selection_dragging_state_ = SelectionDraggingState::kNone; if (show_touch_handles_after_scroll_) { CreateTouchSelectionControllerAndNotifyIt(); show_touch_handles_after_scroll_ = false; @@ -933,7 +888,9 @@ } break; case ui::ET_GESTURE_END: - selection_dragging_state_ = SelectionDraggingState::kNone; + if (HandleGestureForSelectionDragging(event)) { + return; + } break; default: return; @@ -2961,18 +2918,108 @@ ShapeContextTokens::kTextfieldRadius, size()); } -void Textfield::MaybeStartSelectionDragging(ui::GestureEvent* event) { - DCHECK_EQ(event->type(), ui::ET_GESTURE_SCROLL_BEGIN); - // Only start selection dragging if scrolling with one touch point. - if (event->details().touch_points() > 1) { - selection_dragging_state_ = SelectionDraggingState::kNone; - return; +void Textfield::OnGestureScrollBegin(int drag_start_location_x) { + drag_start_location_x_ = drag_start_location_x; + drag_start_display_offset_ = GetRenderText()->GetUpdatedDisplayOffset().x(); + show_touch_handles_after_scroll_ = touch_selection_controller_ != nullptr; + DestroyTouchSelection(); +} + +void Textfield::GestureScroll(int drag_location_x) { + int new_display_offset = + drag_start_display_offset_ + drag_location_x - drag_start_location_x_; + GetRenderText()->SetDisplayOffset(new_display_offset); + SchedulePaint(); +} + +bool Textfield::HandleGestureForSelectionDragging(ui::GestureEvent* event) { + if (!::features::IsTouchTextEditingRedesignEnabled()) { + return false; } - const float delta_x = event->details().scroll_x_hint(); - const float delta_y = event->details().scroll_y_hint(); - if (selection_dragging_state_ == - SelectionDraggingState::kDraggingSelectionExtent) { + switch (event->type()) { + case ui::ET_GESTURE_TAP: + if (selection_dragging_state_ != SelectionDraggingState::kNone) { + // Selection has already been set in preceding events, so we can just + // cancel selection dragging and show touch handles without changing the + // selection. + StopSelectionDragging(); + CreateTouchSelectionControllerAndNotifyIt(); + event->SetHandled(); + return true; + } + return false; + case ui::ET_GESTURE_TAP_DOWN: + if (event->details().tap_down_count() == 1) { + selection_dragging_state_ = SelectionDraggingState::kNone; + return false; + } else if (event->details().tap_down_count() == 2) { + OnBeforeUserAction(); + SelectWordAt(event->location()); + OnAfterUserAction(); + selection_dragging_state_ = SelectionDraggingState::kSelectedWord; + } else if (event->details().tap_down_count() == 3) { + OnBeforeUserAction(); + SelectAll(false); + OnAfterUserAction(); + selection_dragging_state_ = SelectionDraggingState::kSelectedAll; + } + DestroyTouchSelection(); + event->SetHandled(); + return true; + case ui::ET_GESTURE_LONG_PRESS: + selection_dragging_state_ = SelectionDraggingState::kSelectedWord; + event->SetHandled(); + return true; + case ui::ET_GESTURE_SCROLL_BEGIN: + // Only start selection dragging if scrolling with one touch point. + if (event->details().touch_points() == 1 && + StartSelectionDragging(*event)) { + CreateTouchSelectionControllerAndNotifyIt(); + show_touch_handles_after_scroll_ = true; + event->SetHandled(); + return true; + } + StopSelectionDragging(); + return false; + case ui::ET_GESTURE_SCROLL_UPDATE: + // Switch from selection dragging to default scrolling behaviour if scroll + // update has multiple touch points. + if (IsSelectionDragging() && event->details().touch_points() > 1) { + StopSelectionDragging(); + OnGestureScrollBegin(event->location().x()); + return false; + } else if (selection_dragging_state_ == + SelectionDraggingState::kDraggingSelectionExtent) { + MoveRangeSelectionExtent(event->location() + + selection_dragging_offset_); + event->SetHandled(); + return true; + } else if (selection_dragging_state_ == + SelectionDraggingState::kDraggingCursor) { + MoveCursorTo(event->location(), false); + event->SetHandled(); + return true; + } + return false; + case ui::ET_GESTURE_SCROLL_END: + case ui::ET_SCROLL_FLING_START: + StopSelectionDragging(); + return false; + case ui::ET_GESTURE_END: + StopSelectionDragging(); + return false; + default: + return false; + } +} + +bool Textfield::StartSelectionDragging(const ui::GestureEvent& event) { + DCHECK_EQ(event.type(), ui::ET_GESTURE_SCROLL_BEGIN); + + const float delta_x = event.details().scroll_x_hint(); + const float delta_y = event.details().scroll_y_hint(); + if (selection_dragging_state_ == SelectionDraggingState::kSelectedWord) { gfx::RenderText* render_text = GetRenderText(); gfx::SelectionModel start_sel = render_text->GetSelectionModelForSelectionStart(); @@ -2984,12 +3031,12 @@ gfx::LogicalCursorDirection drag_direction = gfx::CURSOR_FORWARD; if (std::fabs(delta_y) > std::fabs(delta_x)) { - // If the initial dragging motion is up/down, extend the - // selection backwards/forwards. + // If the initial dragging motion is up/down, extend the selection + // backwards/forwards. drag_direction = delta_y < 0 ? gfx::CURSOR_BACKWARD : gfx::CURSOR_FORWARD; } else { - // Otherwise, extend the selection in the direction of - // horizontal movement. + // Otherwise, extend the selection in the direction of horizontal + // movement. drag_direction = delta_x * (selection_end.x() - selection_start.x()) < 0 ? gfx::CURSOR_BACKWARD : gfx::CURSOR_FORWARD; @@ -3000,13 +3047,23 @@ gfx::Point extent = drag_direction == gfx::CURSOR_FORWARD ? selection_end : selection_start; SelectBetweenCoordinates(base, extent); - selection_dragging_offset_ = extent - event->location(); - } else if (std::fabs(delta_x) >= std::fabs(delta_y)) { - // Use the scroll sequence for cursor placement if it begins in a - // horizontal direction and is not already being used for dragging - // the selection. + + selection_dragging_offset_ = extent - event.location(); + selection_dragging_state_ = + SelectionDraggingState::kDraggingSelectionExtent; + return true; + } else if (selection_dragging_state_ == SelectionDraggingState::kNone && + std::fabs(delta_x) >= std::fabs(delta_y)) { + // Only start dragging the cursor if the gesture begins in a horizontal + // direction. selection_dragging_state_ = SelectionDraggingState::kDraggingCursor; + return true; } + return false; +} + +void Textfield::StopSelectionDragging() { + selection_dragging_state_ = SelectionDraggingState::kNone; } BEGIN_METADATA(Textfield, View)
diff --git a/ui/views/controls/textfield/textfield.h b/ui/views/controls/textfield/textfield.h index e87e208..b486a86 100644 --- a/ui/views/controls/textfield/textfield.h +++ b/ui/views/controls/textfield/textfield.h
@@ -668,12 +668,23 @@ // Returns the corner radius of the text field. float GetCornerRadius(); - // Checks and updates the selection dragging state for the upcoming scroll - // sequence, if required. If the scroll sequence starts while long pressing, - // it will be used for adjusting the text selection. Otherwise, if the scroll - // begins horizontally it will be used for cursor placement. Otherwise, the - // scroll sequence won't be used for selection dragging. - void MaybeStartSelectionDragging(ui::GestureEvent* event); + // Prepares the Textfield for gesture scrolling by setting the drag start + // state. + void OnGestureScrollBegin(int drag_start_location_x); + + // Performs gesture scrolling. + void GestureScroll(int drag_location_x); + + // Performs gesture handling needed for touch selection dragging. Sets `event` + // as handled and returns true if the event should not be processed further. + bool HandleGestureForSelectionDragging(ui::GestureEvent* event); + + // Determines whether touch selection dragging should start and updates the + // selection dragging state if needed. Returns true if selection dragging + // starts. + bool StartSelectionDragging(const ui::GestureEvent& event); + + void StopSelectionDragging(); // The text model. std::unique_ptr<TextfieldModel> model_; @@ -761,10 +772,13 @@ SelectionController selection_controller_; - // Tracks when the current scroll sequence should be used for cursor placement + // Tracks the touch selection dragging state which is used when determining + // whether a dragging movement should be used for scrolling, cursor placement // or adjusting the text selection. enum class SelectionDraggingState { kNone, + kSelectedAll, + kSelectedWord, kDraggingCursor, kDraggingSelectionExtent };