diff --git a/.eslintrc.js b/.eslintrc.js index 5b2eafc..9b682b6 100644 --- a/.eslintrc.js +++ b/.eslintrc.js
@@ -93,11 +93,22 @@ { selector: 'classProperty', format: ['UPPER_CASE'], - modifiers: ['static', 'readonly'], + modifiers: ['private', 'static', 'readonly'], + }, + { + selector: 'classProperty', + format: ['UPPER_CASE'], + modifiers: ['public', 'static', 'readonly'], }, { selector: 'classProperty', format: ['camelCase'], + modifiers: ['public'], + }, + { + selector: 'classProperty', + format: ['camelCase'], + modifiers: ['private'], trailingUnderscore: 'allow', }, {
diff --git a/DEPS b/DEPS index b0343bd..a85acaed 100644 --- a/DEPS +++ b/DEPS
@@ -280,11 +280,11 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and whatever else without interference from each other. - 'skia_revision': '78c1845e6655428ab6f9b35fecf3d3d1032b5348', + 'skia_revision': '1f6b4de4014784409325b051604e2f9b5b9537e7', # 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': '9a3e0afbcd224b74d03f2e6b1dbcc2110c98c28e', + 'v8_revision': 'dc48e6496209f29b87b58bbcd6a6ebfcc64eb0df', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ANGLE # and whatever else without interference from each other. @@ -359,7 +359,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': '45cde6c2f5bfb8e12c81528092edfd7b1429e492', + 'devtools_frontend_revision': '5780a775c90505c63824d50d414fd82b9c68b514', # 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. @@ -395,7 +395,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': '6d48f573af6004ce4243c97745562a270de9c0e4', + 'dawn_revision': '6d200d53eebe92cc23d358d9cd8b378cabc5ce15', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -439,7 +439,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. - 'libcxxabi_revision': 'bb4dcb7164a67f828225714c7ed099cfe418d3d7', + 'libcxxabi_revision': '2dba7d2cc46a25cd67fb990826179e0c159c5b5c', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -780,7 +780,7 @@ }, 'src/ios/third_party/material_components_ios/src': { - 'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + '4ca68941b8b4b7a02ebf2e3902168196f4122135', + 'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + 'c6d4682d323ed098f4a5265a1f264531f4a251f6', 'condition': 'checkout_ios', }, @@ -929,7 +929,7 @@ 'packages': [ { 'package': 'chromium/third_party/androidx', - 'version': 'oRZBRiYR93sr5l0V68UgLgP_K7BSeq12h0dvFXdyLkEC', + 'version': 'ffRu7ou3A-tWC0cp9INlqplJN090p9v3saKCut6KJZ8C', }, ], 'condition': 'checkout_android', @@ -1542,7 +1542,7 @@ }, 'src/third_party/perfetto': - Var('android_git') + '/platform/external/perfetto.git' + '@' + '29c99a813c0b03800cc2b06f521d9dfbf590194b', + Var('android_git') + '/platform/external/perfetto.git' + '@' + 'ddc88694c41b71562428bd08b168666c8d42eaf3', 'src/third_party/perl': { 'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3', @@ -1712,7 +1712,7 @@ Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '49e659bea564367588238bd5e88a554014956064', 'src/third_party/webrtc': - Var('webrtc_git') + '/src.git' + '@' + '932d0799374774d397bf28be9deabac31f7260b6', + Var('webrtc_git') + '/src.git' + '@' + '67d2d35443c32e84880f52e7af41cc209be63833', 'src/third_party/libgifcodec': Var('skia_git') + '/libgifcodec' + '@'+ Var('libgifcodec_revision'),
diff --git a/android_webview/BUILD.gn b/android_webview/BUILD.gn index 8fa1491..054b38c 100644 --- a/android_webview/BUILD.gn +++ b/android_webview/BUILD.gn
@@ -807,7 +807,6 @@ "//services/network/public:features_java", "//third_party/androidx:androidx_annotation_annotation_java", "//third_party/blink/public/common:common_java", - "//third_party/webrtc_overrides:webrtc_overrides_java", ] srcjar_deps = [ ":common_java_features_srcjar",
diff --git a/android_webview/browser/gfx/output_surface_provider_webview.cc b/android_webview/browser/gfx/output_surface_provider_webview.cc index 4e2c33f..12555ab 100644 --- a/android_webview/browser/gfx/output_surface_provider_webview.cc +++ b/android_webview/browser/gfx/output_surface_provider_webview.cc
@@ -25,7 +25,6 @@ #include "gpu/ipc/single_task_sequence.h" #include "ui/base/ui_base_switches.h" #include "ui/gfx/geometry/size.h" -#include "ui/gl/gl_bindings.h" #include "ui/gl/gl_context.h" #include "ui/gl/gl_share_group.h" #include "ui/gl/gl_surface_egl.h" @@ -113,7 +112,7 @@ // If EGL supports EGL_ANGLE_external_context_and_surface, then we will create // an ANGLE context for the current native GL context. const bool is_angle = - !enable_vulkan_ && display->ext->b_EGL_ANGLE_external_context_and_surface; + !enable_vulkan_ && display->IsANGLEExternalContextAndSurfaceSupported(); GLSurfaceContextPair real_context; if (enable_vulkan_) {
diff --git a/android_webview/browser/gfx/scoped_app_gl_state_restore.cc b/android_webview/browser/gfx/scoped_app_gl_state_restore.cc index 35305c1..1289f30 100644 --- a/android_webview/browser/gfx/scoped_app_gl_state_restore.cc +++ b/android_webview/browser/gfx/scoped_app_gl_state_restore.cc
@@ -32,7 +32,7 @@ TRACE_EVENT0("android_webview", "AppGLStateSave"); if (gl::GLSurfaceEGL::GetGLDisplayEGL() - ->ext->b_EGL_ANGLE_external_context_and_surface) { + ->IsANGLEExternalContextAndSurfaceSupported()) { impl_ = std::make_unique<internal::ScopedAppGLStateRestoreImplAngle>( mode, save_restore); } else {
diff --git a/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java b/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java index 9fe24a0..9c2a946 100644 --- a/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java +++ b/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java
@@ -19,7 +19,6 @@ import org.chromium.gpu.config.GpuFeatures; import org.chromium.gpu.config.GpuSwitches; import org.chromium.services.network.NetworkServiceFeatures; -import org.chromium.webrtc_overrides.WebRtcOverridesFeatures; /** * List of experimental features/flags supported for user devices. Add features/flags to this list @@ -267,8 +266,6 @@ "Enables prefetching Android fonts on renderer startup."), Flag.baseFeature(AwFeatures.WEBVIEW_LEGACY_TLS_SUPPORT, "Whether legacy TLS versions (TLS 1.0/1.1) conections are allowed."), - Flag.baseFeature(WebRtcOverridesFeatures.WEB_RTC_METRONOME_TASK_QUEUE, - "Enables more efficient scheduling of work in WebRTC."), Flag.baseFeature(BlinkFeatures.INITIAL_NAVIGATION_ENTRY, "Enables creation of initial NavigationEntries on WebContents creation."), Flag.baseFeature(BlinkFeatures.CANVAS2D_STAYS_GPU_ON_READBACK, @@ -297,8 +294,6 @@ AwFeatures.WEBVIEW_SYNTHESIZE_PAGE_LOAD_ONLY_ON_INITIAL_MAIN_DOCUMENT_ACCESS, "Only synthesize page load for URL spoof prevention at most once," + " on initial main document access."), - Flag.baseFeature(WebRtcOverridesFeatures.WEB_RTC_TIMER_USES_METRONOME, - "Makes WebRtcTimer coalesce delayed tasks on metronome ticks."), Flag.baseFeature(BlinkFeatures.VIEWPORT_HEIGHT_CLIENT_HINT_HEADER, "Enables the use of sec-ch-viewport-height client hint."), Flag.baseFeature(BlinkFeatures.USER_AGENT_OVERRIDE_EXPERIMENT,
diff --git a/android_webview/tools/cts_config/README.md b/android_webview/tools/cts_config/README.md index c7130472..57bf2b4 100644 --- a/android_webview/tools/cts_config/README.md +++ b/android_webview/tools/cts_config/README.md
@@ -36,6 +36,14 @@ // be queryable by other APKs // Only usable from Android 11+ "forced_queryable": true + }, + { + "apk": "location of the additional apk in the cts zip file", + // An optional boolean flag to indicate an additional APK should always + // be installed in full mode, even when the tests are being run in + // instant mode + // This flag is only available for additional APKs + "force_full_mode": true } ] },
diff --git a/android_webview/tools/cts_config/webview_cts_gcs_path.json b/android_webview/tools/cts_config/webview_cts_gcs_path.json index e6ddcc2..36b6ca2 100644 --- a/android_webview/tools/cts_config/webview_cts_gcs_path.json +++ b/android_webview/tools/cts_config/webview_cts_gcs_path.json
@@ -170,7 +170,8 @@ "apk": "android-cts/testcases/CtsAssistApp.apk" }, { - "apk": "android-cts/testcases/CtsAssistService.apk" + "apk": "android-cts/testcases/CtsAssistService.apk", + "force_full_mode": true } ], "includes": [ @@ -220,7 +221,8 @@ "apk": "android-cts/testcases/CtsAssistApp.apk" }, { - "apk": "android-cts/testcases/CtsAssistService.apk" + "apk": "android-cts/testcases/CtsAssistService.apk", + "force_full_mode": true } ], "includes": [ @@ -289,7 +291,8 @@ "apk": "android-cts/testcases/CtsAssistApp.apk" }, { - "apk": "android-cts/testcases/CtsAssistService.apk" + "apk": "android-cts/testcases/CtsAssistService.apk", + "force_full_mode": true } ], "includes": [ @@ -389,7 +392,8 @@ "apk": "android-cts/testcases/CtsAssistApp.apk" }, { - "apk": "android-cts/testcases/CtsAssistService.apk" + "apk": "android-cts/testcases/CtsAssistService.apk", + "force_full_mode": true } ], "includes": [ @@ -480,7 +484,8 @@ "apk": "android-cts/testcases/CtsAssistApp.apk" }, { - "apk": "android-cts/testcases/CtsAssistService.apk" + "apk": "android-cts/testcases/CtsAssistService.apk", + "force_full_mode": true } ], "includes": [ @@ -494,7 +499,8 @@ "additional_apks": [ { "apk": "android-cts/testcases/CtsMockInputMethod.apk", - "forced_queryable": true + "forced_queryable": true, + "force_full_mode": true } ], "includes": [ @@ -605,7 +611,8 @@ "apk": "android-cts/testcases/CtsAssistApp.apk" }, { - "apk": "android-cts/testcases/CtsAssistService.apk" + "apk": "android-cts/testcases/CtsAssistService.apk", + "force_full_mode": true } ], "includes": [ @@ -619,7 +626,8 @@ "additional_apks": [ { "apk": "android-cts/testcases/CtsMockInputMethod.apk", - "forced_queryable": true + "forced_queryable": true, + "force_full_mode": true } ], "includes": [
diff --git a/android_webview/tools/run_cts.py b/android_webview/tools/run_cts.py index ea6b15e..9729334 100755 --- a/android_webview/tools/run_cts.py +++ b/android_webview/tools/run_cts.py
@@ -32,6 +32,9 @@ # contents need to be updated if there is an important fix to any of # the tests +_APP_MODE_FULL = 'full' +_APP_MODE_INSTANT = 'instant' + _TEST_RUNNER_PATH = os.path.join( os.path.dirname(__file__), os.pardir, os.pardir, 'build', 'android', 'test_runner.py') @@ -101,16 +104,16 @@ return [os.path.basename(r['apk']) for r in test_runs] -def GetTestRunFilterArg(args, test_run, arch=None): +def GetTestRunFilterArg(args, test_run, test_app_mode=None, arch=None): """ Merges json file filters with cmdline filters using test_filter.InitializeFilterFromArgs """ + test_app_mode = test_app_mode or _APP_MODE_FULL + # Convert cmdline filters to test-filter style filter_string = test_filter.InitializeFilterFromArgs(args) - test_app_mode = 'instant' if args.test_apk_as_instant else 'full' - # Get all the filters for either include or exclude patterns # and filter where an architecture is provided and does not match # The architecture is used when tests only fail on one architecture @@ -144,6 +147,7 @@ apk, voice_service=None, additional_apks=None, + test_app_mode=None, json_results_file=None): """Run tests in apk using test_runner script at _TEST_RUNNER_PATH. @@ -151,6 +155,8 @@ the json_results_file file if specified. """ + test_app_mode = test_app_mode or _APP_MODE_FULL + local_test_runner_args = test_runner_args + ['--test-apk', os.path.join(local_cts_dir, apk)] @@ -167,6 +173,12 @@ '--forced-queryable-additional-apk', additional_apk_tmp ] + if test_app_mode == _APP_MODE_INSTANT and not additional_apk.get( + 'force_full_mode', False): + local_test_runner_args += [ + '--instant-additional-apk', additional_apk_tmp + ] + if json_results_file: local_test_runner_args += ['--json-results-file=%s' % json_results_file] @@ -253,25 +265,29 @@ # services to run additional_apks = cts_test_run.get('additional_apks') + test_app_mode = (_APP_MODE_INSTANT + if args.test_apk_as_instant else _APP_MODE_FULL) + # If --module-apk is specified then skip tests in all other modules if args.module_apk and os.path.basename(test_apk) != args.module_apk: continue iter_test_runner_args = test_runner_args + GetTestRunFilterArg( - args, cts_test_run, arch) + args, cts_test_run, test_app_mode, arch) if json_results_file: with tempfile.NamedTemporaryFile() as iteration_json_file: iteration_cts_result = RunCTS(iter_test_runner_args, local_cts_dir, test_apk, voice_service, - additional_apks, + additional_apks, test_app_mode, iteration_json_file.name) with open(iteration_json_file.name) as f: additional_results_json = json.load(f) MergeTestResults(cts_results_json, additional_results_json) else: iteration_cts_result = RunCTS(iter_test_runner_args, local_cts_dir, - test_apk, voice_service, additional_apks) + test_apk, voice_service, test_app_mode, + additional_apks) if iteration_cts_result: cts_result = iteration_cts_result if json_results_file:
diff --git a/android_webview/tools/run_cts_test.py b/android_webview/tools/run_cts_test.py index 5f59503..e3f329b8 100755 --- a/android_webview/tools/run_cts_test.py +++ b/android_webview/tools/run_cts_test.py
@@ -140,7 +140,8 @@ } self.assertEqual([run_cts.TEST_FILTER_OPT + '=good.test1:good.test2'], - run_cts.GetTestRunFilterArg(mock_args, cts_run, 'x86')) + run_cts.GetTestRunFilterArg(mock_args, cts_run, + arch='x86')) def testFilter_ExcludesForArchitecture(self): mock_args = self._getArgsMock(skip_expected_failures=True) @@ -160,10 +161,11 @@ } self.assertEqual([run_cts.TEST_FILTER_OPT + '=-good.test1:good.test2'], - run_cts.GetTestRunFilterArg(mock_args, cts_run, 'x86')) + run_cts.GetTestRunFilterArg(mock_args, cts_run, + arch='x86')) def testFilter_IncludesForMode(self): - mock_args = self._getArgsMock(test_apk_as_instant=True) + mock_args = self._getArgsMock() cts_run = { 'apk': @@ -180,11 +182,12 @@ } self.assertEqual([run_cts.TEST_FILTER_OPT + '=good.test1:good.test2'], - run_cts.GetTestRunFilterArg(mock_args, cts_run)) + run_cts.GetTestRunFilterArg(mock_args, + cts_run, + test_app_mode='instant')) def testFilter_ExcludesForMode(self): - mock_args = self._getArgsMock(test_apk_as_instant=True, - skip_expected_failures=True) + mock_args = self._getArgsMock(skip_expected_failures=True) cts_run = { 'apk': @@ -201,7 +204,9 @@ } self.assertEqual([run_cts.TEST_FILTER_OPT + '=-good.test1:good.test2'], - run_cts.GetTestRunFilterArg(mock_args, cts_run)) + run_cts.GetTestRunFilterArg(mock_args, + cts_run, + test_app_mode='instant')) def testIsolatedFilter_CombinesExcludedMatches(self): mock_args = self._getArgsMock(isolated_script_test_filter='good#test',
diff --git a/ash/components/phonehub/phone_status_processor_unittest.cc b/ash/components/phonehub/phone_status_processor_unittest.cc index 83efe78..dff4943 100644 --- a/ash/components/phonehub/phone_status_processor_unittest.cc +++ b/ash/components/phonehub/phone_status_processor_unittest.cc
@@ -152,6 +152,111 @@ std::unique_ptr<PhoneStatusProcessor> phone_status_processor_; }; +TEST_F(PhoneStatusProcessorTest, PhoneStatusSnapshotUpdate_EcheDisabled) { + scoped_feature_list_.Reset(); + scoped_feature_list_.InitWithFeatures( + /*enabled_features=*/{}, + /*disabled_features=*/{features::kEcheSWA, + features::kPhoneHubCameraRoll}); + + fake_multidevice_setup_client_->SetHostStatusWithDevice( + std::make_pair(HostStatus::kHostVerified, test_remote_device_)); + CreatePhoneStatusProcessor(); + + auto expected_phone_properties = std::make_unique<proto::PhoneProperties>(); + expected_phone_properties->set_notification_mode( + proto::NotificationMode::DO_NOT_DISTURB_ON); + expected_phone_properties->set_profile_type( + proto::ProfileType::DEFAULT_PROFILE); + expected_phone_properties->set_notification_access_state( + proto::NotificationAccessState::ACCESS_NOT_GRANTED); + expected_phone_properties->set_ring_status( + proto::FindMyDeviceRingStatus::RINGING); + expected_phone_properties->set_battery_percentage(24u); + expected_phone_properties->set_charging_state( + proto::ChargingState::CHARGING_AC); + expected_phone_properties->set_signal_strength( + proto::SignalStrength::FOUR_BARS); + expected_phone_properties->set_mobile_provider("google"); + expected_phone_properties->set_connection_state( + proto::MobileConnectionState::SIM_WITH_RECEPTION); + expected_phone_properties->set_screen_lock_state( + proto::ScreenLockState::SCREEN_LOCK_UNKNOWN); + proto::CameraRollAccessState* access_state = + expected_phone_properties->mutable_camera_roll_access_state(); + access_state->set_feature_enabled(true); + proto::FeatureSetupConfig* feature_setup_config = + expected_phone_properties->mutable_feature_setup_config(); + feature_setup_config->set_feature_setup_request_supported(true); + + expected_phone_properties->add_user_states(); + proto::UserState* mutable_user_state = + expected_phone_properties->mutable_user_states(0); + mutable_user_state->set_user_id(1u); + mutable_user_state->set_is_quiet_mode_enabled(false); + + proto::PhoneStatusSnapshot expected_snapshot; + expected_snapshot.set_allocated_properties( + expected_phone_properties.release()); + expected_snapshot.add_notifications(); + InitializeNotificationProto(expected_snapshot.mutable_notifications(0), + /*id=*/0u); + auto* app = expected_snapshot.mutable_streamable_apps()->add_apps(); + app->set_package_name("pkg1"); + app->set_visible_name("vis"); + + // Simulate feature set to enabled and connected. + fake_feature_status_provider_->SetStatus(FeatureStatus::kEnabledAndConnected); + fake_multidevice_setup_client_->SetFeatureState( + Feature::kPhoneHubNotifications, FeatureState::kEnabledByUser); + + // Simulate receiving a proto message. + fake_message_receiver_->NotifyPhoneStatusSnapshotReceived(expected_snapshot); + + EXPECT_EQ(1u, fake_notification_manager_->num_notifications()); + EXPECT_EQ(base::UTF8ToUTF16(test_remote_device_.name()), + *mutable_phone_model_->phone_name()); + EXPECT_TRUE(fake_do_not_disturb_controller_->IsDndEnabled()); + EXPECT_TRUE(fake_do_not_disturb_controller_->CanRequestNewDndState()); + EXPECT_EQ(FindMyDeviceController::Status::kRingingOn, + fake_find_my_device_controller_->GetPhoneRingingStatus()); + EXPECT_EQ( + MultideviceFeatureAccessManager::AccessStatus::kAvailableButNotGranted, + fake_multidevice_feature_access_manager_->GetNotificationAccessStatus()); + EXPECT_EQ( + MultideviceFeatureAccessManager::AccessStatus::kAvailableButNotGranted, + fake_multidevice_feature_access_manager_->GetCameraRollAccessStatus()); + EXPECT_TRUE(fake_multidevice_feature_access_manager_ + ->GetFeatureSetupRequestSupported()); + EXPECT_EQ(ScreenLockManager::LockStatus::kUnknown, + fake_screen_lock_manager_->GetLockStatus()); + + absl::optional<PhoneStatusModel> phone_status_model = + mutable_phone_model_->phone_status_model(); + EXPECT_EQ(PhoneStatusModel::ChargingState::kChargingAc, + phone_status_model->charging_state()); + EXPECT_EQ(24u, phone_status_model->battery_percentage()); + EXPECT_EQ(u"google", + phone_status_model->mobile_connection_metadata()->mobile_provider); + EXPECT_EQ(PhoneStatusModel::SignalStrength::kFourBars, + phone_status_model->mobile_connection_metadata()->signal_strength); + EXPECT_EQ(PhoneStatusModel::MobileStatus::kSimWithReception, + phone_status_model->mobile_status()); + + // Change feature status to disconnected. + fake_feature_status_provider_->SetStatus( + FeatureStatus::kEnabledButDisconnected); + + EXPECT_EQ(0u, fake_notification_manager_->num_notifications()); + EXPECT_EQ(base::UTF8ToUTF16(test_remote_device_.name()), + *mutable_phone_model_->phone_name()); + EXPECT_FALSE(mutable_phone_model_->phone_status_model().has_value()); + + std::vector<RecentAppsInteractionHandler::UserState> user_states = + fake_recent_apps_interaction_handler_->user_states(); + EXPECT_TRUE(user_states.empty()); +} + TEST_F(PhoneStatusProcessorTest, PhoneStatusSnapshotUpdate) { fake_multidevice_setup_client_->SetHostStatusWithDevice( std::make_pair(HostStatus::kHostVerified, test_remote_device_)); @@ -195,6 +300,9 @@ expected_snapshot.add_notifications(); InitializeNotificationProto(expected_snapshot.mutable_notifications(0), /*id=*/0u); + auto* app = expected_snapshot.mutable_streamable_apps()->add_apps(); + app->set_package_name("pkg1"); + app->set_visible_name("vis"); // Simulate feature set to enabled and connected. fake_feature_status_provider_->SetStatus(FeatureStatus::kEnabledAndConnected);
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc index 6da86ba4..66ee474 100644 --- a/ash/constants/ash_features.cc +++ b/ash/constants/ash_features.cc
@@ -156,11 +156,6 @@ const base::Feature kAssistMultiWordExpanded{"AssistMultiWordExpanded", base::FEATURE_DISABLED_BY_DEFAULT}; -// Controls whether to enable lacros support for the assistive multi word -// suggestions feature. -const base::Feature kAssistMultiWordLacrosSupport{ - "AssistMultiWordLacrosSupport", base::FEATURE_DISABLED_BY_DEFAULT}; - // Controls whether to enable assistive personal information. const base::Feature kAssistPersonalInfo{"AssistPersonalInfo", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/ash/constants/ash_features.h b/ash/constants/ash_features.h index 568b28b..cbae848 100644 --- a/ash/constants/ash_features.h +++ b/ash/constants/ash_features.h
@@ -76,8 +76,6 @@ COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kAssistMultiWord; COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kAssistMultiWordExpanded; -COMPONENT_EXPORT(ASH_CONSTANTS) -extern const base::Feature kAssistMultiWordLacrosSupport; COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kAssistPersonalInfo; COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kAssistPersonalInfoAddress;
diff --git a/ash/services/ime/ime_service.cc b/ash/services/ime/ime_service.cc index 711ea002..b07328f 100644 --- a/ash/services/ime/ime_service.cc +++ b/ash/services/ime/ime_service.cc
@@ -181,9 +181,7 @@ return chromeos::features::IsAssistiveMultiWordEnabled(); } if (strcmp(feature_name, "AssistiveMultiWordLacrosSupport") == 0) { - return base::FeatureList::IsEnabled( - chromeos::features::kAssistMultiWordLacrosSupport) && - chromeos::features::IsAssistiveMultiWordEnabled(); + return true; } if (strcmp(feature_name, chromeos::features::kAutocorrectParamsTuning.name) == 0) {
diff --git a/ash/webui/camera_app_ui/resources/css/review.css b/ash/webui/camera_app_ui/resources/css/review.css index 2fb9f1d..c705fa9d7 100644 --- a/ash/webui/camera_app_ui/resources/css/review.css +++ b/ash/webui/camera_app_ui/resources/css/review.css
@@ -33,8 +33,8 @@ align-items: center; bottom: 0; display: flex; - flex-direction: row-reverse; flex-wrap: wrap; + gap: 16px; position: absolute; top: calc(100% - calc(var(--bottom-line) * 2)); } @@ -47,18 +47,6 @@ left: calc(var(--left-line) * 2); } -.review-views .button-group button { - margin: 0 8px; -} - -.review-views .button-group button:first-child { - margin-inline-end: 0; -} - -.review-views .button-group button:last-child { - margin-inline-start: 0; -} - .review-views .button-group button[i18n-text=label_share]::before { content: url(/images/review_share.svg); display: inline-block;
diff --git a/ash/webui/camera_app_ui/resources/js/views/camera.ts b/ash/webui/camera_app_ui/resources/js/views/camera.ts index 04e221b9..c60eb283 100644 --- a/ash/webui/camera_app_ui/resources/js/views/camera.ts +++ b/ash/webui/camera_app_ui/resources/js/views/camera.ts
@@ -749,21 +749,25 @@ nav.close(ViewName.FLASH); } + const negative = new review.OptionGroup({ + template: review.ButtonGroupTemplate.NEGATIVE, + options: [ + new review.Option({text: I18nString.LABEL_RETAKE}, { + callback: () => { + sendEvent(metrics.DocResultType.CANCELED); + }, + exitValue: null, + }), + new review.Option({text: I18nString.LABEL_FIX_DOCUMENT}, { + callback: doRecrop, + hasPopup: true, + }), + ], + }); + const positive = new review.OptionGroup({ template: review.ButtonGroupTemplate.POSITIVE, options: [ - new review.Option({text: I18nString.LABEL_SAVE_PDF_DOCUMENT}, { - callback: () => { - sendEvent(metrics.DocResultType.SAVE_AS_PDF); - }, - exitValue: MimeType.PDF, - }), - new review.Option({text: I18nString.LABEL_SAVE_PHOTO_DOCUMENT}, { - callback: () => { - sendEvent(metrics.DocResultType.SAVE_AS_PHOTO); - }, - exitValue: MimeType.JPEG, - }), new review.Option({text: I18nString.LABEL_SHARE}, { callback: async () => { sendEvent(metrics.DocResultType.SHARE); @@ -772,26 +776,22 @@ await util.share(new File([docBlob], name, {type})); }, }), - ], - }); - - const negative = new review.OptionGroup({ - template: review.ButtonGroupTemplate.NEGATIVE, - options: [ - new review.Option({text: I18nString.LABEL_FIX_DOCUMENT}, { - callback: doRecrop, - hasPopup: true, - }), - new review.Option({text: I18nString.LABEL_RETAKE}, { + new review.Option({text: I18nString.LABEL_SAVE_PHOTO_DOCUMENT}, { callback: () => { - sendEvent(metrics.DocResultType.CANCELED); + sendEvent(metrics.DocResultType.SAVE_AS_PHOTO); }, - exitValue: null, + exitValue: MimeType.JPEG, }), + new review.Option( + {text: I18nString.LABEL_SAVE_PDF_DOCUMENT, primary: true}, { + callback: () => { + sendEvent(metrics.DocResultType.SAVE_AS_PDF); + }, + exitValue: MimeType.PDF, + }), ], }); - - const mimeType = await this.review.startReview(positive, negative); + const mimeType = await this.review.startReview(negative, positive); assert(mimeType !== undefined); if (mimeType !== null) { result = {docBlob, mimeType}; @@ -838,25 +838,26 @@ let result: boolean|null = false; await this.prepareReview(async () => { await this.review.setReviewPhoto(blob); + const negative = new review.OptionGroup({ + template: review.ButtonGroupTemplate.NEGATIVE, + options: [new review.Option( + {text: I18nString.LABEL_RETAKE}, {exitValue: null})], + }); const positive = new review.OptionGroup({ template: review.ButtonGroupTemplate.POSITIVE, options: [ - new review.Option({text: I18nString.LABEL_SAVE}, {exitValue: true}), new review.Option({text: I18nString.LABEL_SHARE}, { callback: async () => { sendEvent(metrics.GifResultType.SHARE); await util.share(new File([blob], name, {type: MimeType.GIF})); }, }), + new review.Option( + {text: I18nString.LABEL_SAVE, primary: true}, {exitValue: true}), ], }); - const negative = new review.OptionGroup({ - template: review.ButtonGroupTemplate.NEGATIVE, - options: [new review.Option( - {text: I18nString.LABEL_RETAKE}, {exitValue: null})], - }); nav.close(ViewName.FLASH); - result = (await this.review.startReview(positive, negative)) as boolean; + result = (await this.review.startReview(negative, positive)) as boolean; }); if (result) { sendEvent(metrics.GifResultType.SAVE);
diff --git a/ash/webui/camera_app_ui/resources/js/views/camera_intent.ts b/ash/webui/camera_app_ui/resources/js/views/camera_intent.ts index eadc1af7..70a0e96a 100644 --- a/ash/webui/camera_app_ui/resources/js/views/camera_intent.ts +++ b/ash/webui/camera_app_ui/resources/js/views/camera_intent.ts
@@ -76,6 +76,7 @@ { label: I18nString.CONFIRM_REVIEW_BUTTON, templateId: 'review-intent-button-template', + primary: true, }, {exitValue: true}), new review.Option(
diff --git a/ash/webui/camera_app_ui/resources/js/views/crop_document.ts b/ash/webui/camera_app_ui/resources/js/views/crop_document.ts index 1577391..0a43b9f4 100644 --- a/ash/webui/camera_app_ui/resources/js/views/crop_document.ts +++ b/ash/webui/camera_app_ui/resources/js/views/crop_document.ts
@@ -349,8 +349,9 @@ this.cornerSpaceSize = null; await super.startReview(new OptionGroup({ template: ButtonGroupTemplate.POSITIVE, - options: - [new Option({text: I18nString.LABEL_CROP_DONE}, {exitValue: true})], + options: [new Option( + {text: I18nString.LABEL_CROP_DONE, primary: true}, + {exitValue: true})], })); const newCorners = this.corners.map(({pt: {x, y}}) => { assert(this.cornerSpaceSize !== null);
diff --git a/ash/webui/camera_app_ui/resources/js/views/option_panel.ts b/ash/webui/camera_app_ui/resources/js/views/option_panel.ts index f31d981..3ca1945 100644 --- a/ash/webui/camera_app_ui/resources/js/views/option_panel.ts +++ b/ash/webui/camera_app_ui/resources/js/views/option_panel.ts
@@ -49,6 +49,7 @@ span.setAttribute('i18n-aria', ariaLabel); const input = dom.getFrom(item, 'input', HTMLInputElement); + input.setAttribute('name', titleLabel); const stateEnabled = state.get(targetState); const checked = isDisableOption ? !stateEnabled : stateEnabled; input.checked = checked;
diff --git a/ash/webui/camera_app_ui/resources/js/views/review.ts b/ash/webui/camera_app_ui/resources/js/views/review.ts index 4907388..0b10f93 100644 --- a/ash/webui/camera_app_ui/resources/js/views/review.ts +++ b/ash/webui/camera_app_ui/resources/js/views/review.ts
@@ -18,6 +18,7 @@ text?: I18nString; label?: I18nString; templateId?: string; + primary?: boolean; } /** @@ -158,8 +159,12 @@ } for (const btnGroup of this.btnGroups) { const addButton = - ({uiArgs: {text, label, templateId}, exitValue, callback, hasPopup}: - Option<T|null>) => { + ({ + uiArgs: {text, label, templateId, primary}, + exitValue, + callback, + hasPopup, + }: Option<T|null>) => { const templ = instantiateTemplate( templateId !== undefined ? `#${templateId}` : '#text-button-template'); @@ -170,7 +175,7 @@ if (label !== undefined) { btn.setAttribute('i18n-label', label); } - if (this.primaryBtn === null) { + if (this.primaryBtn === null && primary === true) { btn.classList.add('primary'); this.primaryBtn = btn; } else {
diff --git a/ash/webui/camera_app_ui/resources/views/main.html b/ash/webui/camera_app_ui/resources/views/main.html index ce418d4..f1816e2b 100644 --- a/ash/webui/camera_app_ui/resources/views/main.html +++ b/ash/webui/camera_app_ui/resources/views/main.html
@@ -294,15 +294,15 @@ <div id="ptz-panel-container" class="panel"> <button id="tilt-up" class="inkdrop" i18n-label="tilt_up_button" tabindex="0"></button> - <button id="pan-right" class="inkdrop" i18n-label="pan_right_button" - tabindex="0"></button> - <button id="tilt-down" class="inkdrop" i18n-label="tilt_down_button" - tabindex="0"></button> <button id="pan-left" class="inkdrop" i18n-label="pan_left_button" tabindex="0"></button> + <button id="zoom-out" class="inkdrop" i18n-label="zoom_out_button" + tabindex="0"></button> <button id="zoom-in" class="inkdrop" i18n-label="zoom_in_button" tabindex="0"></button> - <button id="zoom-out" class="inkdrop" i18n-label="zoom_out_button" + <button id="pan-right" class="inkdrop" i18n-label="pan_right_button" + tabindex="0"></button> + <button id="tilt-down" class="inkdrop" i18n-label="tilt_down_button" tabindex="0"></button> <div id="ptz-divider1" class="ptz-divider"></div> <div id="ptz-divider2" class="ptz-divider"></div>
diff --git a/ash/webui/guest_os_installer/resources/app.ts b/ash/webui/guest_os_installer/resources/app.ts index 3f7f036..d9a84f1 100644 --- a/ash/webui/guest_os_installer/resources/app.ts +++ b/ash/webui/guest_os_installer/resources/app.ts
@@ -15,7 +15,7 @@ return html`{__html_template__}`; } - listenerIds_: number[] = []; + private listenerIds_: number[] = []; override connectedCallback() { this.listenerIds_ = [];
diff --git a/ash/webui/os_feedback_ui/os_feedback_ui.cc b/ash/webui/os_feedback_ui/os_feedback_ui.cc index 5a05e3a7..46f4d083 100644 --- a/ash/webui/os_feedback_ui/os_feedback_ui.cc +++ b/ash/webui/os_feedback_ui/os_feedback_ui.cc
@@ -52,11 +52,14 @@ {"popularHelpContent", IDS_FEEDBACK_TOOL_POPULAR_HELP_CONTENT}, {"noMatchedResults", IDS_FEEDBACK_TOOL_NO_MATCHED_RESULTS}, {"attachFilesLabel", IDS_FEEDBACK_TOOL_ATTACH_FILES_LABEL}, + {"attachScreenshotLabel", IDS_FEEDBACK_TOOL_SCREENSHOT_LABEL}, {"replaceFileLabel", IDS_FEEDBACK_TOOL_REPLACE_FILE_LABEL}, {"userEmailLabel", IDS_FEEDBACK_TOOL_USER_EMAIL_LABEL}, {"shareDiagnosticDataLabel", IDS_FEEDBACK_TOOL_SHARE_DIAGNOSTIC_DATA_LABEL}, {"confirmationTitleOnline", IDS_FEEDBACK_TOOL_PAGE_TITLE_AFTER_SENT}, + {"diagnosticsAppLabel", + IDS_FEEDBACK_TOOL_RESOURCES_DIAGNOSTICS_APP_LABEL}, }; source->AddLocalizedStrings(kLocalizedStrings);
diff --git a/ash/webui/os_feedback_ui/resources/confirmation_page.html b/ash/webui/os_feedback_ui/resources/confirmation_page.html index 157a7b7..53ac7c6 100644 --- a/ash/webui/os_feedback_ui/resources/confirmation_page.html +++ b/ash/webui/os_feedback_ui/resources/confirmation_page.html
@@ -26,7 +26,7 @@ on-click="handleLinkClicked_"> </cr-link-row> <cr-link-row id="diagnostics" start-icon="help-resources:diagnostics" - label="Diagnostics app" external + label="[[i18n('diagnosticsAppLabel')]]" external sub-label="Run tests and troubleshooting for hardware issues" on-click="handleLinkClicked_"> </cr-link-row>
diff --git a/ash/webui/os_feedback_ui/resources/share_data_page.html b/ash/webui/os_feedback_ui/resources/share_data_page.html index 10b8e02..584806d 100644 --- a/ash/webui/os_feedback_ui/resources/share_data_page.html +++ b/ash/webui/os_feedback_ui/resources/share_data_page.html
@@ -82,7 +82,7 @@ <input id="screenshotCheckbox" type="checkbox" aria-labelledby="screenshotCheckLabel" disabled="[[!hasScreenshot_(screenshotUrl)]]"> - <label id="screenshotCheckLabel">Screenshot</label> + <label id="screenshotCheckLabel">[[i18n('attachScreenshotLabel')]]</label> <img id="screenshotImage" aria-label="$i18n{screenshotA11y}" src="[[screenshotUrl]]"> </div>
diff --git a/ash/webui/personalization_app/resources/trusted/user/user_subpage_element.ts b/ash/webui/personalization_app/resources/trusted/user/user_subpage_element.ts index e319e1d..34afd1bc 100644 --- a/ash/webui/personalization_app/resources/trusted/user/user_subpage_element.ts +++ b/ash/webui/personalization_app/resources/trusted/user/user_subpage_element.ts
@@ -34,7 +34,7 @@ } path: string; - isUserImageEnterpriseManaged_: boolean|null; + private isUserImageEnterpriseManaged_: boolean|null; override connectedCallback() { super.connectedCallback();
diff --git a/ash/webui/personalization_app/resources/trusted/wallpaper/wallpaper_subpage_element.ts b/ash/webui/personalization_app/resources/trusted/wallpaper/wallpaper_subpage_element.ts index c74a58d..8305d1d7 100644 --- a/ash/webui/personalization_app/resources/trusted/wallpaper/wallpaper_subpage_element.ts +++ b/ash/webui/personalization_app/resources/trusted/wallpaper/wallpaper_subpage_element.ts
@@ -38,7 +38,7 @@ path: string; queryParams: Record<string, string>; - currentSelected_: CurrentWallpaper|null; + private currentSelected_: CurrentWallpaper|null; override connectedCallback(): void { super.connectedCallback();
diff --git a/base/allocator/allocator.gni b/base/allocator/allocator.gni index 97a57df..c3c62f8 100644 --- a/base/allocator/allocator.gni +++ b/base/allocator/allocator.gni
@@ -112,7 +112,10 @@ # Finch. use_fake_binary_experiment = false - use_asan_backup_ref_ptr = false + # The supported platforms are supposed to match `_is_brp_supported`, but we + # enable the feature on Linux early because it's most widely used for security + # research + use_asan_backup_ref_ptr = is_asan && (is_win || is_android || is_linux) } # Prevent using BackupRefPtr when PartitionAlloc-Everywhere isn't used.
diff --git a/base/allocator/partition_alloc_features.cc b/base/allocator/partition_alloc_features.cc index 621f767b..d37b2500 100644 --- a/base/allocator/partition_alloc_features.cc +++ b/base/allocator/partition_alloc_features.cc
@@ -55,7 +55,8 @@ const Feature kPartitionAllocBackupRefPtr { "PartitionAllocBackupRefPtr", -#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_WIN) +#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_WIN) || \ + (BUILDFLAG(USE_ASAN_BACKUP_REF_PTR) && BUILDFLAG(IS_LINUX)) FEATURE_ENABLED_BY_DEFAULT #else FEATURE_DISABLED_BY_DEFAULT
diff --git a/base/memory/raw_ptr.cc b/base/memory/raw_ptr.cc index 56b70fe..9bfe23b 100644 --- a/base/memory/raw_ptr.cc +++ b/base/memory/raw_ptr.cc
@@ -128,6 +128,7 @@ } } // namespace +NO_SANITIZE("address") void AsanBackupRefPtrImpl::AsanCheckIfValidDereference( void const volatile* ptr) { if (RawPtrAsanService::GetInstance().is_dereference_check_enabled() && @@ -138,6 +139,7 @@ } } +NO_SANITIZE("address") void AsanBackupRefPtrImpl::AsanCheckIfValidExtraction( void const volatile* ptr) { auto& service = RawPtrAsanService::GetInstance(); @@ -172,6 +174,7 @@ } } +NO_SANITIZE("address") void AsanBackupRefPtrImpl::AsanCheckIfValidInstantiation( void const volatile* ptr) { if (RawPtrAsanService::GetInstance().is_instantiation_check_enabled() &&
diff --git a/base/memory/raw_ptr_asan_service.cc b/base/memory/raw_ptr_asan_service.cc index 844d9179..78d30ae9f 100644 --- a/base/memory/raw_ptr_asan_service.cc +++ b/base/memory/raw_ptr_asan_service.cc
@@ -11,7 +11,6 @@ #include <string.h> #include "base/check_op.h" -#include "base/compiler_specific.h" #include "base/logging.h" #include "base/strings/stringprintf.h"
diff --git a/base/memory/raw_ptr_asan_service.h b/base/memory/raw_ptr_asan_service.h index 8566634..7028e7a6 100644 --- a/base/memory/raw_ptr_asan_service.h +++ b/base/memory/raw_ptr_asan_service.h
@@ -12,6 +12,7 @@ #include <cstdint> #include "base/base_export.h" +#include "base/compiler_specific.h" #include "base/types/strong_alias.h" namespace base { @@ -44,17 +45,24 @@ bool IsSupportedAllocation(void*) const; - bool is_dereference_check_enabled() const { + NO_SANITIZE("address") + ALWAYS_INLINE bool is_dereference_check_enabled() const { return is_dereference_check_enabled_; } - bool is_extraction_check_enabled() const { + + NO_SANITIZE("address") + ALWAYS_INLINE bool is_extraction_check_enabled() const { return is_extraction_check_enabled_; } - bool is_instantiation_check_enabled() const { + + NO_SANITIZE("address") + ALWAYS_INLINE bool is_instantiation_check_enabled() const { return is_instantiation_check_enabled_; } - static RawPtrAsanService& GetInstance() { return instance_; } + NO_SANITIZE("address") ALWAYS_INLINE static RawPtrAsanService& GetInstance() { + return instance_; + } static void SetPendingReport(ReportType type, const volatile void* ptr); static void Log(const char* format, ...);
diff --git a/build/android/pylib/instrumentation/instrumentation_test_instance.py b/build/android/pylib/instrumentation/instrumentation_test_instance.py index b98c9310..7a1340b 100644 --- a/build/android/pylib/instrumentation/instrumentation_test_instance.py +++ b/build/android/pylib/instrumentation/instrumentation_test_instance.py
@@ -630,6 +630,7 @@ self._additional_apks = [] self._forced_queryable_additional_apks = [] + self._instant_additional_apks = [] self._apk_under_test = None self._apk_under_test_incremental_install_json = None self._modules = None @@ -808,7 +809,8 @@ '(This may just mean that the test package is ' 'currently being installed.)', self._test_package) - for x in set(args.additional_apks + args.forced_queryable_additional_apks): + for x in set(args.additional_apks + args.forced_queryable_additional_apks + + args.instant_additional_apks): if not os.path.exists(x): error_func('Unable to find additional APK: %s' % x) @@ -818,6 +820,9 @@ if x in args.forced_queryable_additional_apks: self._forced_queryable_additional_apks.append(apk) + if x in args.instant_additional_apks: + self._instant_additional_apks.append(apk) + def _initializeDataDependencyAttributes(self, args, data_deps_delegate): self._data_deps = [] self._data_deps_delegate = data_deps_delegate @@ -1137,6 +1142,9 @@ def IsApkForceQueryable(self, apk): return apk in self._forced_queryable_additional_apks + def IsApkInstant(self, apk): + return apk in self._instant_additional_apks + # pylint: disable=no-self-use def _InflateTests(self, tests): inflated_tests = []
diff --git a/build/android/pylib/local/device/local_device_instrumentation_test_run.py b/build/android/pylib/local/device/local_device_instrumentation_test_run.py index 6b8231f..510684c 100644 --- a/build/android/pylib/local/device/local_device_instrumentation_test_run.py +++ b/build/android/pylib/local/device/local_device_instrumentation_test_run.py
@@ -288,7 +288,8 @@ instant_app=self._test_instance.test_apk_as_instant)) steps.extend( - install_helper(apk) for apk in self._test_instance.additional_apks) + install_helper(apk, instant_app=self._test_instance.IsApkInstant(apk)) + for apk in self._test_instance.additional_apks) # We'll potentially need the package names later for setting app # compatibility workarounds.
diff --git a/build/android/test_runner.py b/build/android/test_runner.py index b8bdaee..4aea6f5 100755 --- a/build/android/test_runner.py +++ b/build/android/test_runner.py
@@ -437,6 +437,12 @@ type=_RealPath, help='Configures an additional-apk to be forced ' 'to be queryable by other APKs.') + parser.add_argument('--instant-additional-apk', + action='append', + dest='instant_additional_apks', + default=[], + type=_RealPath, + help='Configures an additional-apk to be an instant APK') parser.add_argument( '-A', '--annotation', dest='annotation_str',
diff --git a/chrome/BUILD.gn b/chrome/BUILD.gn index abbbfc5db..06e3385 100644 --- a/chrome/BUILD.gn +++ b/chrome/BUILD.gn
@@ -1569,12 +1569,14 @@ } repack("unit_tests_pak") { + testonly = true sources = [ "$root_gen_dir/chrome/chrome_test_resources.pak" ] output = "$root_out_dir/unit_tests.pak" deps = [ "//chrome/test/data:chrome_test_resources" ] } repack("browser_tests_pak") { + testonly = true sources = [ "$root_gen_dir/chrome/webui_test_resources.pak" ] output = "$root_out_dir/browser_tests.pak" deps = [ "//chrome/test/data:webui_test_resources" ]
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogTest.java index 69d7e918..9e7dfdf 100644 --- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogTest.java +++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogTest.java
@@ -812,8 +812,7 @@ @MediumTest @DisabledTest(message = "TODO(crbug.com/1128345): Fix flakiness.") // clang-format off - @Features.EnableFeatures({ChromeFeatureList.TAB_GROUPS_CONTINUATION_ANDROID, - ChromeFeatureList.TAB_GRID_LAYOUT_ANDROID + "<Study"}) + @Features.EnableFeatures({ChromeFeatureList.TAB_GROUPS_CONTINUATION_ANDROID + "<Study"}) @CommandLineFlags.Add({"force-fieldtrials=Study/Group", TAB_GROUP_LAUNCH_POLISH_PARAMS}) public void testAccessibilityString() throws ExecutionException { // clang-format on
diff --git a/chrome/android/java/res/layout/share_sheet_content.xml b/chrome/android/java/res/layout/share_sheet_content.xml index f272986..ac498439 100644 --- a/chrome/android/java/res/layout/share_sheet_content.xml +++ b/chrome/android/java/res/layout/share_sheet_content.xml
@@ -56,7 +56,7 @@ <TextView android:id="@+id/subtitle_preview" - android:ellipsize="end" + android:ellipsize="start" android:layout_below="@id/title_preview" android:layout_width="match_parent" android:layout_height="wrap_content"
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java index aba87c53..b2b94fe 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
@@ -701,7 +701,6 @@ @Test @SmallTest - @DisabledTest(message = "https://crbug.com/1148544") public void testCreateNewTab() throws Exception { final String testUrl = mTestServer.getURL( "/chrome/test/data/android/customtabs/test_window_open.html");
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/ManageSpaceActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/ManageSpaceActivityTest.java index 5383798..265f4cb 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/ManageSpaceActivityTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/ManageSpaceActivityTest.java
@@ -28,7 +28,6 @@ import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.CriteriaHelper; -import org.chromium.base.test.util.DisabledTest; import org.chromium.base.test.util.Feature; import org.chromium.chrome.R; import org.chromium.chrome.browser.browsing_data.BrowsingDataBridge; @@ -106,7 +105,6 @@ @Test @MediumTest @Feature({"SiteEngagement"}) - @DisabledTest(message = "https://crbug.com/1060975") public void testClearUnimportantOnly() throws Exception { final String cookiesUrl = mTestServer.getURL("/chrome/test/data/android/storage_persistance.html");
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/SiteSettingsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/SiteSettingsTest.java index d269f54e..c228463 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/SiteSettingsTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/SiteSettingsTest.java
@@ -821,7 +821,6 @@ @Test @SmallTest @Feature({"Preferences"}) - @DisabledTest(message = "Flaky - https://crbug.com/1313206") public void testPopupsNotBlocked() throws TimeoutException { new TwoStatePermissionTestCase( "Popups", SiteSettingsCategory.Type.POPUPS, ContentSettingsType.POPUPS, true) @@ -1504,7 +1503,6 @@ @Test @SmallTest @Feature({"Preferences"}) - @DisabledTest(message = "https://crbug.com/1094934") public void testEmbargoedNotificationCategorySiteSettings() throws Exception { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return; final String urlToEmbargo = mPermissionRule.getURLWithHostName(
diff --git a/chrome/browser/OWNERS b/chrome/browser/OWNERS index 24c9190..647fce6 100644 --- a/chrome/browser/OWNERS +++ b/chrome/browser/OWNERS
@@ -85,9 +85,7 @@ per-file chrome_content_browser_client_binder_policies.*=file://ipc/SECURITY_OWNERS # BackForwardCache -per-file chrome_back_forward_cache_browsertest.cc=arthursonzogni@chromium.org -per-file chrome_back_forward_cache_browsertest.cc=altimin@chromium.org -per-file chrome_back_forward_cache_browsertest.cc=rakina@chromium.org +per-file chrome_back_forward_cache_browsertest.cc=file://content/browser/BACK_FORWARD_CACHE_OWNERS per-file chrome_back_forward_cache_browsertest.cc=file://content/OWNERS # Web Platform security metrics tests:
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 774928d5..ee27ac4 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -4698,10 +4698,6 @@ flag_descriptions::kImeAssistMultiWordExpandedName, flag_descriptions::kImeAssistMultiWordExpandedDescription, kOsCrOS, FEATURE_VALUE_TYPE(chromeos::features::kAssistMultiWordExpanded)}, - {"enable-cros-ime-assist-multi-word-lacros", - flag_descriptions::kImeAssistMultiWordLacrosSupportName, - flag_descriptions::kImeAssistMultiWordLacrosSupportDescription, kOsCrOS, - FEATURE_VALUE_TYPE(chromeos::features::kAssistMultiWordLacrosSupport)}, {"enable-cros-ime-assist-personal-info", flag_descriptions::kImeAssistPersonalInfoName, flag_descriptions::kImeAssistPersonalInfoDescription, kOsCrOS, @@ -4728,10 +4724,6 @@ flag_descriptions::kImeStylusHandwritingName, flag_descriptions::kImeStylusHandwritingDescription, kOsCrOS, FEATURE_VALUE_TYPE(chromeos::features::kImeStylusHandwriting)}, - {"enable-cros-language-settings-update-2", - flag_descriptions::kCrosLanguageSettingsUpdate2Name, - flag_descriptions::kCrosLanguageSettingsUpdate2Description, kOsCrOS, - FEATURE_VALUE_TYPE(chromeos::features::kLanguageSettingsUpdate2)}, {"enable-cros-language-settings-update-japanese", flag_descriptions::kCrosLanguageSettingsUpdateJapaneseName, flag_descriptions::kCrosLanguageSettingsUpdateJapaneseDescription, kOsCrOS,
diff --git a/chrome/browser/apps/app_service/app_service_proxy_base.cc b/chrome/browser/apps/app_service/app_service_proxy_base.cc index acb8c19..e38bc26 100644 --- a/chrome/browser/apps/app_service/app_service_proxy_base.cc +++ b/chrome/browser/apps/app_service/app_service_proxy_base.cc
@@ -104,7 +104,7 @@ : inner_icon_loader_(this), icon_coalescer_(&inner_icon_loader_), outer_icon_loader_(&icon_coalescer_, - apps::IconCache::GarbageCollectionPolicy::kEager), + IconCache::GarbageCollectionPolicy::kEager), profile_(profile) { if (base::FeatureList::IsEnabled(kAppServicePreferredAppsWithoutMojom)) { preferred_apps_impl_ = std::make_unique<apps::PreferredAppsImpl>( @@ -114,7 +114,10 @@ AppServiceProxyBase::~AppServiceProxyBase() = default; -void AppServiceProxyBase::ReInitializeForTesting(Profile* profile) { +void AppServiceProxyBase::ReInitializeForTesting( + Profile* profile, + base::OnceClosure read_completed_for_testing, + base::OnceClosure write_completed_for_testing) { // Some test code creates a profile and profile-linked services, like the App // Service, before the profile is fully initialized. Such tests can call this // after full profile initialization to ensure the App Service implementation @@ -122,6 +125,13 @@ app_service_.reset(); profile_ = profile; is_using_testing_profile_ = true; + if (base::FeatureList::IsEnabled(kAppServicePreferredAppsWithoutMojom)) { + preferred_apps_impl_ = std::make_unique<apps::PreferredAppsImpl>( + this, profile ? profile->GetPath() : base::FilePath(), + std::move(read_completed_for_testing), + std::move(write_completed_for_testing)); + } + publishers_.clear(); Initialize(); } @@ -218,7 +228,8 @@ ReplacedAppPreferences replaced_app_preferences) { for (const auto& iter : publishers_) { iter.second->OnPreferredAppSet( - app_id, intent_filter->Clone(), intent->Clone(), + app_id, intent_filter ? intent_filter->Clone() : nullptr, + intent ? intent->Clone() : nullptr, CloneIntentFiltersMap(replaced_app_preferences)); } } @@ -750,7 +761,7 @@ void AppServiceProxyBase::OnApps(std::vector<AppPtr> deltas, AppType app_type, bool should_notify_initialized) { - if (app_service_.is_connected()) { + if (preferred_apps_impl_ || app_service_.is_connected()) { for (const auto& delta : deltas) { if (delta->readiness != Readiness::kUnknown && !apps_util::IsInstalled(delta->readiness)) {
diff --git a/chrome/browser/apps/app_service/app_service_proxy_base.h b/chrome/browser/apps/app_service/app_service_proxy_base.h index 2879e59..0433e90c 100644 --- a/chrome/browser/apps/app_service/app_service_proxy_base.h +++ b/chrome/browser/apps/app_service/app_service_proxy_base.h
@@ -81,7 +81,10 @@ AppServiceProxyBase& operator=(const AppServiceProxyBase&) = delete; ~AppServiceProxyBase() override; - void ReInitializeForTesting(Profile* profile); + void ReInitializeForTesting( + Profile* profile, + base::OnceClosure read_completed_for_testing = base::OnceClosure(), + base::OnceClosure write_completed_for_testing = base::OnceClosure()); Profile* profile() const { return profile_; }
diff --git a/chrome/browser/apps/app_service/app_service_proxy_factory.cc b/chrome/browser/apps/app_service/app_service_proxy_factory.cc index 31adec0..49c31ff 100644 --- a/chrome/browser/apps/app_service/app_service_proxy_factory.cc +++ b/chrome/browser/apps/app_service/app_service_proxy_factory.cc
@@ -8,6 +8,7 @@ #include "base/debug/dump_without_crashing.h" #include "build/chromeos_buildflags.h" #include "chrome/browser/apps/app_service/app_service_proxy.h" +#include "chrome/browser/ash/system_web_apps/system_web_app_manager_factory.h" #include "chrome/browser/content_settings/host_content_settings_map_factory.h" #include "chrome/browser/profiles/incognito_helpers.h" #include "chrome/browser/profiles/profile.h" @@ -93,6 +94,7 @@ DependsOn(extensions::ExtensionRegistryFactory::GetInstance()); DependsOn(HostContentSettingsMapFactory::GetInstance()); DependsOn(web_app::WebAppProviderFactory::GetInstance()); + DependsOn(ash::SystemWebAppManagerFactory::GetInstance()); #if BUILDFLAG(IS_CHROMEOS_ASH) DependsOn(guest_os::GuestOsRegistryServiceFactory::GetInstance()); DependsOn(NotificationDisplayServiceFactory::GetInstance());
diff --git a/chrome/browser/apps/app_service/app_service_proxy_unittest.cc b/chrome/browser/apps/app_service/app_service_proxy_unittest.cc index fd1044f..dedc4dd 100644 --- a/chrome/browser/apps/app_service/app_service_proxy_unittest.cc +++ b/chrome/browser/apps/app_service/app_service_proxy_unittest.cc
@@ -24,6 +24,7 @@ #include "components/services/app_service/public/cpp/intent_filter_util.h" #include "components/services/app_service/public/cpp/intent_test_util.h" #include "components/services/app_service/public/cpp/intent_util.h" +#include "components/services/app_service/public/cpp/preferred_app.h" #include "components/services/app_service/public/cpp/publisher_base.h" #include "components/services/app_service/public/mojom/types.mojom-shared.h" #include "components/services/app_service/public/mojom/types.mojom.h" @@ -49,7 +50,7 @@ app_type_(app_type), known_app_ids_(std::move(initial_app_ids)) { RegisterPublisher(app_type_); - CallOnApps(); + CallOnApps(known_app_ids_, /*uninstall=*/false); } void LaunchAppWithParams(AppLaunchParams&& params, @@ -62,15 +63,27 @@ bool allow_placeholder_icon, LoadIconCallback callback) override {} + void UninstallApps(std::vector<std::string> app_ids) { + CallOnApps(app_ids, /*uninstall=*/true); + + for (const auto& app_id : app_ids) { + known_app_ids_.push_back(app_id); + } + } + bool AppHasSupportedLinksPreference(const std::string& app_id) { return supported_link_apps_.find(app_id) != supported_link_apps_.end(); } private: - void CallOnApps() { + void CallOnApps(std::vector<std::string>& app_ids, bool uninstall) { std::vector<AppPtr> apps; - for (const auto& app_id : known_app_ids_) { - apps.push_back(std::make_unique<App>(app_type_, app_id)); + for (const auto& app_id : app_ids) { + auto app = std::make_unique<App>(app_type_, app_id); + if (uninstall) { + app->readiness = Readiness::kUninstalledByUser; + } + apps.push_back(std::move(app)); } AppPublisher::Publish(std::move(apps), app_type_, /*should_notify_initialized=*/true); @@ -106,6 +119,10 @@ preferred_apps_list_.ApplyBulkUpdate(std::move(changes)); } + void InitializePreferredApps(apps::PreferredApps preferred_apps) override { + preferred_apps_list_.Init(std::move(preferred_apps)); + } + private: apps::PreferredAppsList preferred_apps_list_; }; @@ -562,6 +579,128 @@ proxy()->PreferredAppsList().FindPreferredAppForUrl(kTestUrl3)); } +TEST_F(AppServiceProxyPreferredAppsTest, PreferredApps) { + // Test Initialize. + GetPreferredAppsList().Init(); + + const char kAppId1[] = "abcdefg"; + const char kAppId2[] = "aaaaaaa"; + GURL filter_url = GURL("https://www.google.com/abc"); + auto intent_filter = apps_util::MakeIntentFilterForUrlScope(filter_url); + + GetPreferredAppsList().AddPreferredApp(kAppId1, intent_filter); + + FakePublisherForProxyTest pub(proxy(), AppType::kArc, + std::vector<std::string>{kAppId1, kAppId2}); + + // Test sync preferred app to all subscribers. + filter_url = GURL("https://www.abc.com/"); + GURL another_filter_url = GURL("https://www.test.com/"); + intent_filter = apps_util::MakeIntentFilterForUrlScope(filter_url); + auto another_intent_filter = + apps_util::MakeIntentFilterForUrlScope(another_filter_url); + + EXPECT_EQ(absl::nullopt, + GetPreferredAppsList().FindPreferredAppForUrl(filter_url)); + EXPECT_EQ(absl::nullopt, + GetPreferredAppsList().FindPreferredAppForUrl(another_filter_url)); + + proxy()->PreferredAppsImpl()->AddPreferredApp( + AppType::kUnknown, kAppId2, intent_filter->Clone(), + std::make_unique<Intent>(apps_util::kIntentActionView, filter_url), + /*from_publisher=*/true); + proxy()->PreferredAppsImpl()->AddPreferredApp( + AppType::kUnknown, kAppId2, another_intent_filter->Clone(), + std::make_unique<Intent>(apps_util::kIntentActionView, + another_filter_url), + /*from_publisher=*/true); + EXPECT_EQ(kAppId2, GetPreferredAppsList().FindPreferredAppForUrl(filter_url)); + EXPECT_EQ(kAppId2, + GetPreferredAppsList().FindPreferredAppForUrl(another_filter_url)); + + // Test that uninstall removes all the settings for the app. + pub.UninstallApps(std::vector<std::string>{kAppId2}); + EXPECT_EQ(absl::nullopt, + GetPreferredAppsList().FindPreferredAppForUrl(filter_url)); + EXPECT_EQ(absl::nullopt, + GetPreferredAppsList().FindPreferredAppForUrl(another_filter_url)); + + proxy()->PreferredAppsImpl()->AddPreferredApp( + AppType::kUnknown, kAppId2, intent_filter->Clone(), + std::make_unique<Intent>(apps_util::kIntentActionView, filter_url), + /*from_publisher=*/true); + proxy()->PreferredAppsImpl()->AddPreferredApp( + AppType::kUnknown, kAppId2, another_intent_filter->Clone(), + std::make_unique<Intent>(apps_util::kIntentActionView, + another_filter_url), + /*from_publisher=*/true); + + EXPECT_EQ(kAppId2, GetPreferredAppsList().FindPreferredAppForUrl(filter_url)); + EXPECT_EQ(kAppId2, + GetPreferredAppsList().FindPreferredAppForUrl(another_filter_url)); +} + +// Tests that writing a preferred app value before the PreferredAppsList is +// initialized queues the write for after initialization. +TEST_F(AppServiceProxyPreferredAppsTest, PreferredAppsWriteBeforeInit) { + base::RunLoop run_loop_read; + proxy()->ReInitializeForTesting(proxy()->profile(), + run_loop_read.QuitClosure()); + GURL filter_url("https://www.abc.com/"); + + std::string kAppId1 = "aaa"; + std::string kAppId2 = "bbb"; + + proxy()->PreferredAppsImpl()->AddPreferredApp( + AppType::kArc, kAppId1, + apps_util::MakeIntentFilterForMimeType("image/png"), nullptr, + /*from_publisher=*/false); + + IntentFilters filters; + filters.push_back(apps_util::MakeIntentFilterForUrlScope(filter_url)); + proxy()->SetSupportedLinksPreference(kAppId2, std::move(filters)); + + // Wait for the preferred apps list initialization to read from disk. + run_loop_read.Run(); + + // Both changes to the PreferredAppsList should have been applied. + std::vector<GURL> filesystem_urls( + {GURL("filesystem:chrome://foo/image.png")}); + std::vector<std::string> mime_types({"image/png"}); + ASSERT_EQ(kAppId1, + GetPreferredAppsList().FindPreferredAppForIntent( + apps_util::MakeShareIntent(filesystem_urls, mime_types))); + ASSERT_EQ(kAppId2, GetPreferredAppsList().FindPreferredAppForUrl(filter_url)); +} + +TEST_F(AppServiceProxyPreferredAppsTest, PreferredAppsPersistency) { + const char kAppId1[] = "abcdefg"; + GURL filter_url = GURL("https://www.google.com/abc"); + auto intent_filter = apps_util::MakeIntentFilterForUrlScope(filter_url); + { + base::RunLoop run_loop_read; + base::RunLoop run_loop_write; + proxy()->ReInitializeForTesting(proxy()->profile(), + run_loop_read.QuitClosure(), + run_loop_write.QuitClosure()); + run_loop_read.Run(); + proxy()->PreferredAppsImpl()->AddPreferredApp( + AppType::kUnknown, kAppId1, intent_filter->Clone(), + std::make_unique<Intent>(apps_util::kIntentActionView, filter_url), + /*from_publisher=*/false); + run_loop_write.Run(); + } + // Create a new impl to initialize preferred apps from the disk. + { + base::RunLoop run_loop_read; + proxy()->ReInitializeForTesting(proxy()->profile(), + run_loop_read.QuitClosure()); + run_loop_read.Run(); + EXPECT_EQ(kAppId1, + GetPreferredAppsList().FindPreferredAppForUrl(filter_url)); + } +} + TEST_F(AppServiceProxyPreferredAppsTest, PreferredAppsSetSupportedLinksPublisher) { GetPreferredAppsList().Init(); @@ -632,6 +771,68 @@ EXPECT_FALSE(pub.AppHasSupportedLinksPreference(kAppId3)); } +// Test that app with overlapped works properly. +TEST_F(AppServiceProxyPreferredAppsTest, PreferredAppsOverlap) { + // Test Initialize. + GetPreferredAppsList().Init(); + + const char kAppId1[] = "abcdefg"; + const char kAppId2[] = "hijklmn"; + + GURL filter_url_1 = GURL("https://www.google.com/abc"); + GURL filter_url_2 = GURL("http://www.google.com.au/abc"); + GURL filter_url_3 = GURL("https://www.abc.com/abc"); + + auto intent_filter_1 = apps_util::MakeIntentFilterForUrlScope(filter_url_1); + apps_util::AddConditionValue(ConditionType::kScheme, filter_url_2.scheme(), + PatternMatchType::kNone, intent_filter_1); + apps_util::AddConditionValue(ConditionType::kHost, filter_url_2.host(), + PatternMatchType::kNone, intent_filter_1); + + auto intent_filter_2 = apps_util::MakeIntentFilterForUrlScope(filter_url_3); + apps_util::AddConditionValue(ConditionType::kScheme, filter_url_2.scheme(), + PatternMatchType::kNone, intent_filter_2); + apps_util::AddConditionValue(ConditionType::kHost, filter_url_2.host(), + PatternMatchType::kNone, intent_filter_2); + + auto intent_filter_3 = apps_util::MakeIntentFilterForUrlScope(filter_url_1); + + EXPECT_EQ(absl::nullopt, + GetPreferredAppsList().FindPreferredAppForUrl(filter_url_1)); + EXPECT_EQ(absl::nullopt, + GetPreferredAppsList().FindPreferredAppForUrl(filter_url_2)); + EXPECT_EQ(absl::nullopt, + GetPreferredAppsList().FindPreferredAppForUrl(filter_url_3)); + EXPECT_EQ(0U, GetPreferredAppsList().GetEntrySize()); + EXPECT_EQ(0U, GetPreferredAppsList().GetEntrySize()); + + proxy()->PreferredAppsImpl()->AddPreferredApp( + AppType::kArc, kAppId1, intent_filter_1->Clone(), + std::make_unique<Intent>(apps_util::kIntentActionView, filter_url_1), + /*from_publisher=*/true); + EXPECT_EQ(kAppId1, + GetPreferredAppsList().FindPreferredAppForUrl(filter_url_1)); + EXPECT_EQ(kAppId1, + GetPreferredAppsList().FindPreferredAppForUrl(filter_url_2)); + EXPECT_EQ(absl::nullopt, + GetPreferredAppsList().FindPreferredAppForUrl(filter_url_3)); + EXPECT_EQ(1U, GetPreferredAppsList().GetEntrySize()); + + // Add preferred app with intent filter overlap with existing entry for + // another app will reset the preferred app setting for the other app. + proxy()->PreferredAppsImpl()->AddPreferredApp( + AppType::kArc, kAppId2, intent_filter_2->Clone(), + std::make_unique<Intent>(apps_util::kIntentActionView, filter_url_1), + /*from_publisher=*/true); + EXPECT_EQ(absl::nullopt, + GetPreferredAppsList().FindPreferredAppForUrl(filter_url_1)); + EXPECT_EQ(kAppId2, + GetPreferredAppsList().FindPreferredAppForUrl(filter_url_2)); + EXPECT_EQ(kAppId2, + GetPreferredAppsList().FindPreferredAppForUrl(filter_url_3)); + EXPECT_EQ(1U, GetPreferredAppsList().GetEntrySize()); +} + // Test that app with overlapped supported links works properly. TEST_F(AppServiceProxyPreferredAppsTest, PreferredAppsOverlapSupportedLink) { // Test Initialize. @@ -720,6 +921,37 @@ EXPECT_EQ(2U, GetPreferredAppsList().GetEntrySize()); } +// Test that duplicated entry will not be added. +TEST_F(AppServiceProxyPreferredAppsTest, PreferredAppsDuplicated) { + // Test Initialize. + GetPreferredAppsList().Init(); + + const char kAppId1[] = "abcdefg"; + + GURL filter_url = GURL("https://www.google.com/abc"); + + auto intent_filter = apps_util::MakeIntentFilterForUrlScope(filter_url); + + EXPECT_EQ(absl::nullopt, + GetPreferredAppsList().FindPreferredAppForUrl(filter_url)); + EXPECT_EQ(0U, GetPreferredAppsList().GetEntrySize()); + + proxy()->PreferredAppsImpl()->AddPreferredApp( + AppType::kArc, kAppId1, intent_filter->Clone(), + std::make_unique<Intent>(apps_util::kIntentActionView, filter_url), + /*from_publisher=*/true); + EXPECT_EQ(kAppId1, GetPreferredAppsList().FindPreferredAppForUrl(filter_url)); + EXPECT_EQ(1U, GetPreferredAppsList().GetEntrySize()); + EXPECT_EQ(1U, GetPreferredAppsList().GetEntrySize()); + + proxy()->PreferredAppsImpl()->AddPreferredApp( + AppType::kArc, kAppId1, intent_filter->Clone(), + std::make_unique<Intent>(apps_util::kIntentActionView, filter_url), + /*from_publisher=*/true); + EXPECT_EQ(kAppId1, GetPreferredAppsList().FindPreferredAppForUrl(filter_url)); + EXPECT_EQ(1U, GetPreferredAppsList().GetEntrySize()); +} + // Test that duplicated entry will not be added for supported links. TEST_F(AppServiceProxyPreferredAppsTest, PreferredAppsDuplicatedSupportedLink) { // Test Initialize.
diff --git a/chrome/browser/apps/app_service/subscriber_crosapi.cc b/chrome/browser/apps/app_service/subscriber_crosapi.cc index d90dd72..d1d2962 100644 --- a/chrome/browser/apps/app_service/subscriber_crosapi.cc +++ b/chrome/browser/apps/app_service/subscriber_crosapi.cc
@@ -18,6 +18,7 @@ #include "chrome/browser/ui/webui/settings/ash/app_management/app_management_uma.h" #include "components/services/app_service/public/cpp/app_registry_cache.h" #include "components/services/app_service/public/cpp/app_types.h" +#include "components/services/app_service/public/cpp/features.h" #include "components/services/app_service/public/mojom/types.mojom.h" namespace { @@ -191,8 +192,13 @@ void SubscriberCrosapi::AddPreferredApp(const std::string& app_id, crosapi::mojom::IntentPtr intent) { - proxy_->AddPreferredApp( - app_id, apps_util::ConvertCrosapiToAppServiceIntent(intent, profile_)); + if (base::FeatureList::IsEnabled(kAppServicePreferredAppsWithoutMojom)) { + proxy_->AddPreferredApp( + app_id, apps_util::CreateAppServiceIntentFromCrosapi(intent, profile_)); + } else { + proxy_->AddPreferredApp( + app_id, apps_util::ConvertCrosapiToAppServiceIntent(intent, profile_)); + } } void SubscriberCrosapi::ShowAppManagementPage(const std::string& app_id) {
diff --git a/chrome/browser/apps/app_service/subscriber_crosapi.h b/chrome/browser/apps/app_service/subscriber_crosapi.h index c8dfb9f..ffbea681 100644 --- a/chrome/browser/apps/app_service/subscriber_crosapi.h +++ b/chrome/browser/apps/app_service/subscriber_crosapi.h
@@ -46,7 +46,7 @@ void OnApps(const std::vector<AppPtr>& deltas); - void InitializePreferredApps(PreferredApps preferred_apps); + virtual void InitializePreferredApps(PreferredApps preferred_apps); virtual void OnPreferredAppsChanged(PreferredAppChangesPtr changes); protected:
diff --git a/chrome/browser/apps/platform_apps/platform_app_navigation_redirector.cc b/chrome/browser/apps/platform_apps/platform_app_navigation_redirector.cc index 45ad314..b9f5a2315 100644 --- a/chrome/browser/apps/platform_apps/platform_app_navigation_redirector.cc +++ b/chrome/browser/apps/platform_apps/platform_app_navigation_redirector.cc
@@ -32,6 +32,7 @@ const std::string& handler_id, content::NavigationHandle* navigation_handle) { DCHECK_CURRENTLY_ON(BrowserThread::UI); + DCHECK(navigation_handle->IsInMainFrame()); // Redirect top-level navigations only. This excludes iframes and webviews // in particular. @@ -40,6 +41,11 @@ return false; } + if (navigation_handle->IsInPrerenderedMainFrame()) { + // If it's from prerendering, don't launch the app but abort the navigation. + return true; + } + // If no-state prefetching, don't launch the app but abort the navigation. prerender::NoStatePrefetchContents* no_state_prefetch_contents = prerender::ChromeNoStatePrefetchContentsDelegate::FromWebContents(
diff --git a/chrome/browser/apps/platform_apps/platform_app_navigation_redirector_browsertest.cc b/chrome/browser/apps/platform_apps/platform_app_navigation_redirector_browsertest.cc index 91377d0..3d41585 100644 --- a/chrome/browser/apps/platform_apps/platform_app_navigation_redirector_browsertest.cc +++ b/chrome/browser/apps/platform_apps/platform_app_navigation_redirector_browsertest.cc
@@ -13,6 +13,7 @@ #include "content/public/test/browser_test.h" #include "content/public/test/browser_test_base.h" #include "content/public/test/browser_test_utils.h" +#include "content/public/test/prerender_test_util.h" #include "extensions/test/extension_test_message_listener.h" #include "net/test/embedded_test_server/embedded_test_server.h" #include "ui/base/page_transition_types.h" @@ -425,4 +426,53 @@ "XHR failed", "url_handlers/handlers/steal_xhr_target"); } +class PlatformAppNavigationRedirectorPrerenderingBrowserTest + : public PlatformAppNavigationRedirectorBrowserTest { + public: + PlatformAppNavigationRedirectorPrerenderingBrowserTest() + : prerender_helper_(base::BindRepeating( + &PlatformAppNavigationRedirectorPrerenderingBrowserTest:: + GetWebContents, + base::Unretained(this))) {} + ~PlatformAppNavigationRedirectorPrerenderingBrowserTest() override = default; + + content::WebContents* GetWebContents() { + return browser()->tab_strip_model()->GetActiveWebContents(); + } + + content::test::PrerenderTestHelper& prerender_helper() { + return prerender_helper_; + } + + private: + content::test::PrerenderTestHelper prerender_helper_; +}; + +// Test that prerendering doesn't launch an app but aborts the navigation. +IN_PROC_BROWSER_TEST_F(PlatformAppNavigationRedirectorPrerenderingBrowserTest, + DoNotLaunchAppInPrerendering) { + ASSERT_TRUE(StartEmbeddedTestServer()); + const char* handler = "url_handlers/handlers/simple"; + InstallPlatformApp(handler); + + const auto initial_url = embedded_test_server()->GetURL("/empty.html"); + ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), initial_url)); + EXPECT_EQ(initial_url, GetWebContents()->GetLastCommittedURL()); + + const auto prerender_url = embedded_test_server()->GetURL( + "/extensions/platform_apps/url_handlers/common/target.html"); + + // Loading an app URL in prerendering cancels prerendering. + prerender_helper().AddPrerenderAsync(prerender_url); + content::test::PrerenderHostObserver host_observer(*GetWebContents(), + prerender_url); + // Wait until PrerenderHost is destroyed by canceling prerendering. + host_observer.WaitForDestroyed(); + + // The primary page doesn't have any change. + EXPECT_EQ(initial_url, GetWebContents()->GetLastCommittedURL()); + EXPECT_EQ(1, browser()->tab_strip_model()->count()); + EXPECT_EQ(0U, GetAppWindowCount()); +} + } // namespace extensions
diff --git a/chrome/browser/ash/BUILD.gn b/chrome/browser/ash/BUILD.gn index 9d9b08d..12a9e90 100644 --- a/chrome/browser/ash/BUILD.gn +++ b/chrome/browser/ash/BUILD.gn
@@ -1116,6 +1116,176 @@ "floating_workspace/floating_workspace_util.h", "fusebox/fusebox_util.cc", "fusebox/fusebox_util.h", + "guest_os/guest_os_capabilities.cc", + "guest_os/guest_os_capabilities.h", + "guest_os/guest_os_diagnostics_builder.cc", + "guest_os/guest_os_diagnostics_builder.h", + "guest_os/guest_os_external_protocol_handler.cc", + "guest_os/guest_os_external_protocol_handler.h", + "guest_os/guest_os_launcher.cc", + "guest_os/guest_os_launcher.h", + "guest_os/guest_os_mime_types_service.cc", + "guest_os/guest_os_mime_types_service.h", + "guest_os/guest_os_mime_types_service_factory.cc", + "guest_os/guest_os_mime_types_service_factory.h", + "guest_os/guest_os_pref_names.cc", + "guest_os/guest_os_pref_names.h", + "guest_os/guest_os_registry_service.cc", + "guest_os/guest_os_registry_service.h", + "guest_os/guest_os_registry_service_factory.cc", + "guest_os/guest_os_registry_service_factory.h", + "guest_os/guest_os_share_path.cc", + "guest_os/guest_os_share_path.h", + "guest_os/guest_os_share_path_factory.cc", + "guest_os/guest_os_share_path_factory.h", + "guest_os/guest_os_stability_monitor.cc", + "guest_os/guest_os_stability_monitor.h", + "guest_os/infra/cached_callback.h", + "guest_os/public/guest_os_mount_provider.cc", + "guest_os/public/guest_os_mount_provider.h", + "guest_os/public/guest_os_mount_provider_registry.cc", + "guest_os/public/guest_os_mount_provider_registry.h", + "guest_os/public/guest_os_service.cc", + "guest_os/public/guest_os_service.h", + "guest_os/public/guest_os_service_factory.cc", + "guest_os/public/guest_os_service_factory.h", + "guest_os/public/guest_os_terminal_provider.cc", + "guest_os/public/guest_os_terminal_provider.h", + "guest_os/public/guest_os_terminal_provider_registry.cc", + "guest_os/public/guest_os_terminal_provider_registry.h", + "guest_os/public/guest_os_wayland_server.cc", + "guest_os/public/guest_os_wayland_server.h", + "guest_os/public/installer_delegate_factory.cc", + "guest_os/public/installer_delegate_factory.h", + "guest_os/public/types.h", + "guest_os/virtual_machines/virtual_machines_util.cc", + "guest_os/virtual_machines/virtual_machines_util.h", + "guest_os/vm_sk_forwarding_native_message_host.cc", + "guest_os/vm_sk_forwarding_native_message_host.h", + "hats/hats_config.cc", + "hats/hats_config.h", + "hats/hats_dialog.cc", + "hats/hats_dialog.h", + "hats/hats_finch_helper.cc", + "hats/hats_finch_helper.h", + "hats/hats_notification_controller.cc", + "hats/hats_notification_controller.h", + "idle_detector.cc", + "idle_detector.h", + "input_method/accessibility.cc", + "input_method/accessibility.h", + "input_method/assistive_suggester.cc", + "input_method/assistive_suggester.h", + "input_method/assistive_suggester_client_filter.cc", + "input_method/assistive_suggester_client_filter.h", + "input_method/assistive_suggester_prefs.cc", + "input_method/assistive_suggester_prefs.h", + "input_method/assistive_suggester_switch.h", + "input_method/assistive_window_controller.cc", + "input_method/assistive_window_controller.h", + "input_method/assistive_window_controller_delegate.h", + "input_method/assistive_window_properties.cc", + "input_method/assistive_window_properties.h", + "input_method/autocorrect_manager.cc", + "input_method/autocorrect_manager.h", + "input_method/candidate_window_controller.cc", + "input_method/candidate_window_controller.h", + "input_method/candidate_window_controller_impl.cc", + "input_method/candidate_window_controller_impl.h", + "input_method/component_extension_ime_manager_delegate_impl.cc", + "input_method/component_extension_ime_manager_delegate_impl.h", + "input_method/diacritics_checker.cc", + "input_method/diacritics_checker.h", + "input_method/diacritics_insensitive_string_comparator.cc", + "input_method/diacritics_insensitive_string_comparator.h", + "input_method/emoji_suggester.cc", + "input_method/emoji_suggester.h", + "input_method/get_browser_url.cc", + "input_method/get_browser_url.h", + "input_method/grammar_manager.cc", + "input_method/grammar_manager.h", + "input_method/grammar_service_client.cc", + "input_method/grammar_service_client.h", + "input_method/ime_rules_config.cc", + "input_method/ime_rules_config.h", + "input_method/ime_service_connector.cc", + "input_method/ime_service_connector.h", + "input_method/input_method_configuration.cc", + "input_method/input_method_configuration.h", + "input_method/input_method_delegate_impl.cc", + "input_method/input_method_delegate_impl.h", + "input_method/input_method_engine.cc", + "input_method/input_method_engine.h", + "input_method/input_method_engine_observer.h", + "input_method/input_method_manager_impl.cc", + "input_method/input_method_manager_impl.h", + "input_method/input_method_persistence.cc", + "input_method/input_method_persistence.h", + "input_method/input_method_quick_settings_helpers.cc", + "input_method/input_method_quick_settings_helpers.h", + "input_method/input_method_settings.cc", + "input_method/input_method_settings.h", + "input_method/input_method_syncer.cc", + "input_method/input_method_syncer.h", + "input_method/longpress_diacritics_suggester.cc", + "input_method/longpress_diacritics_suggester.h", + "input_method/multi_word_suggester.cc", + "input_method/multi_word_suggester.h", + "input_method/native_input_method_engine.cc", + "input_method/native_input_method_engine.h", + "input_method/native_input_method_engine_observer.cc", + "input_method/native_input_method_engine_observer.h", + "input_method/personal_info_suggester.cc", + "input_method/personal_info_suggester.h", + "input_method/suggester.h", + "input_method/suggestion_enums.h", + "input_method/suggestion_handler_interface.h", + "input_method/suggestions_collector.cc", + "input_method/suggestions_collector.h", + "input_method/suggestions_service_client.cc", + "input_method/suggestions_service_client.h", + "input_method/suggestions_source.h", + "input_method/text_field_contextual_info_fetcher.cc", + "input_method/text_field_contextual_info_fetcher.h", + "input_method/text_utils.cc", + "input_method/text_utils.h", + "input_method/ui/assistive_accessibility_view.cc", + "input_method/ui/assistive_accessibility_view.h", + "input_method/ui/assistive_delegate.h", + "input_method/ui/border_factory.cc", + "input_method/ui/border_factory.h", + "input_method/ui/candidate_view.cc", + "input_method/ui/candidate_view.h", + "input_method/ui/candidate_window_constants.h", + "input_method/ui/candidate_window_view.cc", + "input_method/ui/candidate_window_view.h", + "input_method/ui/colors.cc", + "input_method/ui/colors.h", + "input_method/ui/completion_suggestion_label_view.cc", + "input_method/ui/completion_suggestion_label_view.h", + "input_method/ui/completion_suggestion_view.cc", + "input_method/ui/completion_suggestion_view.h", + "input_method/ui/grammar_suggestion_window.cc", + "input_method/ui/grammar_suggestion_window.h", + "input_method/ui/infolist_window.cc", + "input_method/ui/infolist_window.h", + "input_method/ui/input_method_menu_item.cc", + "input_method/ui/input_method_menu_item.h", + "input_method/ui/input_method_menu_manager.cc", + "input_method/ui/input_method_menu_manager.h", + "input_method/ui/suggestion_accessibility_label.cc", + "input_method/ui/suggestion_accessibility_label.h", + "input_method/ui/suggestion_details.h", + "input_method/ui/suggestion_window_view.cc", + "input_method/ui/suggestion_window_view.h", + "input_method/ui/undo_window.cc", + "input_method/ui/undo_window.h", + "kerberos/kerberos_credentials_manager.cc", + "kerberos/kerberos_credentials_manager.h", + "kerberos/kerberos_credentials_manager_factory.cc", + "kerberos/kerberos_credentials_manager_factory.h", + "kerberos/kerberos_ticket_expiry_notification.cc", + "kerberos/kerberos_ticket_expiry_notification.h", ] allow_circular_includes_from = [ @@ -1146,18 +1316,24 @@ "//ash/components/login/auth", "//ash/components/settings", "//ash/components/tpm", + "//ash/constants", "//ash/public/cpp", "//ash/public/cpp/external_arc", "//ash/services/device_sync/proto", "//ash/services/device_sync/public/cpp", + "//ash/services/ime/public/cpp:structs", + "//ash/services/ime/public/mojom", "//ash/services/multidevice_setup/public/cpp", "//ash/services/multidevice_setup/public/cpp:android_sms_app_helper_delegate", "//ash/services/multidevice_setup/public/cpp:android_sms_pairing_state_tracker", "//ash/webui/eche_app_ui", + "//ash/webui/guest_os_installer/mojom", "//base", + "//build:chromeos_buildflags", "//chrome/browser/ash/arc/input_overlay/db/proto", "//chrome/browser/ash/crosapi", "//chrome/browser/ash/crostini:crostini_installer_types_mojom", + "//chrome/browser/ash/guest_os:guest_os_diagnostics_mojom", "//chrome/browser/chromeos", "//chrome/browser/extensions", "//chrome/browser/image_decoder", @@ -1167,6 +1343,7 @@ "//chrome/browser/web_applications", "//chrome/common", "//chrome/common:buildflags", + "//chrome/common:chrome_features", "//chrome/common:constants", "//chrome/common/extensions/api", "//chrome/services/file_util/public/cpp", @@ -1178,16 +1355,24 @@ "//chromeos/ash/components/dbus/cicerone:cicerone_proto", "//chromeos/ash/components/dbus/concierge", "//chromeos/ash/components/dbus/concierge:concierge_proto", + "//chromeos/ash/components/dbus/kerberos:kerberos_proto", + "//chromeos/ash/components/dbus/seneschal", + "//chromeos/ash/components/dbus/seneschal:seneschal_proto", "//chromeos/ash/components/dbus/services", "//chromeos/ash/components/dbus/system_clock", "//chromeos/ash/components/memory", + "//chromeos/ash/components/network/portal_detector", + "//chromeos/components/onc", "//chromeos/components/sharesheet:constants", "//chromeos/crosapi/mojom", "//chromeos/dbus:metrics_event_proto", + "//chromeos/dbus:vm_applications_apps_proto", + "//chromeos/dbus:vm_launch_proto", "//chromeos/dbus/anomaly_detector", "//chromeos/dbus/anomaly_detector:proto", "//chromeos/dbus/attestation", "//chromeos/dbus/attestation:attestation_proto", + "//chromeos/dbus/chunneld", "//chromeos/dbus/common", "//chromeos/dbus/constants", "//chromeos/dbus/cros_disks", @@ -1202,12 +1387,14 @@ "//chromeos/metrics", "//chromeos/network", "//chromeos/services/cros_healthd/public/mojom", + "//chromeos/services/machine_learning/public/mojom", "//chromeos/ui/base", "//components/account_id", "//components/account_manager_core", "//components/app_restore", "//components/arc", "//components/arc/common", + "//components/autofill/core/browser", "//components/content_settings/core/browser", "//components/download/content/public", "//components/drive", @@ -1271,6 +1458,7 @@ "//third_party/abseil-cpp:absl", "//third_party/blink/public/mojom:mojom_platform", "//third_party/boringssl", + "//third_party/icu", "//ui/accessibility", "//ui/accessibility:ax_base", "//ui/accessibility:ax_enums_mojo_headers", @@ -1278,9 +1466,11 @@ "//ui/base", "//ui/base:ui_data_pack", "//ui/base/ime", + "//ui/base/ime:ime_types", "//ui/base/ime/ash", "//ui/base/metadata", "//ui/chromeos/events", + "//ui/chromeos/styles:cros_styles_views", "//ui/compositor", "//ui/display", "//ui/display/types", @@ -1290,9 +1480,11 @@ "//ui/gfx", "//ui/gfx:native_widget_types", "//ui/gfx/geometry", + "//ui/gfx/range", "//ui/message_center/public/cpp", "//ui/shell_dialogs", "//ui/views", + "//ui/web_dialogs", "//ui/wm/public", "//url", ] @@ -1315,12 +1507,12 @@ "//ash/components/peripheral_notification", "//ash/components/phonehub", "//ash/components/power", - "//ash/constants", "//ash/keyboard/ui", "//ash/public/mojom", "//ash/resources/vector_icons", "//ash/services/device_sync", "//ash/services/device_sync:stub_device_sync", + "//ash/services/ime:constants", "//ash/services/multidevice_setup/public/cpp:prefs", "//ash/services/multidevice_setup/public/mojom", "//ash/services/secure_channel", @@ -1330,6 +1522,7 @@ "//ash/webui/file_manager:constants", "//ash/webui/file_manager:file_manager_ui", "//ash/webui/file_manager:file_manager_untrusted_ui", + "//ash/webui/guest_os_installer", "//ash/webui/shimless_rma", "//base:i18n", "//build:branding_buildflags", @@ -1347,11 +1540,11 @@ "//chrome/browser/metrics/structured", "//chrome/browser/profiles", "//chrome/browser/resources:component_extension_resources", + "//chrome/browser/resources/chromeos:app_icon_resources", "//chrome/browser/ui/webui/chromeos/crostini_upgrader:mojo_bindings", "//chrome/browser/ui/webui/settings/chromeos/constants:mojom", "//chrome/browser/webshare:storage", "//chrome/common:channel_info", - "//chrome/common:chrome_features", "//chrome/common:non_code_constants", "//chrome/common/net", "//chromeos/ash/components/dbus/biod", @@ -1366,26 +1559,21 @@ "//chromeos/ash/components/dbus/pciguard", "//chromeos/ash/components/dbus/rgbkbd", "//chromeos/ash/components/dbus/rmad", - "//chromeos/ash/components/dbus/seneschal", "//chromeos/ash/components/dbus/spaced", "//chromeos/ash/components/dbus/system_proxy", "//chromeos/ash/components/dbus/typecd", "//chromeos/ash/components/dbus/upstart", "//chromeos/ash/components/hibernate:buildflags", - "//chromeos/ash/components/network/portal_detector", "//chromeos/components/cdm_factory_daemon:cdm_factory_daemon_browser", "//chromeos/components/chromebox_for_meetings/buildflags", "//chromeos/components/disks:prefs", "//chromeos/components/local_search_service/public/cpp", "//chromeos/components/mojo_bootstrap", - "//chromeos/components/onc", "//chromeos/components/sensors", "//chromeos/constants", "//chromeos/dbus", "//chromeos/dbus:plugin_vm_service_proto", - "//chromeos/dbus:vm_applications_apps_proto", "//chromeos/dbus:vm_disk_management_proto", - "//chromeos/dbus:vm_launch_proto", "//chromeos/dbus:vm_permission_service_proto", "//chromeos/dbus:vm_sk_forwarding_proto", "//chromeos/dbus/arc", @@ -1401,6 +1589,7 @@ "//chromeos/dbus/hermes", "//chromeos/dbus/human_presence", "//chromeos/dbus/init", + "//chromeos/dbus/lorgnette_manager", "//chromeos/dbus/machine_learning", "//chromeos/dbus/permission_broker", "//chromeos/dbus/tpm_manager", @@ -1408,6 +1597,7 @@ "//chromeos/dbus/userdataauth", "//chromeos/dbus/util", "//chromeos/dbus/virtual_file_provider", + "//chromeos/ime:gencode", "//chromeos/login/login_state", "//chromeos/services/assistant/public/cpp", "//chromeos/services/cros_healthd/private/cpp", @@ -1426,6 +1616,7 @@ "//components/device_event_log", "//components/download/public/common:public", "//components/embedder_support:browser_util", + "//components/exo/server", "//components/gcm_driver", "//components/google/core/common", "//components/guest_os:prefs", @@ -1454,12 +1645,14 @@ "//components/services/unzip/content", "//components/services/unzip/public/mojom", "//components/signin/public/base", + "//components/spellcheck/browser", "//components/strings:components_strings", "//components/sync/base", "//components/sync/driver", "//components/sync_sessions", "//components/translate/core/browser", "//components/url_matcher", + "//components/user_prefs", "//components/vector_icons", "//components/version_info", "//components/version_info:channel", @@ -1492,7 +1685,6 @@ "//services/network/public/mojom:url_loader_base", "//services/tracing/public/mojom", "//third_party/blink/public/common:headers", - "//third_party/icu", "//third_party/re2", "//third_party/securemessage/proto", "//third_party/zlib/google:zip", @@ -1502,10 +1694,10 @@ "//ui/base/clipboard:clipboard_types", "//ui/base/clipboard:file_info", "//ui/base/data_transfer_policy", + "//ui/base/ime:text_input_types", "//ui/chromeos", "//ui/chromeos/resources", "//ui/chromeos/strings", - "//ui/chromeos/styles:cros_styles_views", "//ui/color", "//ui/color:color_headers", "//ui/color:mixers", @@ -1519,6 +1711,7 @@ "//ui/gfx/codec", "//ui/message_center", "//ui/native_theme", + "//ui/ozone", "//ui/strings:ui_strings", "//ui/views/controls/webview", "//ui/wm",
diff --git a/chrome/browser/ash/arc/input_overlay/ui/input_menu_view.cc b/chrome/browser/ash/arc/input_overlay/ui/input_menu_view.cc index 9461293..4460a838 100644 --- a/chrome/browser/ash/arc/input_overlay/ui/input_menu_view.cc +++ b/chrome/browser/ash/arc/input_overlay/ui/input_menu_view.cc
@@ -324,7 +324,7 @@ std::unique_ptr<views::View> InputMenuView::BuildSeparator() { auto separator = std::make_unique<views::Separator>(); - separator->SetColorId(ui::kColorAshArcInputMenuSeparator); + separator->SetColorId(ui::kColorAshSystemUIMenuSeparator); return std::move(separator); }
diff --git a/chrome/browser/ash/crosapi/audio_service_ash.cc b/chrome/browser/ash/crosapi/audio_service_ash.cc index 0534482f..2220c48 100644 --- a/chrome/browser/ash/crosapi/audio_service_ash.cc +++ b/chrome/browser/ash/crosapi/audio_service_ash.cc
@@ -14,7 +14,7 @@ namespace crosapi { -// TODO: Add unit tests for AudioServiceAsh (b/235565865) +// TODO: Add unit tests for AudioServiceAsh (b/235565865). AudioServiceAsh::Observer::Observer() = default; AudioServiceAsh::Observer::~Observer() = default; @@ -24,11 +24,6 @@ audio_service_observation_.Observe(service); } -void AudioServiceAsh::Observer::OnDeviceChanged() { - // Not implemented, because this event is deprecated in chrome.audio API. - // TODO: Should have been removed in M60, see (http://crbug.com/697279). -} - void AudioServiceAsh::Observer::OnLevelChanged(const std::string& id, int level) { for (auto& observer : observers_) { @@ -64,7 +59,7 @@ void AudioServiceAsh::Initialize(Profile* profile) { DCHECK(profile); if (stable_id_calculator_) { - // TODO: investigate why crosapi ash object inits are called more than once + // TODO: investigate why crosapi ash object inits are called more than once. // (b/235203815) LOG(WARNING) << "AudioServiceAsh was already initialized. Not initializing again."; @@ -154,9 +149,7 @@ bool success = false; if (properties) { - // reusing existing volume/gain method, thus same param passed twice - success = - service_->SetDeviceSoundLevel(id, properties->level, properties->level); + success = service_->SetDeviceSoundLevel(id, properties->level); } std::move(callback).Run(success); }
diff --git a/chrome/browser/ash/crosapi/audio_service_ash.h b/chrome/browser/ash/crosapi/audio_service_ash.h index 65132f0b..51bc899 100644 --- a/chrome/browser/ash/crosapi/audio_service_ash.h +++ b/chrome/browser/ash/crosapi/audio_service_ash.h
@@ -19,7 +19,7 @@ namespace crosapi { -// Implements the crosapi interface for audio service API +// Implements the crosapi interface for audio service API. class AudioServiceAsh : public mojom::AudioService { public: AudioServiceAsh(); @@ -56,7 +56,6 @@ void Initialize(extensions::AudioService* service); // extensions::AudioService::Observer implementation: - void OnDeviceChanged() override; void OnLevelChanged(const std::string& id, int level) override; void OnMuteChanged(bool is_input, bool is_muted) override; void OnDevicesChanged(const extensions::DeviceInfoList& devices) override; @@ -79,7 +78,7 @@ std::unique_ptr<extensions::AudioDeviceIdCalculator> stable_id_calculator_; std::unique_ptr<extensions::AudioService> service_; - // Observer must be defined after AudioService for a correct destruction order + // Observer must be defined after service for a correct destruction order. Observer observer_; };
diff --git a/chrome/browser/ash/crosapi/browser_manager.cc b/chrome/browser/ash/crosapi/browser_manager.cc index 7ac97e0f..7120f6cc 100644 --- a/chrome/browser/ash/crosapi/browser_manager.cc +++ b/chrome/browser/ash/crosapi/browser_manager.cc
@@ -86,6 +86,7 @@ #include "components/session_manager/core/session_manager.h" #include "components/user_manager/user_type.h" #include "components/version_info/version_info.h" +#include "media/capture/capture_switches.h" #include "mojo/public/cpp/bindings/pending_remote.h" #include "mojo/public/cpp/platform/platform_channel.h" #include "ui/base/l10n/l10n_util.h" @@ -1093,6 +1094,12 @@ for (const auto& flag : delimited_flags) argv.emplace_back(flag); + // Forward flag for zero copy video capture to Lacros if it is enabled. + if (switches::IsVideoCaptureUseGpuMemoryBufferEnabled()) { + argv.emplace_back( + base::StringPrintf("--%s", switches::kVideoCaptureUseGpuMemoryBuffer)); + } + // If logfd is valid, enable logging and redirect stdout/stderr to logfd. if (params.logfd.is_valid()) { // The next flag will make chrome log only via stderr. See
diff --git a/chrome/browser/ash/crosapi/networking_private_ash.cc b/chrome/browser/ash/crosapi/networking_private_ash.cc index b7a5bfe5..312dc52f 100644 --- a/chrome/browser/ash/crosapi/networking_private_ash.cc +++ b/chrome/browser/ash/crosapi/networking_private_ash.cc
@@ -425,8 +425,10 @@ std::move(observer))); if (!is_listening_network_state) { - network_state_observation_.Observe( - NetworkHandler::Get()->network_state_handler()); + auto* net_handler = NetworkHandler::Get(); + network_state_observation_.Observe(net_handler->network_state_handler()); + network_certificate_observation_.Observe( + net_handler->network_certificate_handler()); } } @@ -490,9 +492,16 @@ } } +void NetworkingPrivateAsh::OnCertificatesChanged() { + for (auto& observer : observers_) { + observer->OnCertificateListsChanged(); + } +} + void NetworkingPrivateAsh::OnObserverDisconnected(mojo::RemoteSetElementId id) { if (observers_.empty()) { network_state_observation_.Reset(); + network_certificate_observation_.Reset(); } }
diff --git a/chrome/browser/ash/crosapi/networking_private_ash.h b/chrome/browser/ash/crosapi/networking_private_ash.h index 0a247d8..d6d745d 100644 --- a/chrome/browser/ash/crosapi/networking_private_ash.h +++ b/chrome/browser/ash/crosapi/networking_private_ash.h
@@ -7,6 +7,7 @@ #include "base/scoped_observation.h" #include "chromeos/crosapi/mojom/networking_private.mojom.h" +#include "chromeos/network/network_certificate_handler.h" #include "chromeos/network/network_state_handler.h" #include "chromeos/network/network_state_handler_observer.h" #include "mojo/public/cpp/bindings/pending_receiver.h" @@ -16,8 +17,10 @@ namespace crosapi { // The ash-chrome implementation of the NetworkingPrivate crosapi interface. -class NetworkingPrivateAsh : public mojom::NetworkingPrivate, - public chromeos::NetworkStateHandlerObserver { +class NetworkingPrivateAsh + : public mojom::NetworkingPrivate, + public chromeos::NetworkStateHandlerObserver, + public chromeos::NetworkCertificateHandler::Observer { public: NetworkingPrivateAsh(); NetworkingPrivateAsh(const NetworkingPrivateAsh&) = delete; @@ -98,6 +101,9 @@ const chromeos::NetworkState* default_network, chromeos::NetworkState::PortalState portal_state) override; + // NetworkCertificateHandler::Observer overrides: + void OnCertificatesChanged() override; + private: void OnObserverDisconnected(mojo::RemoteSetElementId id); @@ -107,6 +113,9 @@ base::ScopedObservation<chromeos::NetworkStateHandler, chromeos::NetworkStateHandlerObserver> network_state_observation_{this}; + base::ScopedObservation<chromeos::NetworkCertificateHandler, + chromeos::NetworkCertificateHandler::Observer> + network_certificate_observation_{this}; // This class supports any number of connections. mojo::ReceiverSet<mojom::NetworkingPrivate> receivers_; };
diff --git a/chrome/browser/ash/file_manager/file_manager_jstest.cc b/chrome/browser/ash/file_manager/file_manager_jstest.cc index 2394711..a733e95 100644 --- a/chrome/browser/ash/file_manager/file_manager_jstest.cc +++ b/chrome/browser/ash/file_manager/file_manager_jstest.cc
@@ -7,8 +7,9 @@ class FileManagerJsTest : public FileManagerJsTestBase { protected: - FileManagerJsTest() : FileManagerJsTestBase( - base::FilePath(FILE_PATH_LITERAL("ui/file_manager/file_manager"))) {} + FileManagerJsTest() + : FileManagerJsTestBase( + base::FilePath(FILE_PATH_LITERAL("file_manager"))) {} }; // Tests that draw to canvases and test pixels need pixel output turned on. @@ -293,3 +294,7 @@ IN_PROC_BROWSER_TEST_F(FileManagerJsTest, VolumeManagerTypesTest) { RunTestURL("common/js/volume_manager_types_unittest.m_gen.html"); } + +IN_PROC_BROWSER_TEST_F(FileManagerJsTest, RecentDateBucketTest) { + RunTestURL("common/js/recent_date_bucket_unittest.m_gen.html"); +}
diff --git a/chrome/browser/ash/file_manager/file_manager_jstest_base.cc b/chrome/browser/ash/file_manager/file_manager_jstest_base.cc index 56d23d6..5c430466 100644 --- a/chrome/browser/ash/file_manager/file_manager_jstest_base.cc +++ b/chrome/browser/ash/file_manager/file_manager_jstest_base.cc
@@ -25,6 +25,7 @@ #include "content/public/test/scoped_web_ui_controller_factory_registration.h" #include "net/base/filename_util.h" #include "services/network/public/mojom/content_security_policy.mojom.h" +#include "ui/base/resource/resource_bundle.h" namespace { @@ -34,133 +35,6 @@ return executable_path.AppendASCII("gen"); } -// URLDataSource for the test URL chrome://file_manager_test/. It reads files -// directly from repository source. -class TestFilesDataSource : public content::URLDataSource { - public: - TestFilesDataSource() {} - - TestFilesDataSource(const TestFilesDataSource&) = delete; - TestFilesDataSource& operator=(const TestFilesDataSource&) = delete; - - ~TestFilesDataSource() override {} - - private: - // This has to match TestResourceUrl() - std::string GetSource() override { return "file_manager_test"; } - - void StartDataRequest( - const GURL& url, - const content::WebContents::Getter& wc_getter, - content::URLDataSource::GotDataCallback callback) override { - const std::string path = content::URLDataSource::URLToRequestPath(url); - base::ThreadPool::PostTask( - FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_BLOCKING}, - base::BindOnce(&TestFilesDataSource::ReadFile, base::Unretained(this), - path, std::move(callback))); - } - - void ReadFile(const std::string& path, - content::URLDataSource::GotDataCallback callback) { - if (source_root_.empty()) { - CHECK(base::PathService::Get(base::DIR_SOURCE_ROOT, &source_root_)); - } - if (gen_root_.empty()) { - CHECK(base::PathService::Get(base::DIR_EXE, &gen_root_)); - gen_root_ = GetGenRoot(); - } - - std::string content; - - base::FilePath src_file_path = - source_root_.Append(base::FilePath::FromUTF8Unsafe(path)); - base::FilePath gen_file_path = - gen_root_.Append(base::FilePath::FromUTF8Unsafe(path)); - - // File manager sets up the embedded test server with a specific base path, - // and the server assumes all paths are relative to this path without - // checking for absolute URLs. Hence, absolute URLS are transformed to - // requests for <some_base_path>/chrome://resources/<path_to_resource>. - // Strip off the assumed base path and replace chrome://resources with - // ui/webui/resources in this case. - const char kResourcesUrl[] = "chrome://resources"; - size_t url_pos = path.find(kResourcesUrl); - if (url_pos != std::string::npos) { - std::string new_path = - "ui/webui/resources" + - path.substr(url_pos + std::size(kResourcesUrl) - 1); - src_file_path = - source_root_.Append(base::FilePath::FromUTF8Unsafe(new_path)); - gen_file_path = - gen_root_.Append(base::FilePath::FromUTF8Unsafe(new_path)); - } - - // Do some basic validation of the file extension. - CHECK(src_file_path.Extension() == ".html" || - src_file_path.Extension() == ".js" || - src_file_path.Extension() == ".css" || - src_file_path.Extension() == ".svg") - << "chrome://file_manager_test/ only supports .html/.js/.css/.svg " - "extension files"; - - CHECK(base::PathExists(src_file_path) || base::PathExists(gen_file_path)) - << src_file_path << " or: " << gen_file_path << " input path: " << path; - CHECK(base::ReadFileToString(gen_file_path, &content) || - base::ReadFileToString(src_file_path, &content)) - << src_file_path << " or: " << gen_file_path; - - scoped_refptr<base::RefCountedString> response = - base::RefCountedString::TakeString(&content); - std::move(callback).Run(response.get()); - } - - bool ShouldServeMimeTypeAsContentTypeHeader() override { return true; } - - // It currently only serves HTML/JS/CSS/SVG. - std::string GetMimeType(const std::string& path) override { - if (base::EndsWith(path, ".html", base::CompareCase::INSENSITIVE_ASCII)) { - return "text/html"; - } - - if (base::EndsWith(path, ".css", base::CompareCase::INSENSITIVE_ASCII)) { - return "text/css"; - } - - if (base::EndsWith(path, ".js", base::CompareCase::INSENSITIVE_ASCII)) { - return "application/javascript"; - } - - if (base::EndsWith(path, ".svg", base::CompareCase::INSENSITIVE_ASCII)) { - return "image/svg+xml"; - } - - LOG(FATAL) << "unsupported file type: " << path; - return {}; - } - - std::string GetContentSecurityPolicy( - const network::mojom::CSPDirectiveName directive) override { - if (directive == network::mojom::CSPDirectiveName::ScriptSrc) { - // Add 'unsafe-inline' to CSP to allow the inline <script> in the - // generated HTML to run see js_test_gen_html.py. - return "script-src chrome://resources chrome://test 'self' " - "chrome-extension://hhaomjibdihmijegdhdafkllkbggdgoj " - "chrome-extension://pmfjbimdmchhbnneeidfognadeopoehp " - "'unsafe-inline'; "; - } else if (directive == - network::mojom::CSPDirectiveName::RequireTrustedTypesFor || - directive == network::mojom::CSPDirectiveName::TrustedTypes) { - return std::string(); - } - - return content::URLDataSource::GetContentSecurityPolicy(directive); - } - - // Root of repository source, where files are served directly from. - base::FilePath source_root_; - base::FilePath gen_root_; -}; - // WebUIProvider to attach the URLDataSource for the test URL during tests. // Used to start the unittest from a chrome:// URL which allows unittest files // (HTML/JS/CSS) to load other resources from WebUI URLs chrome://*. @@ -176,21 +50,36 @@ std::unique_ptr<content::WebUIController> NewWebUI(content::WebUI* web_ui, const GURL& url) override { - auto* profile = Profile::FromWebUI(web_ui); - content::URLDataSource::Add(profile, - std::make_unique<TestFilesDataSource>()); - content::URLDataSource::Add(profile, - std::make_unique<TestDataSource>("webui")); - return std::make_unique<content::WebUIController>(web_ui); } + + void DataSourceOverrides(content::WebUIDataSource* source) override { + // Add 'unsafe-inline' to CSP to allow the inline <script> in the + // generated HTML to run see js_test_gen_html.py. + source->OverrideContentSecurityPolicy( + network::mojom::CSPDirectiveName::ScriptSrc, + "script-src chrome://resources chrome://webui-test chrome://test " + "'self' chrome-extension://hhaomjibdihmijegdhdafkllkbggdgoj " + "chrome-extension://pmfjbimdmchhbnneeidfognadeopoehp " + "'unsafe-inline'; "); + + source->OverrideContentSecurityPolicy( + network::mojom::CSPDirectiveName::ScriptSrcElem, + "script-src chrome://resources chrome://webui-test chrome://test " + "'self' chrome-extension://hhaomjibdihmijegdhdafkllkbggdgoj " + "chrome-extension://pmfjbimdmchhbnneeidfognadeopoehp " + "'unsafe-inline'; "); + + // TODO(crbug.com/1098685): Trusted Type remaining WebUI. + source->DisableTrustedTypesCSP(); + } }; base::LazyInstance<TestWebUIProvider>::DestructorAtExit test_webui_provider_ = LAZY_INSTANCE_INITIALIZER; static const GURL TestResourceUrl() { - static GURL url(content::GetWebUIURLString("file_manager_test")); + static GURL url(content::GetWebUIURLString("webui-test")); return url; } @@ -227,8 +116,7 @@ } void FileManagerJsTestBase::RunTestURL(const std::string& file) { - RunTestImpl( - GURL("chrome://file_manager_test/" + base_path_.Append(file).value())); + RunTestImpl(GURL("chrome://webui-test/" + base_path_.Append(file).value())); } void FileManagerJsTestBase::RunTestImpl(const GURL& url) { @@ -242,6 +130,12 @@ void FileManagerJsTestBase::SetUpOnMainThread() { InProcessBrowserTest::SetUpOnMainThread(); + base::FilePath pak_path; + ASSERT_TRUE(base::PathService::Get(base::DIR_MODULE, &pak_path)); + pak_path = pak_path.AppendASCII("browser_tests.pak"); + ui::ResourceBundle::GetSharedInstance().AddDataPackFromPath( + pak_path, ui::kScaleFactorNone); + webui_controller_factory_ = std::make_unique<TestChromeWebUIControllerFactory>(); webui_controller_factory_registration_ =
diff --git a/chrome/browser/ash/file_manager/image_loader_jstest.cc b/chrome/browser/ash/file_manager/image_loader_jstest.cc index 219df76..c3b0c08 100644 --- a/chrome/browser/ash/file_manager/image_loader_jstest.cc +++ b/chrome/browser/ash/file_manager/image_loader_jstest.cc
@@ -9,8 +9,9 @@ class ImageLoaderJsTest : public FileManagerJsTestBase { protected: - ImageLoaderJsTest() : FileManagerJsTestBase( - base::FilePath(FILE_PATH_LITERAL("ui/file_manager/image_loader"))) {} + ImageLoaderJsTest() + : FileManagerJsTestBase( + base::FilePath(FILE_PATH_LITERAL("image_loader"))) {} void SetUpCommandLine(base::CommandLine* command_lin) override { // Until Files SWA is fully launched Image Loader imports using
diff --git a/chrome/browser/ash/file_manager/trash_io_task.cc b/chrome/browser/ash/file_manager/trash_io_task.cc index 1479cbe3f..a25cf76 100644 --- a/chrome/browser/ash/file_manager/trash_io_task.cc +++ b/chrome/browser/ash/file_manager/trash_io_task.cc
@@ -177,8 +177,8 @@ TrashLocation& trash_location = trash_parent_path_it->second; const base::FilePath trash_parent_path = trash_parent_path_it->first; TrashEntry& entry = trash_entries_[source_idx]; - entry.trash_path = - trash_parent_path.Append(trash_location.relative_folder_path); + entry.trash_mount_path = trash_parent_path; + entry.relative_trash_path = trash_location.relative_folder_path; if (!UpdateTrashInfoContents(source_path, trash_parent_path, trash_location.prefix_restore_path, entry)) { @@ -363,8 +363,10 @@ DCHECK(source_idx < progress_.sources.size()); DCHECK(source_idx < trash_entries_.size()); + const TrashEntry& entry = trash_entries_[source_idx]; const auto trash_path = MakeRelativeFromBasePath( - trash_entries_[source_idx].trash_path.Append(kFilesFolderName)); + entry.trash_mount_path.Append(entry.relative_trash_path) + .Append(kFilesFolderName)); const storage::FileSystemURL files_location = CreateFileSystemURL(progress_.sources[source_idx].url, trash_path); @@ -386,9 +388,14 @@ TrashComplete(source_idx, output_idx, destination_result.error()); return; } + const base::FilePath absolute_trash_path = + trash_entries_[source_idx].trash_mount_path.Append( + trash_entries_[source_idx].relative_trash_path); + const std::string file_name = + destination_result.value().path().BaseName().value(); + const base::FilePath destination_path = - GenerateTrashPath(trash_entries_[source_idx].trash_path, kInfoFolderName, - destination_result.value().path().BaseName().value()); + GenerateTrashPath(absolute_trash_path, kInfoFolderName, file_name); progress_.outputs.emplace_back( CreateFileSystemURL(progress_.sources[source_idx].url, destination_path), absl::nullopt);
diff --git a/chrome/browser/ash/file_manager/trash_io_task.h b/chrome/browser/ash/file_manager/trash_io_task.h index 1c4b57e..126588b0 100644 --- a/chrome/browser/ash/file_manager/trash_io_task.h +++ b/chrome/browser/ash/file_manager/trash_io_task.h
@@ -36,9 +36,13 @@ TrashEntry(TrashEntry&& other); TrashEntry& operator=(TrashEntry&& other); - // The final location for the trashed file, this may not be the same as the - // `url` in the case of naming conflicts. - base::FilePath trash_path; + // The relative path (to `trash_mount_path`) where the final location of the + // trashed file. + base::FilePath relative_trash_path; + + // An absolute location which contains the `relative_trash_path` and combined + // represents the final location of the trashed file. + base::FilePath trash_mount_path; // The date of deletion, stored in the metadata file to help scheduled // cleanup.
diff --git a/chrome/browser/ash/input_method/assistive_window_controller_unittest.cc b/chrome/browser/ash/input_method/assistive_window_controller_unittest.cc index f2a9f73..d4a91e2 100644 --- a/chrome/browser/ash/input_method/assistive_window_controller_unittest.cc +++ b/chrome/browser/ash/input_method/assistive_window_controller_unittest.cc
@@ -255,7 +255,9 @@ ASSERT_TRUE(controller_->GetSuggestionWindowViewForTesting() != nullptr); views::BoxLayout::Orientation layout_orientation = static_cast<views::BoxLayout*>( - controller_->GetSuggestionWindowViewForTesting()->GetLayoutManager()) + controller_->GetSuggestionWindowViewForTesting() + ->multiple_candidate_area_for_testing() + ->GetLayoutManager()) ->GetOrientation(); EXPECT_EQ(layout_orientation, views::BoxLayout::Orientation::kVertical); } @@ -274,7 +276,9 @@ ASSERT_TRUE(controller_->GetSuggestionWindowViewForTesting() != nullptr); views::BoxLayout::Orientation layout_orientation = static_cast<views::BoxLayout*>( - controller_->GetSuggestionWindowViewForTesting()->GetLayoutManager()) + controller_->GetSuggestionWindowViewForTesting() + ->multiple_candidate_area_for_testing() + ->GetLayoutManager()) ->GetOrientation(); EXPECT_EQ(layout_orientation, views::BoxLayout::Orientation::kVertical); } @@ -292,7 +296,9 @@ ASSERT_TRUE(controller_->GetSuggestionWindowViewForTesting() != nullptr); views::BoxLayout::Orientation layout_orientation = static_cast<views::BoxLayout*>( - controller_->GetSuggestionWindowViewForTesting()->GetLayoutManager()) + controller_->GetSuggestionWindowViewForTesting() + ->multiple_candidate_area_for_testing() + ->GetLayoutManager()) ->GetOrientation(); EXPECT_EQ(layout_orientation, views::BoxLayout::Orientation::kVertical); } @@ -312,7 +318,9 @@ ASSERT_TRUE(controller_->GetSuggestionWindowViewForTesting() != nullptr); views::BoxLayout::Orientation layout_orientation = static_cast<views::BoxLayout*>( - controller_->GetSuggestionWindowViewForTesting()->GetLayoutManager()) + controller_->GetSuggestionWindowViewForTesting() + ->multiple_candidate_area_for_testing() + ->GetLayoutManager()) ->GetOrientation(); EXPECT_EQ(layout_orientation, views::BoxLayout::Orientation::kHorizontal); }
diff --git a/chrome/browser/ash/input_method/input_method_settings.cc b/chrome/browser/ash/input_method/input_method_settings.cc index f7e4e04..8c796b4 100644 --- a/chrome/browser/ash/input_method/input_method_settings.cc +++ b/chrome/browser/ash/input_method/input_method_settings.cc
@@ -107,7 +107,6 @@ .value_or(0) > 0; settings->predictive_writing = features::IsAssistiveMultiWordEnabled() && - !base::FeatureList::IsEnabled(chromeos::features::kLacrosSupport) && prefs.GetBoolean(prefs::kAssistPredictiveWritingEnabled) && IsUsEnglishEngine(engine_id); return settings;
diff --git a/chrome/browser/ash/input_method/input_method_settings_unittest.cc b/chrome/browser/ash/input_method/input_method_settings_unittest.cc index c7015ddf..cec16363 100644 --- a/chrome/browser/ash/input_method/input_method_settings_unittest.cc +++ b/chrome/browser/ash/input_method/input_method_settings_unittest.cc
@@ -67,7 +67,7 @@ } TEST(CreateSettingsFromPrefsTest, - PredictiveWritingEnabledWhenMultiWordAllowedAndEnabledAndLacrosDisabled) { + PredictiveWritingEnabledWhenMultiWordAllowedAndEnabled) { base::test::ScopedFeatureList features; features.InitWithFeatures({features::kAssistMultiWord}, {}); TestingPrefServiceSimple prefs; @@ -83,23 +83,6 @@ EXPECT_TRUE(latin_settings.predictive_writing); } -TEST(CreateSettingsFromPrefsTest, PredictiveWritingDisabledWhenLacrosEnabled) { - base::test::ScopedFeatureList features; - features.InitWithFeatures( - {features::kAssistMultiWord, features::kLacrosSupport}, {}); - TestingPrefServiceSimple prefs; - base::DictionaryValue dict; - RegisterTestingPrefs(prefs, dict); - prefs.registry()->RegisterBooleanPref(prefs::kAssistPredictiveWritingEnabled, - true); - - const auto settings = CreateSettingsFromPrefs(prefs, kUsEnglishEngineId); - - ASSERT_TRUE(settings->is_latin_settings()); - const auto& latin_settings = *settings->get_latin_settings(); - EXPECT_FALSE(latin_settings.predictive_writing); -} - TEST(CreateSettingsFromPrefsTest, PredictiveWritingDisabledWhenMultiwordDisabled) { base::test::ScopedFeatureList features;
diff --git a/chrome/browser/ash/input_method/native_input_method_engine_observer.cc b/chrome/browser/ash/input_method/native_input_method_engine_observer.cc index 93ad9ff..231705e 100644 --- a/chrome/browser/ash/input_method/native_input_method_engine_observer.cc +++ b/chrome/browser/ash/input_method/native_input_method_engine_observer.cc
@@ -51,7 +51,6 @@ namespace mojom = ::ash::ime::mojom; struct InputFieldContext { - bool lacros_enabled = false; bool multiword_enabled = false; bool multiword_allowed = false; }; @@ -123,13 +122,9 @@ return autocorrect_setting && autocorrect_setting->GetIfInt().value_or(0) > 0; } -bool IsLacrosEnabled() { - return base::FeatureList::IsEnabled(chromeos::features::kLacrosSupport); -} - bool IsPredictiveWritingEnabled(PrefService* pref_service, const std::string& engine_id) { - return (!IsLacrosEnabled() && features::IsAssistiveMultiWordEnabled() && + return (features::IsAssistiveMultiWordEnabled() && IsPredictiveWritingPrefEnabled(pref_service, engine_id) && IsUsEnglishEngine(engine_id)); } @@ -455,7 +450,6 @@ InputFieldContext CreateInputFieldContext( const AssistiveSuggesterSwitch::EnabledSuggestions& enabled_suggestions) { return InputFieldContext{ - .lacros_enabled = IsLacrosEnabled(), .multiword_enabled = features::IsAssistiveMultiWordEnabled(), .multiword_allowed = enabled_suggestions.multi_word_suggestions}; } @@ -464,9 +458,7 @@ const std::string& engine_id, const InputFieldContext& context, const PrefService& prefs) { - // TODO(crbug.com/1263335): Enable text prediction for Lacros. return context.multiword_enabled && context.multiword_allowed && - !context.lacros_enabled && prefs.GetBoolean(prefs::kAssistPredictiveWritingEnabled) && IsUsEnglishEngine(engine_id) ? mojom::TextPredictionMode::kEnabled
diff --git a/chrome/browser/ash/input_method/native_input_method_engine_unittest.cc b/chrome/browser/ash/input_method/native_input_method_engine_unittest.cc index 02da8001..34e8c8a 100644 --- a/chrome/browser/ash/input_method/native_input_method_engine_unittest.cc +++ b/chrome/browser/ash/input_method/native_input_method_engine_unittest.cc
@@ -264,16 +264,6 @@ }); } - void EnableDefaultFeatureListWithMultiWordAndLacros() { - EnableFeatureList({ - features::kAssistPersonalInfo, - features::kAssistPersonalInfoEmail, - features::kAssistPersonalInfoName, - features::kAssistMultiWord, - features::kLacrosSupport, - }); - } - private: content::BrowserTaskEnvironment task_environment_; base::test::ScopedFeatureList feature_list_; @@ -364,27 +354,6 @@ } TEST_F(NativeInputMethodEngineTest, - PredictiveWritingDoesNotLaunchImeServiceWithLacrosEnabled) { - TestingProfile testing_profile; - EnableDefaultFeatureListWithMultiWordAndLacros(); - SetInputMethodOptions(testing_profile, /*autocorrect_enabled=*/false, - /*predictive_writing_enabled=*/true); - - testing::StrictMock<MockInputMethod> mock_input_method; - InputMethodManager::Initialize( - new TestInputMethodManager(&mock_input_method)); - NativeInputMethodEngine engine; - engine.Initialize(std::make_unique<StubInputMethodEngineObserver>(), - /*extension_id=*/"", &testing_profile); - - engine.Enable(kEngineIdUs); - engine.FlushForTesting(); // ensure input_method is connected. - EXPECT_FALSE(engine.IsConnectedForTesting()); - - InputMethodManager::Shutdown(); -} - -TEST_F(NativeInputMethodEngineTest, PredictiveWritingLaunchesImeServiceWithEnglishEngineId) { TestingProfile testing_profile; EnableDefaultFeatureListWithMultiWord();
diff --git a/chrome/browser/ash/input_method/ui/suggestion_view.cc b/chrome/browser/ash/input_method/ui/completion_suggestion_view.cc similarity index 76% rename from chrome/browser/ash/input_method/ui/suggestion_view.cc rename to chrome/browser/ash/input_method/ui/completion_suggestion_view.cc index 7d14b15..a1babec1 100644 --- a/chrome/browser/ash/input_method/ui/suggestion_view.cc +++ b/chrome/browser/ash/input_method/ui/completion_suggestion_view.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/ash/input_method/ui/suggestion_view.h" +#include "chrome/browser/ash/input_method/ui/completion_suggestion_view.h" #include "base/strings/utf_string_conversions.h" #include "chrome/app/vector_icons/vector_icons.h" @@ -35,21 +35,6 @@ const int kDownIconSize = 16; const int kEnterKeyHorizontalPadding = 2; -// Creates the index label, and returns it (never returns nullptr). -// The label text is not set in this function. -std::unique_ptr<views::Label> CreateIndexLabel() { - auto index_label = std::make_unique<views::Label>(); - index_label->SetFontList(gfx::FontList({kFontStyle}, gfx::Font::NORMAL, - kIndexFontSize, - gfx::Font::Weight::MEDIUM)); - index_label->SetEnabledColor( - ResolveSemanticColor(cros_styles::ColorName::kTextColorSecondary)); - index_label->SetHorizontalAlignment(gfx::ALIGN_CENTER); - index_label->SetBorder( - views::CreateEmptyBorder(gfx::Insets::VH(kPadding / 2, 0))); - return index_label; -} - std::unique_ptr<views::ImageView> CreateDownIcon() { auto icon = std::make_unique<views::ImageView>(); icon->SetBorder(views::CreateEmptyBorder(gfx::Insets::TLBR( @@ -97,10 +82,8 @@ } // namespace -SuggestionView::SuggestionView(PressedCallback callback) +CompletionSuggestionView::CompletionSuggestionView(PressedCallback callback) : views::Button(std::move(callback)) { - index_label_ = AddChildView(CreateIndexLabel()); - index_label_->SetVisible(false); suggestion_label_ = AddChildView(std::make_unique<CompletionSuggestionLabelView>()); suggestion_label_->SetBorder( @@ -123,9 +106,10 @@ SetProperty(views::kSkipAccessibilityPaintChecks, true); } -SuggestionView::~SuggestionView() = default; +CompletionSuggestionView::~CompletionSuggestionView() = default; -std::unique_ptr<views::View> SuggestionView::CreateAnnotationContainer() { +std::unique_ptr<views::View> +CompletionSuggestionView::CreateAnnotationContainer() { auto label = std::make_unique<views::View>(); label->SetLayoutManager(std::make_unique<views::BoxLayout>( views::BoxLayout::Orientation::kHorizontal)); @@ -137,7 +121,7 @@ } std::unique_ptr<views::View> -SuggestionView::CreateDownAndEnterAnnotationLabel() { +CompletionSuggestionView::CreateDownAndEnterAnnotationLabel() { auto label = std::make_unique<views::View>(); label->SetBorder(views::CreateEmptyBorder( gfx::Insets::TLBR(0, kAnnotationPaddingLeft, 0, 0))); @@ -152,7 +136,8 @@ return label; } -std::unique_ptr<views::View> SuggestionView::CreateTabAnnotationLabel() { +std::unique_ptr<views::View> +CompletionSuggestionView::CreateTabAnnotationLabel() { auto label = std::make_unique<views::View>(); label->SetBorder(views::CreateEmptyBorder( gfx::Insets::TLBR(0, kAnnotationPaddingLeft, 0, 0))); @@ -162,7 +147,7 @@ return label; } -void SuggestionView::SetView(const SuggestionDetails& details) { +void CompletionSuggestionView::SetView(const SuggestionDetails& details) { SetSuggestionText(details.text, details.confirmed_length); suggestion_width_ = suggestion_label_->GetPreferredSize().width(); down_and_enter_annotation_label_->SetVisible(details.show_accept_annotation); @@ -171,22 +156,14 @@ details.show_quick_accept_annotation); } -void SuggestionView::SetViewWithIndex(const std::u16string& index, - const std::u16string& text) { - index_label_->SetText(index); - index_label_->SetVisible(true); - index_width_ = index_label_->GetPreferredSize().width(); - suggestion_label_->SetPrefixAndPrediction(u"", text); - suggestion_width_ = suggestion_label_->GetPreferredSize().width(); -} - -void SuggestionView::SetSuggestionText(const std::u16string& text, - const size_t confirmed_length) { +void CompletionSuggestionView::SetSuggestionText( + const std::u16string& text, + const size_t confirmed_length) { suggestion_label_->SetPrefixAndPrediction(text.substr(0, confirmed_length), text.substr(confirmed_length)); } -void SuggestionView::SetHighlighted(bool highlighted) { +void CompletionSuggestionView::SetHighlighted(bool highlighted) { if (highlighted_ == highlighted) return; @@ -202,7 +179,7 @@ SchedulePaint(); } -void SuggestionView::OnThemeChanged() { +void CompletionSuggestionView::OnThemeChanged() { const auto* color_provider = GetColorProvider(); down_icon_->SetImage( gfx::CreateVectorIcon(kKeyboardArrowDownIcon, kDownIconSize, @@ -213,12 +190,8 @@ views::View::OnThemeChanged(); } -void SuggestionView::Layout() { +void CompletionSuggestionView::Layout() { int left = kPadding; - if (index_label_->GetVisible()) { - index_label_->SetBounds(left, 0, index_width_, height()); - left += index_width_ + kPadding; - } suggestion_label_->SetBounds(left, 0, suggestion_width_, height()); @@ -232,13 +205,8 @@ } } -gfx::Size SuggestionView::CalculatePreferredSize() const { +gfx::Size CompletionSuggestionView::CalculatePreferredSize() const { gfx::Size size; - if (index_label_->GetVisible()) { - size = index_label_->GetPreferredSize(); - size.SetToMax(gfx::Size(index_width_, 0)); - size.Enlarge(kPadding, 0); - } gfx::Size suggestion_size = suggestion_label_->GetPreferredSize(); suggestion_size.SetToMax(gfx::Size(suggestion_width_, 0)); size.Enlarge(suggestion_size.width() + 2 * kPadding, 0); @@ -252,24 +220,24 @@ return size; } -void SuggestionView::SetMinWidth(int min_width) { +void CompletionSuggestionView::SetMinWidth(int min_width) { min_width_ = min_width; } -gfx::Point SuggestionView::GetAnchorOrigin() const { +gfx::Point CompletionSuggestionView::GetAnchorOrigin() const { return gfx::Point(suggestion_label_->GetPrefixWidthPx() + kPadding, 0); } -std::u16string SuggestionView::GetSuggestionForTesting() { +std::u16string CompletionSuggestionView::GetSuggestionForTesting() { return suggestion_label_->GetText(); } -CompletionSuggestionLabelView* SuggestionView::suggestion_label_for_testing() - const { +CompletionSuggestionLabelView* +CompletionSuggestionView::suggestion_label_for_testing() const { return suggestion_label_; } -BEGIN_METADATA(SuggestionView, views::Button) +BEGIN_METADATA(CompletionSuggestionView, views::Button) END_METADATA } // namespace ime
diff --git a/chrome/browser/ash/input_method/ui/suggestion_view.h b/chrome/browser/ash/input_method/ui/completion_suggestion_view.h similarity index 79% rename from chrome/browser/ash/input_method/ui/suggestion_view.h rename to chrome/browser/ash/input_method/ui/completion_suggestion_view.h index 235876cf..b61e860c 100644 --- a/chrome/browser/ash/input_method/ui/suggestion_view.h +++ b/chrome/browser/ash/input_method/ui/completion_suggestion_view.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_ASH_INPUT_METHOD_UI_SUGGESTION_VIEW_H_ -#define CHROME_BROWSER_ASH_INPUT_METHOD_UI_SUGGESTION_VIEW_H_ +#ifndef CHROME_BROWSER_ASH_INPUT_METHOD_UI_COMPLETION_SUGGESTION_VIEW_H_ +#define CHROME_BROWSER_ASH_INPUT_METHOD_UI_COMPLETION_SUGGESTION_VIEW_H_ #include "base/gtest_prod_util.h" #include "ui/base/metadata/metadata_header_macros.h" @@ -41,20 +41,17 @@ constexpr cros_styles::ColorName kButtonHighlightColor = cros_styles::ColorName::kRippleColor; -// SuggestionView renders a suggestion. -class UI_CHROMEOS_EXPORT SuggestionView : public views::Button { +// CompletionSuggestionView renders a suggestion. +class UI_CHROMEOS_EXPORT CompletionSuggestionView : public views::Button { public: - METADATA_HEADER(SuggestionView); - explicit SuggestionView(PressedCallback callback); - SuggestionView(const SuggestionView&) = delete; - SuggestionView& operator=(const SuggestionView&) = delete; - ~SuggestionView() override; + METADATA_HEADER(CompletionSuggestionView); + explicit CompletionSuggestionView(PressedCallback callback); + CompletionSuggestionView(const CompletionSuggestionView&) = delete; + CompletionSuggestionView& operator=(const CompletionSuggestionView&) = delete; + ~CompletionSuggestionView() override; void SetView(const SuggestionDetails& details); - void SetViewWithIndex(const std::u16string& index, - const std::u16string& text); - void SetHighlighted(bool highlighted); void SetMinWidth(int width); @@ -86,7 +83,6 @@ void SetSuggestionText(const std::u16string& text, const size_t confirmed_length); - views::Label* index_label_ = nullptr; // The suggestion label renders the suggestion text. CompletionSuggestionLabelView* suggestion_label_ = nullptr; // The annotation view renders annotations. @@ -97,12 +93,11 @@ views::ImageView* arrow_icon_ = nullptr; int suggestion_width_ = 0; - int index_width_ = 0; int min_width_ = 0; bool highlighted_ = false; }; -BEGIN_VIEW_BUILDER(UI_CHROMEOS_EXPORT, SuggestionView, views::Button) +BEGIN_VIEW_BUILDER(UI_CHROMEOS_EXPORT, CompletionSuggestionView, views::Button) VIEW_BUILDER_PROPERTY(const SuggestionDetails&, View) VIEW_BUILDER_PROPERTY(bool, Highlighted) VIEW_BUILDER_PROPERTY(int, MinWidth) @@ -111,6 +106,6 @@ } // namespace ime } // namespace ui -DEFINE_VIEW_BUILDER(UI_CHROMEOS_EXPORT, ui::ime::SuggestionView) +DEFINE_VIEW_BUILDER(UI_CHROMEOS_EXPORT, ui::ime::CompletionSuggestionView) -#endif // CHROME_BROWSER_ASH_INPUT_METHOD_UI_SUGGESTION_VIEW_H_ +#endif // CHROME_BROWSER_ASH_INPUT_METHOD_UI_COMPLETION_SUGGESTION_VIEW_H_
diff --git a/chrome/browser/ash/input_method/ui/suggestion_view_unittest.cc b/chrome/browser/ash/input_method/ui/completion_suggestion_view_unittest.cc similarity index 73% rename from chrome/browser/ash/input_method/ui/suggestion_view_unittest.cc rename to chrome/browser/ash/input_method/ui/completion_suggestion_view_unittest.cc index 2a0c592c..524badb 100644 --- a/chrome/browser/ash/input_method/ui/suggestion_view_unittest.cc +++ b/chrome/browser/ash/input_method/ui/completion_suggestion_view_unittest.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/ash/input_method/ui/suggestion_view.h" +#include "chrome/browser/ash/input_method/ui/completion_suggestion_view.h" #include <stddef.h> @@ -17,13 +17,14 @@ namespace ime { namespace { -class SuggestionViewTest : public views::ViewsTestBase { +class CompletionSuggestionViewTest : public views::ViewsTestBase { public: - SuggestionViewTest() = default; + CompletionSuggestionViewTest() = default; }; -TEST_F(SuggestionViewTest, AnchorOriginIsPaddingWhenConfirmedLengthIsZero) { - SuggestionView suggestion({}); +TEST_F(CompletionSuggestionViewTest, + AnchorOriginIsPaddingWhenConfirmedLengthIsZero) { + CompletionSuggestionView suggestion({}); suggestion.SetView({ .text = u"good", .confirmed_length = 0, @@ -32,9 +33,9 @@ EXPECT_EQ(suggestion.GetAnchorOrigin(), gfx::Point(kPadding, 0)); } -TEST_F(SuggestionViewTest, +TEST_F(CompletionSuggestionViewTest, AnchorOriginIsPaddingAndPrefixWidthWhenConfirmedLengthIsNonZero) { - SuggestionView suggestion({}); + CompletionSuggestionView suggestion({}); // "how a" is confirmed suggestion.SetView({ .text = u"how are you",
diff --git a/chrome/browser/ash/input_method/ui/grammar_suggestion_window.cc b/chrome/browser/ash/input_method/ui/grammar_suggestion_window.cc index cc3aa12..972c406 100644 --- a/chrome/browser/ash/input_method/ui/grammar_suggestion_window.cc +++ b/chrome/browser/ash/input_method/ui/grammar_suggestion_window.cc
@@ -50,8 +50,8 @@ SetLayoutManager(std::make_unique<views::BoxLayout>( views::BoxLayout::Orientation::kHorizontal)); - suggestion_button_ = - AddChildView(std::make_unique<SuggestionView>(base::BindRepeating( + suggestion_button_ = AddChildView( + std::make_unique<CompletionSuggestionView>(base::BindRepeating( &AssistiveDelegate::AssistiveWindowButtonClicked, base::Unretained(delegate_), AssistiveWindowButton{ @@ -164,7 +164,8 @@ SetAnchorRect(bounds); } -SuggestionView* GrammarSuggestionWindow::GetSuggestionButtonForTesting() { +CompletionSuggestionView* +GrammarSuggestionWindow::GetSuggestionButtonForTesting() { return suggestion_button_; }
diff --git a/chrome/browser/ash/input_method/ui/grammar_suggestion_window.h b/chrome/browser/ash/input_method/ui/grammar_suggestion_window.h index 2d73404..dc204dc 100644 --- a/chrome/browser/ash/input_method/ui/grammar_suggestion_window.h +++ b/chrome/browser/ash/input_method/ui/grammar_suggestion_window.h
@@ -6,7 +6,7 @@ #define CHROME_BROWSER_ASH_INPUT_METHOD_UI_GRAMMAR_SUGGESTION_WINDOW_H_ #include "chrome/browser/ash/input_method/ui/assistive_delegate.h" -#include "chrome/browser/ash/input_method/ui/suggestion_view.h" +#include "chrome/browser/ash/input_method/ui/completion_suggestion_view.h" #include "ui/base/metadata/metadata_header_macros.h" #include "ui/chromeos/ui_chromeos_export.h" #include "ui/views/bubble/bubble_dialog_delegate_view.h" @@ -39,7 +39,7 @@ void SetBounds(gfx::Rect bounds); - SuggestionView* GetSuggestionButtonForTesting(); + CompletionSuggestionView* GetSuggestionButtonForTesting(); views::Button* GetIgnoreButtonForTesting(); protected: @@ -47,7 +47,7 @@ private: AssistiveDelegate* delegate_; - SuggestionView* suggestion_button_; + CompletionSuggestionView* suggestion_button_; views::ImageButton* ignore_button_; ButtonId current_highlighted_button_id_ = ButtonId::kNone;
diff --git a/chrome/browser/ash/input_method/ui/suggestion_window_view.cc b/chrome/browser/ash/input_method/ui/suggestion_window_view.cc index 939ba73..301c9bb 100644 --- a/chrome/browser/ash/input_method/ui/suggestion_window_view.cc +++ b/chrome/browser/ash/input_method/ui/suggestion_window_view.cc
@@ -14,8 +14,8 @@ #include "chrome/browser/ash/input_method/ui/assistive_delegate.h" #include "chrome/browser/ash/input_method/ui/border_factory.h" #include "chrome/browser/ash/input_method/ui/colors.h" +#include "chrome/browser/ash/input_method/ui/completion_suggestion_view.h" #include "chrome/browser/ash/input_method/ui/suggestion_details.h" -#include "chrome/browser/ash/input_method/ui/suggestion_view.h" #include "chrome/grit/generated_resources.h" #include "components/strings/grit/components_strings.h" #include "components/vector_icons/vector_icons.h" @@ -35,6 +35,7 @@ #include "ui/views/bubble/bubble_border.h" #include "ui/views/bubble/bubble_frame_view.h" #include "ui/views/controls/button/image_button.h" +#include "ui/views/controls/button/label_button.h" #include "ui/views/controls/link.h" #include "ui/views/layout/box_layout.h" #include "ui/views/layout/layout_provider.h" @@ -87,12 +88,12 @@ } void SuggestionWindowView::Show(const SuggestionDetails& details) { - ResizeCandidateArea(1); - auto* const candidate = - static_cast<SuggestionView*>(candidate_area_->children().front()); - candidate->SetView(details); + ResizeCandidateArea(0); + + completion_view_->SetVisible(true); + completion_view_->SetView(details); if (details.show_setting_link) - candidate->SetMinWidth(setting_link_->GetPreferredSize().width()); + completion_view_->SetMinWidth(setting_link_->GetPreferredSize().width()); setting_link_->SetVisible(details.show_setting_link); @@ -102,14 +103,12 @@ void SuggestionWindowView::ShowMultipleCandidates( const ash::input_method::AssistiveWindowProperties& properties) { const std::vector<std::u16string>& candidates = properties.candidates; + completion_view_->SetVisible(false); ResizeCandidateArea(candidates.size()); for (size_t i = 0; i < candidates.size(); ++i) { - auto* const candidate = - static_cast<SuggestionView*>(candidate_area_->children()[i]); - if (properties.show_indices) - candidate->SetViewWithIndex(base::FormatNumber(i + 1), candidates[i]); - else - candidate->SetView({.text = candidates[i]}); + auto* const candidate = static_cast<views::LabelButton*>( + multiple_candidate_area_->children()[i]); + candidate->SetText(candidates[i]); } learn_more_button_->SetVisible(properties.show_setting_link); @@ -121,10 +120,16 @@ const AssistiveWindowButton& button, bool highlighted) { if (button.id == ButtonId::kSuggestion) { - const views::View::Views& candidates = candidate_area_->children(); - if (button.index < candidates.size()) { - SetCandidateHighlighted( - static_cast<SuggestionView*>(candidates[button.index]), highlighted); + if (completion_view_->GetVisible()) { + completion_view_->SetHighlighted(highlighted); + } else { + const views::View::Views& candidates = + multiple_candidate_area_->children(); + if (button.index < candidates.size()) { + SetCandidateHighlighted( + static_cast<views::LabelButton*>(candidates[button.index]), + highlighted); + } } } else if (button.id == ButtonId::kSmartInputsSettingLink) { SetHighlighted(*setting_link_, highlighted); @@ -134,15 +139,11 @@ } gfx::Rect SuggestionWindowView::GetBubbleBounds() { - // The bubble bounds must be shifted to align with the anchor. - // If there is more than one suggestion, use the anchor origin of the first - // (topmost) suggestion. This allows the alignment to work correctly for both - // vertical and horizontal orientations. - const views::View::Views& candidates = candidate_area_->children(); - const gfx::Point anchor_origin = - !candidates.empty() - ? static_cast<SuggestionView*>(candidates[0])->GetAnchorOrigin() - : gfx::Point(0, 0); + // The bubble bounds must be shifted to align with the anchor if there is a + // completion view. + const gfx::Point anchor_origin = completion_view_->GetVisible() + ? completion_view_->GetAnchorOrigin() + : gfx::Point(0, 0); return BubbleDialogDelegateView::GetBubbleBounds() - anchor_origin.OffsetFromOrigin(); } @@ -193,11 +194,19 @@ } } - SetLayoutManager(std::make_unique<views::BoxLayout>(layout_orientation)); - - candidate_area_ = AddChildView(std::make_unique<views::View>()); - candidate_area_->SetLayoutManager( + SetLayoutManager(std::make_unique<views::BoxLayout>( + views::BoxLayout::Orientation::kHorizontal)); + completion_view_ = AddChildView( + std::make_unique<CompletionSuggestionView>(base::BindRepeating( + &AssistiveDelegate::AssistiveWindowButtonClicked, + base::Unretained(delegate_), + AssistiveWindowButton{.id = ui::ime::ButtonId::kSuggestion, + .index = 0}))); + completion_view_->SetVisible(false); + multiple_candidate_area_ = AddChildView(std::make_unique<views::View>()); + multiple_candidate_area_->SetLayoutManager( std::make_unique<views::BoxLayout>(layout_orientation)); + multiple_candidate_area_->SetVisible(false); setting_link_ = AddChildView(std::make_unique<views::Link>( l10n_util::GetStringUTF16(IDS_SUGGESTION_LEARN_MORE))); @@ -242,24 +251,27 @@ SuggestionWindowView::~SuggestionWindowView() = default; void SuggestionWindowView::ResizeCandidateArea(size_t size) { - if (highlighted_candidate_) - SetCandidateHighlighted(highlighted_candidate_, false); - - const views::View::Views& candidates = candidate_area_->children(); + const views::View::Views& candidates = multiple_candidate_area_->children(); while (candidates.size() > size) { subscriptions_.erase( - candidate_area_->RemoveChildViewT(candidates.back()).get()); + multiple_candidate_area_->RemoveChildViewT(candidates.back()).get()); } for (size_t index = candidates.size(); index < size; ++index) { - auto* const candidate = candidate_area_->AddChildView( - std::make_unique<SuggestionView>(base::BindRepeating( - &AssistiveDelegate::AssistiveWindowButtonClicked, - base::Unretained(delegate_), - AssistiveWindowButton{.id = ui::ime::ButtonId::kSuggestion, - .index = index}))); + // TODO(b/217560706): Separate this into a CandidateView that will follow + // specs and contain an index. + auto* const candidate = multiple_candidate_area_->AddChildView( + std::make_unique<views::LabelButton>( + base::BindRepeating( + &AssistiveDelegate::AssistiveWindowButtonClicked, + base::Unretained(delegate_), + AssistiveWindowButton{.id = ui::ime::ButtonId::kSuggestion, + .index = index}), + u"")); + candidate->SetBorder(views::CreateEmptyBorder(gfx::Insets::VH(6, 10))); + auto subscription = candidate->AddStateChangedCallback(base::BindRepeating( - [](SuggestionWindowView* window, SuggestionView* button) { + [](SuggestionWindowView* window, views::LabelButton* button) { window->SetCandidateHighlighted(button, ShouldHighlight(*button)); }, base::Unretained(this), base::Unretained(candidate))); @@ -268,24 +280,19 @@ } void SuggestionWindowView::MakeVisible() { - candidate_area_->SetVisible(true); + multiple_candidate_area_->SetVisible(true); SizeToContents(); } -void SuggestionWindowView::SetCandidateHighlighted(SuggestionView* candidate, +void SuggestionWindowView::SetCandidateHighlighted(views::LabelButton* view, bool highlighted) { - DCHECK(candidate); - DCHECK_EQ(candidate_area_, candidate->parent()); + // Clear all highlights if any exists. + for (auto* candidate : multiple_candidate_area_->children()) { + SetHighlighted(*candidate, false); + } - // Can't highlight a highlighted candidate, or unhighlight an unhighlighted - // one. - if (highlighted == (candidate == highlighted_candidate_)) - return; - - if (highlighted && highlighted_candidate_) - highlighted_candidate_->SetHighlighted(false); - candidate->SetHighlighted(highlighted); - highlighted_candidate_ = highlighted ? candidate : nullptr; + if (highlighted) + SetHighlighted(*view, highlighted); } BEGIN_METADATA(SuggestionWindowView, views::BubbleDialogDelegateView)
diff --git a/chrome/browser/ash/input_method/ui/suggestion_window_view.h b/chrome/browser/ash/input_method/ui/suggestion_window_view.h index 6ec619b..6696296 100644 --- a/chrome/browser/ash/input_method/ui/suggestion_window_view.h +++ b/chrome/browser/ash/input_method/ui/suggestion_window_view.h
@@ -34,7 +34,7 @@ class AssistiveDelegate; struct AssistiveWindowButton; struct SuggestionDetails; -class SuggestionView; +class CompletionSuggestionView; // SuggestionWindowView is the main container of the suggestion window UI. class UI_CHROMEOS_EXPORT SuggestionWindowView @@ -69,7 +69,9 @@ void SetButtonHighlighted(const AssistiveWindowButton& button, bool highlighted); - views::View* candidate_area_for_testing() { return candidate_area_; } + views::View* multiple_candidate_area_for_testing() { + return multiple_candidate_area_; + } views::Link* setting_link_for_testing() { return setting_link_; } views::ImageButton* learn_more_button_for_testing() { return learn_more_button_; @@ -96,13 +98,18 @@ // Sets |candidate|'s highlight state to |highlighted|. At most one candidate // will be highlighted at any given time. - void SetCandidateHighlighted(SuggestionView* candidate, bool highlighted); + void SetCandidateHighlighted(views::LabelButton* candidate, bool highlighted); // The delegate to handle events from this class. AssistiveDelegate* const delegate_; - // The view containing all the suggestions. - views::View* candidate_area_; + // The view containing all the suggestions if multiple candidates are + // visible. + views::View* multiple_candidate_area_; + + // The view containing the completion view. If this is visible then there is + // only one suggestion to show. + CompletionSuggestionView* completion_view_; // The setting link, positioned below candidate_area_. // TODO(crbug/1102175): Rename setting to settings since there can be multiple @@ -111,9 +118,6 @@ views::ImageButton* learn_more_button_; - // The currently-highlighted candidate, if any. - SuggestionView* highlighted_candidate_ = nullptr; - // TODO(crbug/1099062): Add tests for mouse hovered and pressed. base::flat_map<views::View*, base::CallbackListSubscription> subscriptions_;
diff --git a/chrome/browser/ash/input_method/ui/suggestion_window_view_unittest.cc b/chrome/browser/ash/input_method/ui/suggestion_window_view_unittest.cc index 1707199..6b5dc87 100644 --- a/chrome/browser/ash/input_method/ui/suggestion_window_view_unittest.cc +++ b/chrome/browser/ash/input_method/ui/suggestion_window_view_unittest.cc
@@ -10,8 +10,8 @@ #include "chrome/browser/ash/input_method/assistive_window_properties.h" #include "chrome/browser/ash/input_method/ui/assistive_delegate.h" #include "chrome/browser/ash/input_method/ui/completion_suggestion_label_view.h" +#include "chrome/browser/ash/input_method/ui/completion_suggestion_view.h" #include "chrome/browser/ash/input_method/ui/suggestion_details.h" -#include "chrome/browser/ash/input_method/ui/suggestion_view.h" #include "chrome/test/views/chrome_views_test_base.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/abseil-cpp/absl/types/optional.h" @@ -68,7 +68,8 @@ size_t GetHighlightedCount() const { const auto& children = - suggestion_window_view_->candidate_area_for_testing()->children(); + suggestion_window_view_->multiple_candidate_area_for_testing() + ->children(); return std::count_if( children.cbegin(), children.cend(), [](const views::View* v) { return !!v->background(); }); @@ -76,7 +77,8 @@ absl::optional<int> GetHighlightedIndex() const { const auto& children = - suggestion_window_view_->candidate_area_for_testing()->children(); + suggestion_window_view_->multiple_candidate_area_for_testing() + ->children(); const auto it = std::find_if(children.cbegin(), children.cend(), [](const views::View* v) { return !!v->background(); }); @@ -310,7 +312,8 @@ suggestion_window_view_->ShowMultipleCandidates(window_); views::BoxLayout::Orientation layout_orientation = static_cast<views::BoxLayout*>( - suggestion_window_view_->GetLayoutManager()) + suggestion_window_view_->multiple_candidate_area_for_testing() + ->GetLayoutManager()) ->GetOrientation(); EXPECT_EQ(layout_orientation, expected_orientation); }
diff --git a/chrome/browser/ash/policy/dlp/dlp_files_controller.cc b/chrome/browser/ash/policy/dlp/dlp_files_controller.cc index 07956516..ffc03bc1 100644 --- a/chrome/browser/ash/policy/dlp/dlp_files_controller.cc +++ b/chrome/browser/ash/policy/dlp/dlp_files_controller.cc
@@ -4,11 +4,13 @@ #include "chrome/browser/ash/policy/dlp/dlp_files_controller.h" +#include <sys/types.h> #include <string> #include "base/bind.h" #include "base/check.h" #include "base/containers/contains.h" +#include "base/containers/flat_map.h" #include "base/files/file_path.h" #include "base/files/file_util.h" #include "base/logging.h" @@ -30,6 +32,22 @@ namespace { +absl::optional<ino_t> GetInodeValue(const base::FilePath& path) { + struct stat file_stats; + if (stat(path.value().c_str(), &file_stats) != 0) + return absl::nullopt; + return file_stats.st_ino; +} + +std::vector<absl::optional<ino_t>> GetFilesInodes( + const std::vector<storage::FileSystemURL>& files) { + std::vector<absl::optional<ino_t>> inodes; + for (const auto& file : files) { + inodes.push_back(GetInodeValue(file.path())); + } + return inodes; +} + // Maps |file_path| to DlpRulesManager::Component if possible. absl::optional<DlpRulesManager::Component> MapFilePathtoPolicyComponent( Profile* profile, @@ -62,6 +80,11 @@ } // namespace +DlpFilesController::DlpFileMetadata::DlpFileMetadata( + const std::string& source_url, + bool is_dlp_restricted) + : source_url(source_url), is_dlp_restricted(is_dlp_restricted) {} + DlpFilesController::DlpFilesController() = default; DlpFilesController::~DlpFilesController() = default; @@ -100,16 +123,25 @@ std::move(result_callback))); } -void DlpFilesController::GetFilesRestrictedByAnyRule( +void DlpFilesController::GetDlpMetadata( std::vector<storage::FileSystemURL> files, - GetFilesRestrictedByAnyRuleCallback result_callback) { + GetDlpMetadataCallback result_callback) { if (!chromeos::DlpClient::Get() || !chromeos::DlpClient::Get()->IsAlive()) { - std::move(result_callback).Run(std::vector<storage::FileSystemURL>()); + std::move(result_callback).Run(std::vector<DlpFileMetadata>()); return; } - // TODO(aidazolic): Implement getting the restricted files by calling DLP - // daemon to check restrictions. - NOTIMPLEMENTED(); + + std::vector<absl::optional<ino_t>> inodes = GetFilesInodes(files); + dlp::GetFilesSourcesRequest request; + for (const auto& inode : inodes) { + if (inode.has_value()) { + request.add_files_inodes(inode.value()); + } + } + chromeos::DlpClient::Get()->GetFilesSources( + request, base::BindOnce(&DlpFilesController::ReturnDlpMetadata, + weak_ptr_factory_.GetWeakPtr(), std::move(inodes), + std::move(result_callback))); } void DlpFilesController::FilterDisallowedUploads( @@ -218,4 +250,48 @@ std::move(result_callback).Run(std::move(filtered_files)); } +void DlpFilesController::ReturnDlpMetadata( + std::vector<absl::optional<ino_t>> inodes, + GetDlpMetadataCallback result_callback, + const dlp::GetFilesSourcesResponse response) { + if (response.has_error_message()) { + LOG(ERROR) << "Failed to get files sources, error: " + << response.error_message(); + } + + policy::DlpRulesManager* dlp_rules_manager = + policy::DlpRulesManagerFactory::GetForPrimaryProfile(); + if (!dlp_rules_manager) { + std::move(result_callback).Run(std::vector<DlpFileMetadata>()); + return; + } + + base::flat_map<ino_t, DlpFileMetadata> metadata_map; + for (const auto& metadata : response.files_metadata()) { + DlpRulesManager::Level level = dlp_rules_manager->IsRestrictedByAnyRule( + GURL(metadata.source_url()), DlpRulesManager::Restriction::kFiles); + bool is_dlp_restricted = level != DlpRulesManager::Level::kNotSet && + level != DlpRulesManager::Level::kAllow; + metadata_map.emplace( + metadata.inode(), + DlpFileMetadata(metadata.source_url(), is_dlp_restricted)); + } + + std::vector<DlpFileMetadata> result; + for (const auto& inode : inodes) { + if (!inode.has_value()) { + result.emplace_back("", false); + continue; + } + auto metadata_itr = metadata_map.find(inode.value()); + if (metadata_itr == metadata_map.end()) { + result.emplace_back("", false); + } else { + result.emplace_back(metadata_itr->second); + } + } + + std::move(result_callback).Run(std::move(result)); +} + } // namespace policy
diff --git a/chrome/browser/ash/policy/dlp/dlp_files_controller.h b/chrome/browser/ash/policy/dlp/dlp_files_controller.h index 9fadd84..b5ecd0f 100644 --- a/chrome/browser/ash/policy/dlp/dlp_files_controller.h +++ b/chrome/browser/ash/policy/dlp/dlp_files_controller.h
@@ -11,6 +11,7 @@ #include "base/containers/flat_map.h" #include "base/memory/weak_ptr.h" #include "chromeos/dbus/dlp/dlp_service.pb.h" +#include "storage/browser/file_system/file_system_url.h" #include "third_party/blink/public/mojom/choosers/file_chooser.mojom-forward.h" #include "url/gurl.h" @@ -27,14 +28,35 @@ // of the Data leak prevention policy set by the admin. class DlpFilesController { public: + // DlpFileMetadata keeps metadata about a file, such as whether it's managed + // or not and the source URL, if it exists. + struct DlpFileMetadata { + DlpFileMetadata() = delete; + DlpFileMetadata(const std::string& source_url, bool is_dlp_restricted); + + friend bool operator==(const DlpFileMetadata& a, const DlpFileMetadata& b) { + return a.is_dlp_restricted == b.is_dlp_restricted && + a.source_url == b.source_url; + } + friend bool operator!=(const DlpFileMetadata& a, const DlpFileMetadata& b) { + return !(a == b); + } + + // Source URL from which the file was downloaded. + std::string source_url; + // Whether the file is under any DLP rule or not. + bool is_dlp_restricted; + }; + using GetDisallowedTransfersCallback = base::OnceCallback<void(std::vector<storage::FileSystemURL>)>; using GetFilesRestrictedByAnyRuleCallback = GetDisallowedTransfersCallback; using FilterDisallowedUploadsCallback = base::OnceCallback<void( std::vector<blink::mojom::FileChooserFileInfoPtr>)>; + using GetDlpMetadataCallback = + base::OnceCallback<void(std::vector<DlpFileMetadata>)>; DlpFilesController(); - DlpFilesController(const DlpFilesController& other) = delete; DlpFilesController& operator=(const DlpFilesController& other) = delete; @@ -46,10 +68,10 @@ storage::FileSystemURL destination, GetDisallowedTransfersCallback result_callback); - // Returns a list of files restricted by any DLP rule in |result_callback|. - void GetFilesRestrictedByAnyRule( - std::vector<storage::FileSystemURL> files, - GetFilesRestrictedByAnyRuleCallback result_callback); + // Retrieves metadata for each entry in |files| and returns it as a list in + // |result_callback|. + void GetDlpMetadata(std::vector<storage::FileSystemURL> files, + GetDlpMetadataCallback result_callback); // Filters files disallowed to be uploaded to `destination`. void FilterDisallowedUploads( @@ -74,6 +96,9 @@ std::vector<blink::mojom::FileChooserFileInfoPtr> uploaded_files, FilterDisallowedUploadsCallback result_callback, dlp::CheckFilesTransferResponse response); + void ReturnDlpMetadata(std::vector<absl::optional<ino_t>> inodes, + GetDlpMetadataCallback result_callback, + const dlp::GetFilesSourcesResponse response); base::WeakPtrFactory<DlpFilesController> weak_ptr_factory_{this}; };
diff --git a/chrome/browser/ash/policy/dlp/dlp_files_controller_unittest.cc b/chrome/browser/ash/policy/dlp/dlp_files_controller_unittest.cc index 19239177..50e1394 100644 --- a/chrome/browser/ash/policy/dlp/dlp_files_controller_unittest.cc +++ b/chrome/browser/ash/policy/dlp/dlp_files_controller_unittest.cc
@@ -70,6 +70,10 @@ } // namespace class DlpFilesControllerTest : public testing::Test { + public: + DlpFilesControllerTest(const DlpFilesControllerTest&) = delete; + DlpFilesControllerTest& operator=(const DlpFilesControllerTest&) = delete; + protected: DlpFilesControllerTest() : profile_(std::make_unique<TestingProfile>()), @@ -77,10 +81,7 @@ scoped_user_manager_(std::make_unique<user_manager::ScopedUserManager>( base::WrapUnique(user_manager_))) {} - DlpFilesControllerTest(const DlpFilesControllerTest&) = delete; - DlpFilesControllerTest& operator=(const DlpFilesControllerTest&) = delete; - - ~DlpFilesControllerTest() override {} + ~DlpFilesControllerTest() override = default; void SetUp() override { AccountId account_id = AccountId::FromUserEmailGaiaId(kEmailId, kGaiaId); @@ -327,19 +328,58 @@ EXPECT_EQ(filtered_uploads, future.Take()); } +TEST_F(DlpFilesControllerTest, GetDlpMetadata) { + AddFilesToDlpClient(); + + std::vector<storage::FileSystemURL> files_to_check( + {file_url1_, file_url2_, file_url3_}); + std::vector<DlpFilesController::DlpFileMetadata> dlp_metadata( + {DlpFilesController::DlpFileMetadata(kExample1, true), + DlpFilesController::DlpFileMetadata(kExample2, false), + DlpFilesController::DlpFileMetadata(kExample3, true)}); + + EXPECT_CALL(*rules_manager_, IsRestrictedByAnyRule) + .WillOnce(testing::Return(DlpRulesManager::Level::kBlock)) + .WillOnce(testing::Return(DlpRulesManager::Level::kAllow)) + .WillOnce(testing::Return(DlpRulesManager::Level::kWarn)); + + base::test::TestFuture<std::vector<DlpFilesController::DlpFileMetadata>> + future; + files_controller_.GetDlpMetadata(files_to_check, future.GetCallback()); + EXPECT_TRUE(future.Wait()); + EXPECT_EQ(dlp_metadata, future.Take()); +} + +TEST_F(DlpFilesControllerTest, GetDlpMetadata_FileNotAvailable) { + ASSERT_TRUE(chromeos::DlpClient::Get()->IsAlive()); + + std::vector<storage::FileSystemURL> files_to_check({file_url1_}); + std::vector<DlpFilesController::DlpFileMetadata> dlp_metadata( + {DlpFilesController::DlpFileMetadata("", false)}); + + EXPECT_CALL(*rules_manager_, IsRestrictedByAnyRule).Times(0); + + base::test::TestFuture<std::vector<DlpFilesController::DlpFileMetadata>> + future; + files_controller_.GetDlpMetadata(files_to_check, future.GetCallback()); + EXPECT_TRUE(future.Wait()); + EXPECT_EQ(dlp_metadata, future.Take()); +} + class DlpFilesExternalDestinationTest : public DlpFilesControllerTest, public ::testing::WithParamInterface< std::tuple<std::string, std::string, DlpRulesManager::Component>> { - protected: - DlpFilesExternalDestinationTest() = default; - + public: DlpFilesExternalDestinationTest(const DlpFilesExternalDestinationTest&) = delete; DlpFilesExternalDestinationTest& operator=( const DlpFilesExternalDestinationTest&) = delete; - ~DlpFilesExternalDestinationTest() = default; + protected: + DlpFilesExternalDestinationTest() = default; + + ~DlpFilesExternalDestinationTest() override = default; void SetUp() override { DlpFilesControllerTest::SetUp();
diff --git a/chrome/browser/ash/policy/status_collector/app_info_generator_unittest.cc b/chrome/browser/ash/policy/status_collector/app_info_generator_unittest.cc index 0a558680..63d4fb4 100644 --- a/chrome/browser/ash/policy/status_collector/app_info_generator_unittest.cc +++ b/chrome/browser/ash/policy/status_collector/app_info_generator_unittest.cc
@@ -17,7 +17,6 @@ #include "chrome/browser/ash/login/users/chrome_user_manager.h" #include "chrome/browser/ash/login/users/fake_chrome_user_manager.h" #include "chrome/browser/ash/login/users/mock_user_manager.h" -#include "chrome/browser/web_applications/system_web_apps/test/test_system_web_app_manager.h" #include "chrome/browser/web_applications/test/fake_install_finalizer.h" #include "chrome/browser/web_applications/test/fake_web_app_provider.h" #include "chrome/browser/web_applications/test/fake_web_app_registry_controller.h" @@ -210,24 +209,11 @@ profile_ = CreateProfile(account_id_); test_clock().SetNow(MakeLocalTime("25-MAR-2020 1:30am")); - web_app::WebAppProviderFactory::GetInstance()->SetTestingFactoryAndUse( - profile_.get(), - base::BindLambdaForTesting([this](content::BrowserContext* context) - -> std::unique_ptr<KeyedService> { - Profile* profile = Profile::FromBrowserContext(context); - auto provider = - std::make_unique<web_app::FakeWebAppProvider>(profile); - auto app_registrar = - std::make_unique<web_app::WebAppRegistrarMutable>(profile); - auto system_web_app_manager = - std::make_unique<web_app::TestSystemWebAppManager>(profile); + auto* provider = web_app::FakeWebAppProvider::Get(profile_.get()); + provider->SetRunSubsystemStartupTasks(true); + provider->Start(); - app_registrar_ = app_registrar.get(); - provider->SetRegistrar(std::move(app_registrar)); - provider->SetSystemWebAppManager(std::move(system_web_app_manager)); - provider->Start(); - return provider; - })); + app_registrar_ = &provider->GetRegistrarMutable(); } apps::AppRegistryCache& GetCache() {
diff --git a/chrome/browser/ash/system_web_apps/system_web_app_manager.cc b/chrome/browser/ash/system_web_apps/system_web_app_manager.cc index 385ba4e2..4da38809 100644 --- a/chrome/browser/ash/system_web_apps/system_web_app_manager.cc +++ b/chrome/browser/ash/system_web_apps/system_web_app_manager.cc
@@ -22,10 +22,12 @@ #include "base/version.h" #include "build/chromeos_buildflags.h" #include "chrome/browser/ash/system_web_apps/system_web_app_background_task.h" +#include "chrome/browser/ash/system_web_apps/system_web_app_manager_factory.h" #include "chrome/browser/ash/system_web_apps/types/system_web_app_delegate.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/web_applications/external_install_options.h" +#include "chrome/browser/web_applications/manifest_update_manager.h" #include "chrome/browser/web_applications/policy/web_app_policy_manager.h" #include "chrome/browser/web_applications/user_display_mode.h" #include "chrome/browser/web_applications/web_app.h" @@ -241,20 +243,20 @@ system_app_delegates_ = CreateSystemWebApps(profile_); } -SystemWebAppManager::~SystemWebAppManager() = default; +SystemWebAppManager::~SystemWebAppManager() { + // SystemWebAppManager lifetime matches WebAppProvider lifetime (see + // BrowserContextDependencyManager) but we reset pointers to + // system_app_delegates_ for integrity with DCHECKs. + if (provider_) + ConnectProviderToSystemWebAppDelegateMap(nullptr); +} // static SystemWebAppManager* SystemWebAppManager::Get(Profile* profile) { if (!web_app::AreSystemWebAppsSupported()) return nullptr; - web_app::WebAppProvider* provider = - web_app::WebAppProvider::GetForLocalAppsUnchecked(profile); - if (!provider) - return nullptr; - - provider->CheckIsConnected(); - return provider->system_web_app_manager_.get(); + return GetForLocalAppsUnchecked(profile); } // static @@ -269,24 +271,33 @@ // static SystemWebAppManager* SystemWebAppManager::GetForLocalAppsUnchecked( Profile* profile) { - web_app::WebAppProvider* provider = - web_app::WebAppProvider::GetForLocalAppsUnchecked(profile); - if (!provider) + SystemWebAppManager* swa_manager = + SystemWebAppManagerFactory::GetForProfile(profile); + if (!swa_manager) return nullptr; - provider->CheckIsConnected(); - return provider->system_web_app_manager_.get(); + swa_manager->CheckIsConnected(); + return swa_manager; } // static SystemWebAppManager* SystemWebAppManager::GetForTest(Profile* profile) { web_app::WebAppProvider* provider = - web_app::WebAppProvider::GetForTest(profile); + SystemWebAppManager::GetWebAppProvider(profile); if (!provider) return nullptr; - provider->CheckIsConnected(); - return provider->system_web_app_manager_.get(); + SystemWebAppManager* swa_manager = GetForLocalAppsUnchecked(profile); + DCHECK(swa_manager); + swa_manager->CheckIsConnected(); + + if (provider->on_registry_ready().is_signaled()) + return swa_manager; + + base::RunLoop run_loop; + provider->on_registry_ready().Post(FROM_HERE, run_loop.QuitClosure()); + run_loop.Run(); + return swa_manager; } void SystemWebAppManager::StopBackgroundTasks() { @@ -299,11 +310,6 @@ return IsSystemWebAppEnabled(system_app_delegates_, type); } -void SystemWebAppManager::Shutdown() { - shutting_down_ = true; - StopBackgroundTasks(); -} - void SystemWebAppManager::SetSubsystems( web_app::ExternallyManagedAppManager* externally_managed_app_manager, web_app::WebAppRegistrar* registrar, @@ -320,6 +326,25 @@ ui_manager_observation_.Observe(ui_manager); } +void SystemWebAppManager::ConnectSubsystems(web_app::WebAppProvider* provider) { + DCHECK(provider); + DCHECK(!provider_); + provider_ = provider; + + SetSubsystems(&provider->externally_managed_app_manager(), + &provider->registrar(), &provider->sync_bridge(), + &provider->ui_manager(), &provider->policy_manager()); + + ConnectProviderToSystemWebAppDelegateMap(&system_app_delegates_); +} + +void SystemWebAppManager::ScheduleStart() { + CheckIsConnected(); + + provider_->on_registry_ready().Post( + FROM_HERE, base::BindOnce(&SystemWebAppManager::Start, GetWeakPtr())); +} + void SystemWebAppManager::Start() { const base::TimeTicks install_start_time = base::TimeTicks::Now(); @@ -370,6 +395,11 @@ should_force_install_apps, install_start_time)); } +void SystemWebAppManager::Shutdown() { + shutting_down_ = true; + StopBackgroundTasks(); +} + void SystemWebAppManager::InstallSystemAppsForTesting() { on_apps_synchronized_ = std::make_unique<base::OneShotEvent>(); on_tasks_started_ = std::make_unique<base::OneShotEvent>(); @@ -717,4 +747,19 @@ return true; } +void SystemWebAppManager::CheckIsConnected() const { + DCHECK(provider_) << "Attempted to access SystemWebAppManager while " + "it is is not connected to WebAppProvider."; +} + +void SystemWebAppManager::ConnectProviderToSystemWebAppDelegateMap( + const SystemWebAppDelegateMap* system_web_apps_delegate_map) const { + DCHECK(provider_); + + provider_->manifest_update_manager().SetSystemWebAppDelegateMap( + system_web_apps_delegate_map); + provider_->policy_manager().SetSystemWebAppDelegateMap( + system_web_apps_delegate_map); +} + } // namespace ash
diff --git a/chrome/browser/ash/system_web_apps/system_web_app_manager.h b/chrome/browser/ash/system_web_apps/system_web_app_manager.h index b3849880..f83bdd8 100644 --- a/chrome/browser/ash/system_web_apps/system_web_app_manager.h +++ b/chrome/browser/ash/system_web_apps/system_web_app_manager.h
@@ -25,6 +25,7 @@ #include "chrome/browser/web_applications/web_app_install_info.h" #include "chrome/browser/web_applications/web_app_ui_manager.h" #include "chrome/browser/web_applications/web_app_url_loader.h" +#include "components/keyed_service/core/keyed_service.h" #include "components/prefs/pref_change_registrar.h" #include "content/public/browser/web_contents.h" #include "ui/gfx/geometry/rect.h" @@ -58,8 +59,10 @@ // Installs, uninstalls, and updates System Web Apps. // System Web Apps are built-in, highly-privileged Web Apps for Chrome OS. They -// have access to more APIs and are part of the Chrome OS image. -class SystemWebAppManager : private web_app::WebAppUiManagerObserver { +// have access to more APIs and are part of the Chrome OS image. All clients +// should await `on_apps_synchronized()` event to start working with SWAs. +class SystemWebAppManager : public KeyedService, + public web_app::WebAppUiManagerObserver { public: // Policy for when the SystemWebAppManager will update apps/install new apps. enum class UpdatePolicy { @@ -109,10 +112,15 @@ web_app::WebAppSyncBridge* sync_bridge, web_app::WebAppUiManager* ui_manager, web_app::WebAppPolicyManager* web_app_policy_manager); + void ConnectSubsystems(web_app::WebAppProvider* provider); + void ScheduleStart(); // Gets called when `WebAppProvider` is ready. void Start(); + // KeyedService: + void Shutdown() override; + // The SystemWebAppManager is disabled in browser tests by default because it // pollutes the startup state (several tests expect the Extensions state to be // clean). @@ -176,8 +184,6 @@ void ResetOnAppsSynchronizedForTesting(); - void Shutdown(); - // Get the timers. Only use this for testing. const std::vector<std::unique_ptr<SystemWebAppBackgroundTask>>& GetBackgroundTasksForTesting(); @@ -225,7 +231,14 @@ content::NavigationHandle* navigation_handle) override; void OnWebAppUiManagerDestroyed() override; + void CheckIsConnected() const; + void ConnectProviderToSystemWebAppDelegateMap( + const SystemWebAppDelegateMap* system_web_apps_delegate_map) const; + raw_ptr<Profile> profile_; + // SystemWebAppManager KeyedService depends on WebAppProvider KeyedService, + // therefore this pointer is always valid once connected. + raw_ptr<web_app::WebAppProvider> provider_ = nullptr; std::unique_ptr<base::OneShotEvent> on_apps_synchronized_; std::unique_ptr<base::OneShotEvent> on_tasks_started_;
diff --git a/chrome/browser/ash/system_web_apps/system_web_app_manager_factory.cc b/chrome/browser/ash/system_web_apps/system_web_app_manager_factory.cc new file mode 100644 index 0000000..278dcdb6 --- /dev/null +++ b/chrome/browser/ash/system_web_apps/system_web_app_manager_factory.cc
@@ -0,0 +1,69 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ash/system_web_apps/system_web_app_manager_factory.h" + +#include "chrome/browser/ash/system_web_apps/system_web_app_manager.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/web_applications/web_app_provider.h" +#include "chrome/browser/web_applications/web_app_provider_factory.h" +#include "chrome/browser/web_applications/web_app_utils.h" +#include "components/keyed_service/content/browser_context_dependency_manager.h" + +namespace ash { + +// static +SystemWebAppManager* SystemWebAppManagerFactory::GetForProfile( + Profile* profile) { + return static_cast<SystemWebAppManager*>( + SystemWebAppManagerFactory::GetInstance()->GetServiceForBrowserContext( + profile, true /* create */)); +} + +// static +SystemWebAppManagerFactory* SystemWebAppManagerFactory::GetInstance() { + return base::Singleton<SystemWebAppManagerFactory>::get(); +} + +// static +bool SystemWebAppManagerFactory::IsServiceCreatedForProfile(Profile* profile) { + return SystemWebAppManagerFactory::GetInstance()->GetServiceForBrowserContext( + profile, /*create=*/false) != nullptr; +} + +SystemWebAppManagerFactory::SystemWebAppManagerFactory() + : BrowserContextKeyedServiceFactory( + "SystemWebAppManager", + BrowserContextDependencyManager::GetInstance()) { + DependsOn(web_app::WebAppProviderFactory::GetInstance()); +} + +SystemWebAppManagerFactory::~SystemWebAppManagerFactory() = default; + +KeyedService* SystemWebAppManagerFactory::BuildServiceInstanceFor( + content::BrowserContext* context) const { + Profile* profile = Profile::FromBrowserContext(context); + DCHECK(web_app::WebAppProviderFactory::IsServiceCreatedForProfile(profile)); + + web_app::WebAppProvider* provider = + web_app::WebAppProvider::GetForLocalAppsUnchecked(profile); + DCHECK(provider); + + SystemWebAppManager* swa_manager = new SystemWebAppManager(profile); + swa_manager->ConnectSubsystems(provider); + swa_manager->ScheduleStart(); + + return swa_manager; +} + +bool SystemWebAppManagerFactory::ServiceIsCreatedWithBrowserContext() const { + return true; +} + +content::BrowserContext* SystemWebAppManagerFactory::GetBrowserContextToUse( + content::BrowserContext* context) const { + return web_app::GetBrowserContextForWebApps(context); +} + +} // namespace ash
diff --git a/chrome/browser/ash/system_web_apps/system_web_app_manager_factory.h b/chrome/browser/ash/system_web_apps/system_web_app_manager_factory.h new file mode 100644 index 0000000..ea1660de --- /dev/null +++ b/chrome/browser/ash/system_web_apps/system_web_app_manager_factory.h
@@ -0,0 +1,55 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_ASH_SYSTEM_WEB_APPS_SYSTEM_WEB_APP_MANAGER_FACTORY_H_ +#define CHROME_BROWSER_ASH_SYSTEM_WEB_APPS_SYSTEM_WEB_APP_MANAGER_FACTORY_H_ + +#include "base/memory/singleton.h" +#include "components/keyed_service/content/browser_context_keyed_service_factory.h" + +namespace content { +class BrowserContext; +} + +class Profile; + +namespace ash { + +class SystemWebAppManager; + +// Singleton factory that creates all SystemWebAppManagers and associates them +// with Profile. Clients of SystemWebAppManager shouldn't use this class to +// obtain SystemWebAppManager instances, instead they should call +// SystemWebAppManager static methods. +class SystemWebAppManagerFactory : public BrowserContextKeyedServiceFactory { + public: + SystemWebAppManagerFactory(const SystemWebAppManagerFactory&) = delete; + SystemWebAppManagerFactory& operator=(const SystemWebAppManagerFactory&) = + delete; + + static SystemWebAppManagerFactory* GetInstance(); + + static bool IsServiceCreatedForProfile(Profile* profile); + + private: + friend struct base::DefaultSingletonTraits<SystemWebAppManagerFactory>; + friend class SystemWebAppManager; + + SystemWebAppManagerFactory(); + ~SystemWebAppManagerFactory() override; + + // Called by SystemWebAppManager static methods. + static SystemWebAppManager* GetForProfile(Profile* profile); + + // BrowserContextKeyedServiceFactory + KeyedService* BuildServiceInstanceFor( + content::BrowserContext* context) const override; + bool ServiceIsCreatedWithBrowserContext() const override; + content::BrowserContext* GetBrowserContextToUse( + content::BrowserContext* context) const override; +}; + +} // namespace ash + +#endif // CHROME_BROWSER_ASH_SYSTEM_WEB_APPS_SYSTEM_WEB_APP_MANAGER_FACTORY_H_
diff --git a/chrome/browser/chrome_back_forward_cache_browsertest.cc b/chrome/browser/chrome_back_forward_cache_browsertest.cc index 96b82acb..598c0662 100644 --- a/chrome/browser/chrome_back_forward_cache_browsertest.cc +++ b/chrome/browser/chrome_back_forward_cache_browsertest.cc
@@ -234,9 +234,8 @@ content::RenderFrameHost::LifecycleState::kInBackForwardCache); } -// TODO(crbug.com/1324437): Disabled for being flaky. IN_PROC_BROWSER_TEST_F(ChromeBackForwardCacheBrowserTest, - DISABLED_PermissionContextBase) { + PermissionContextBase) { // HTTPS needed for GEOLOCATION permission net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS); https_server.AddDefaultHandlers(GetChromeTestDataDir());
diff --git a/chrome/browser/chrome_content_browser_client_unittest.cc b/chrome/browser/chrome_content_browser_client_unittest.cc index 077d33b..6ecb5f99 100644 --- a/chrome/browser/chrome_content_browser_client_unittest.cc +++ b/chrome/browser/chrome_content_browser_client_unittest.cc
@@ -79,6 +79,8 @@ #include "chrome/browser/ash/login/users/fake_chrome_user_manager.h" #include "chrome/browser/policy/networking/policy_cert_service.h" #include "chrome/browser/policy/networking/policy_cert_service_factory.h" +#include "chrome/browser/web_applications/system_web_apps/test/test_system_web_app_manager.h" +#include "chrome/browser/web_applications/web_app_provider.h" #include "components/user_manager/scoped_user_manager.h" #endif // BUILDFLAG(IS_CHROMEOS_ASH) @@ -97,8 +99,35 @@ using content::BrowsingDataFilterBuilder; using testing::_; using testing::NotNull; + class ChromeContentBrowserClientTest : public testing::Test { + public: + ChromeContentBrowserClientTest() +#if BUILDFLAG(IS_CHROMEOS_ASH) + : test_system_web_app_manager_creator_(base::BindRepeating( + &ChromeContentBrowserClientTest::CreateSystemWebAppManager, + base::Unretained(this))) +#endif // BUILDFLAG(IS_CHROMEOS_ASH) + { + } + protected: +#if BUILDFLAG(IS_CHROMEOS_ASH) + std::unique_ptr<KeyedService> CreateSystemWebAppManager(Profile* profile) { + auto* provider = web_app::WebAppProvider::GetForLocalAppsUnchecked(profile); + DCHECK(provider); + + // Unit tests need SWAs from production. Creates real SystemWebAppManager + // instead of `TestSystemWebAppManager::BuildDefault()` for + // `TestingProfile`. + auto swa_manager = std::make_unique<ash::SystemWebAppManager>(profile); + swa_manager->ConnectSubsystems(provider); + return swa_manager; + } + // The custom manager creator should be constructed before `TestingProfile`. + web_app::TestSystemWebAppManagerCreator test_system_web_app_manager_creator_; +#endif // BUILDFLAG(IS_CHROMEOS_ASH) + content::BrowserTaskEnvironment task_environment_; TestingProfile profile_; }; @@ -573,6 +602,8 @@ } TEST_F(ChromeContentSettingsRedirectTest, RedirectCameraAppURL) { + // This test needs `SystemWebAppType::CAMERA` (`CameraSystemAppDelegate`) + // registered in `SystemWebAppManager`. TestChromeContentBrowserClient test_content_browser_client; const GURL camera_app_url(ash::kChromeUICameraAppMainURL); GURL dest_url = camera_app_url;
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn index 78c4f5302..a2d377d 100644 --- a/chrome/browser/chromeos/BUILD.gn +++ b/chrome/browser/chromeos/BUILD.gn
@@ -588,176 +588,6 @@ ] sources = [ - "../ash/guest_os/guest_os_capabilities.cc", - "../ash/guest_os/guest_os_capabilities.h", - "../ash/guest_os/guest_os_diagnostics_builder.cc", - "../ash/guest_os/guest_os_diagnostics_builder.h", - "../ash/guest_os/guest_os_external_protocol_handler.cc", - "../ash/guest_os/guest_os_external_protocol_handler.h", - "../ash/guest_os/guest_os_launcher.cc", - "../ash/guest_os/guest_os_launcher.h", - "../ash/guest_os/guest_os_mime_types_service.cc", - "../ash/guest_os/guest_os_mime_types_service.h", - "../ash/guest_os/guest_os_mime_types_service_factory.cc", - "../ash/guest_os/guest_os_mime_types_service_factory.h", - "../ash/guest_os/guest_os_pref_names.cc", - "../ash/guest_os/guest_os_pref_names.h", - "../ash/guest_os/guest_os_registry_service.cc", - "../ash/guest_os/guest_os_registry_service.h", - "../ash/guest_os/guest_os_registry_service_factory.cc", - "../ash/guest_os/guest_os_registry_service_factory.h", - "../ash/guest_os/guest_os_share_path.cc", - "../ash/guest_os/guest_os_share_path.h", - "../ash/guest_os/guest_os_share_path_factory.cc", - "../ash/guest_os/guest_os_share_path_factory.h", - "../ash/guest_os/guest_os_stability_monitor.cc", - "../ash/guest_os/guest_os_stability_monitor.h", - "../ash/guest_os/infra/cached_callback.h", - "../ash/guest_os/public/guest_os_mount_provider.cc", - "../ash/guest_os/public/guest_os_mount_provider.h", - "../ash/guest_os/public/guest_os_mount_provider_registry.cc", - "../ash/guest_os/public/guest_os_mount_provider_registry.h", - "../ash/guest_os/public/guest_os_service.cc", - "../ash/guest_os/public/guest_os_service.h", - "../ash/guest_os/public/guest_os_service_factory.cc", - "../ash/guest_os/public/guest_os_service_factory.h", - "../ash/guest_os/public/guest_os_terminal_provider.cc", - "../ash/guest_os/public/guest_os_terminal_provider.h", - "../ash/guest_os/public/guest_os_terminal_provider_registry.cc", - "../ash/guest_os/public/guest_os_terminal_provider_registry.h", - "../ash/guest_os/public/guest_os_wayland_server.cc", - "../ash/guest_os/public/guest_os_wayland_server.h", - "../ash/guest_os/public/installer_delegate_factory.cc", - "../ash/guest_os/public/installer_delegate_factory.h", - "../ash/guest_os/public/types.h", - "../ash/guest_os/virtual_machines/virtual_machines_util.cc", - "../ash/guest_os/virtual_machines/virtual_machines_util.h", - "../ash/guest_os/vm_sk_forwarding_native_message_host.cc", - "../ash/guest_os/vm_sk_forwarding_native_message_host.h", - "../ash/hats/hats_config.cc", - "../ash/hats/hats_config.h", - "../ash/hats/hats_dialog.cc", - "../ash/hats/hats_dialog.h", - "../ash/hats/hats_finch_helper.cc", - "../ash/hats/hats_finch_helper.h", - "../ash/hats/hats_notification_controller.cc", - "../ash/hats/hats_notification_controller.h", - "../ash/idle_detector.cc", - "../ash/idle_detector.h", - "../ash/input_method/accessibility.cc", - "../ash/input_method/accessibility.h", - "../ash/input_method/assistive_suggester.cc", - "../ash/input_method/assistive_suggester.h", - "../ash/input_method/assistive_suggester_client_filter.cc", - "../ash/input_method/assistive_suggester_client_filter.h", - "../ash/input_method/assistive_suggester_prefs.cc", - "../ash/input_method/assistive_suggester_prefs.h", - "../ash/input_method/assistive_suggester_switch.h", - "../ash/input_method/assistive_window_controller.cc", - "../ash/input_method/assistive_window_controller.h", - "../ash/input_method/assistive_window_controller_delegate.h", - "../ash/input_method/assistive_window_properties.cc", - "../ash/input_method/assistive_window_properties.h", - "../ash/input_method/autocorrect_manager.cc", - "../ash/input_method/autocorrect_manager.h", - "../ash/input_method/candidate_window_controller.cc", - "../ash/input_method/candidate_window_controller.h", - "../ash/input_method/candidate_window_controller_impl.cc", - "../ash/input_method/candidate_window_controller_impl.h", - "../ash/input_method/component_extension_ime_manager_delegate_impl.cc", - "../ash/input_method/component_extension_ime_manager_delegate_impl.h", - "../ash/input_method/diacritics_checker.cc", - "../ash/input_method/diacritics_checker.h", - "../ash/input_method/diacritics_insensitive_string_comparator.cc", - "../ash/input_method/diacritics_insensitive_string_comparator.h", - "../ash/input_method/emoji_suggester.cc", - "../ash/input_method/emoji_suggester.h", - "../ash/input_method/get_browser_url.cc", - "../ash/input_method/get_browser_url.h", - "../ash/input_method/grammar_manager.cc", - "../ash/input_method/grammar_manager.h", - "../ash/input_method/grammar_service_client.cc", - "../ash/input_method/grammar_service_client.h", - "../ash/input_method/ime_rules_config.cc", - "../ash/input_method/ime_rules_config.h", - "../ash/input_method/ime_service_connector.cc", - "../ash/input_method/ime_service_connector.h", - "../ash/input_method/input_method_configuration.cc", - "../ash/input_method/input_method_configuration.h", - "../ash/input_method/input_method_delegate_impl.cc", - "../ash/input_method/input_method_delegate_impl.h", - "../ash/input_method/input_method_engine.cc", - "../ash/input_method/input_method_engine.h", - "../ash/input_method/input_method_engine_observer.h", - "../ash/input_method/input_method_manager_impl.cc", - "../ash/input_method/input_method_manager_impl.h", - "../ash/input_method/input_method_persistence.cc", - "../ash/input_method/input_method_persistence.h", - "../ash/input_method/input_method_quick_settings_helpers.cc", - "../ash/input_method/input_method_quick_settings_helpers.h", - "../ash/input_method/input_method_settings.cc", - "../ash/input_method/input_method_settings.h", - "../ash/input_method/input_method_syncer.cc", - "../ash/input_method/input_method_syncer.h", - "../ash/input_method/longpress_diacritics_suggester.cc", - "../ash/input_method/longpress_diacritics_suggester.h", - "../ash/input_method/multi_word_suggester.cc", - "../ash/input_method/multi_word_suggester.h", - "../ash/input_method/native_input_method_engine.cc", - "../ash/input_method/native_input_method_engine.h", - "../ash/input_method/native_input_method_engine_observer.cc", - "../ash/input_method/native_input_method_engine_observer.h", - "../ash/input_method/personal_info_suggester.cc", - "../ash/input_method/personal_info_suggester.h", - "../ash/input_method/suggester.h", - "../ash/input_method/suggestion_enums.h", - "../ash/input_method/suggestion_handler_interface.h", - "../ash/input_method/suggestions_collector.cc", - "../ash/input_method/suggestions_collector.h", - "../ash/input_method/suggestions_service_client.cc", - "../ash/input_method/suggestions_service_client.h", - "../ash/input_method/suggestions_source.h", - "../ash/input_method/text_field_contextual_info_fetcher.cc", - "../ash/input_method/text_field_contextual_info_fetcher.h", - "../ash/input_method/text_utils.cc", - "../ash/input_method/text_utils.h", - "../ash/input_method/ui/assistive_accessibility_view.cc", - "../ash/input_method/ui/assistive_accessibility_view.h", - "../ash/input_method/ui/assistive_delegate.h", - "../ash/input_method/ui/border_factory.cc", - "../ash/input_method/ui/border_factory.h", - "../ash/input_method/ui/candidate_view.cc", - "../ash/input_method/ui/candidate_view.h", - "../ash/input_method/ui/candidate_window_constants.h", - "../ash/input_method/ui/candidate_window_view.cc", - "../ash/input_method/ui/candidate_window_view.h", - "../ash/input_method/ui/colors.cc", - "../ash/input_method/ui/colors.h", - "../ash/input_method/ui/completion_suggestion_label_view.cc", - "../ash/input_method/ui/completion_suggestion_label_view.h", - "../ash/input_method/ui/grammar_suggestion_window.cc", - "../ash/input_method/ui/grammar_suggestion_window.h", - "../ash/input_method/ui/infolist_window.cc", - "../ash/input_method/ui/infolist_window.h", - "../ash/input_method/ui/input_method_menu_item.cc", - "../ash/input_method/ui/input_method_menu_item.h", - "../ash/input_method/ui/input_method_menu_manager.cc", - "../ash/input_method/ui/input_method_menu_manager.h", - "../ash/input_method/ui/suggestion_accessibility_label.cc", - "../ash/input_method/ui/suggestion_accessibility_label.h", - "../ash/input_method/ui/suggestion_details.h", - "../ash/input_method/ui/suggestion_view.cc", - "../ash/input_method/ui/suggestion_view.h", - "../ash/input_method/ui/suggestion_window_view.cc", - "../ash/input_method/ui/suggestion_window_view.h", - "../ash/input_method/ui/undo_window.cc", - "../ash/input_method/ui/undo_window.h", - "../ash/kerberos/kerberos_credentials_manager.cc", - "../ash/kerberos/kerberos_credentials_manager.h", - "../ash/kerberos/kerberos_credentials_manager_factory.cc", - "../ash/kerberos/kerberos_credentials_manager_factory.h", - "../ash/kerberos/kerberos_ticket_expiry_notification.cc", - "../ash/kerberos/kerberos_ticket_expiry_notification.h", "../ash/language_preferences.cc", "../ash/language_preferences.h", "../ash/locale_change_guard.cc", @@ -3355,10 +3185,10 @@ "../ash/input_method/ui/candidate_view_unittest.cc", "../ash/input_method/ui/candidate_window_view_unittest.cc", "../ash/input_method/ui/completion_suggestion_label_view_unittest.cc", + "../ash/input_method/ui/completion_suggestion_view_unittest.cc", "../ash/input_method/ui/grammar_suggestion_window_unittest.cc", "../ash/input_method/ui/input_method_menu_item_unittest.cc", "../ash/input_method/ui/input_method_menu_manager_unittest.cc", - "../ash/input_method/ui/suggestion_view_unittest.cc", "../ash/input_method/ui/suggestion_window_view_unittest.cc", "../ash/input_method/ui/undo_window_unittest.cc", "../ash/kerberos/kerberos_credentials_manager_test.cc",
diff --git a/chrome/browser/chromeos/extensions/file_manager/event_router.cc b/chrome/browser/chromeos/extensions/file_manager/event_router.cc index f0fb5c56..319f0b3 100644 --- a/chrome/browser/chromeos/extensions/file_manager/event_router.cc +++ b/chrome/browser/chromeos/extensions/file_manager/event_router.cc
@@ -1238,94 +1238,173 @@ } void EventRouter::OnIOTaskStatus(const io_task::ProgressStatus& status) { - // If any Files app window exists we send the progress to all of them. - if (DoFilesSwaWindowsExist(profile_)) { - file_manager_private::ProgressStatus event_status; - event_status.task_id = status.task_id; - event_status.type = GetIOTaskType(status.type); - event_status.state = GetIOTaskState(status.state); - - // Speedometer can produce infinite result which can't be serialized to JSON - // when sending the status via private API. - if (std::isfinite(status.remaining_seconds)) { - event_status.remaining_seconds = status.remaining_seconds; - } - - if (status.destination_folder.is_valid()) { - event_status.destination_name = - util::GetDisplayablePath(profile_, status.destination_folder) - .value_or(base::FilePath()) - .BaseName() - .value(); - } - - size_t processed = 0; - for (const auto& file_status : status.outputs) { - if (file_status.error) - processed++; - } - event_status.num_remaining_items = status.sources.size() - processed; - event_status.item_count = status.sources.size(); - - // Get the last error occurrence in the `sources`. - for (const io_task::EntryStatus& source : base::Reversed(status.sources)) { - if (source.error && source.error.value() != base::File::FILE_OK) { - event_status.error_name = FileErrorToErrorName(source.error.value()); - } - } - // If we have no error on 'sources', check if an error came from 'outputs'. - if (status.state == io_task::State::kError && - event_status.error_name.empty()) { - for (const io_task::EntryStatus& dest : base::Reversed(status.outputs)) { - if (dest.error && dest.error.value() != base::File::FILE_OK) { - event_status.error_name = FileErrorToErrorName(dest.error.value()); - } - } - } - - if (status.sources.size() > 0) { - event_status.source_name = - util::GetDisplayablePath(profile_, status.sources.front().url) - .value_or(base::FilePath()) - .BaseName() - .value(); - } - event_status.bytes_transferred = status.bytes_transferred; - event_status.total_bytes = status.total_bytes; - - BroadcastEvent( - profile_, - extensions::events::FILE_MANAGER_PRIVATE_ON_IO_TASK_PROGRESS_STATUS, - file_manager_private::OnIOTaskProgressStatus::kEventName, - file_manager_private::OnIOTaskProgressStatus::Create(event_status)); - - // Send file watch notifications on I/O task completion. inotify is flaky on - // some filesystems, so send these notifications so that at least operations - // made from Files App are always reflected in the UI. - if (status.IsCompleted()) { - std::set<base::FilePath> updated_paths; - if (status.destination_folder.is_valid()) { - updated_paths.insert(status.destination_folder.path()); - } - for (const auto& source : status.sources) { - updated_paths.insert(source.url.path().DirName()); - } - for (const auto& output : status.outputs) { - updated_paths.insert(output.url.path().DirName()); - } - - for (const auto& path : updated_paths) { - HandleFileWatchNotification(path, false); - } - } - - // Send the progress report to the system notification regardless of whether - // Files app window exists as we may need to remove an existing - // notification. + // Send the progress report to the system notification regardless of whether + // Files app window exists as we may need to remove an existing + // notification. + notification_manager_->HandleIOTaskProgress(status); + if (!DoFilesSwaWindowsExist(profile_) && !force_broadcasting_for_testing_) { + return; } - notification_manager_->HandleIOTaskProgress(status); + // Send file watch notifications on I/O task completion. inotify is flaky on + // some filesystems, so send these notifications so that at least operations + // made from Files App are always reflected in the UI. + if (status.IsCompleted()) { + std::set<base::FilePath> updated_paths; + if (status.destination_folder.is_valid()) { + updated_paths.insert(status.destination_folder.path()); + } + for (const auto& source : status.sources) { + updated_paths.insert(source.url.path().DirName()); + } + for (const auto& output : status.outputs) { + updated_paths.insert(output.url.path().DirName()); + } + + for (const auto& path : updated_paths) { + HandleFileWatchNotification(path, false); + } + } + + // If any Files app window exists we send the progress to all of them. + file_manager_private::ProgressStatus event_status; + event_status.task_id = status.task_id; + event_status.type = GetIOTaskType(status.type); + event_status.state = GetIOTaskState(status.state); + + // Speedometer can produce infinite result which can't be serialized to JSON + // when sending the status via private API. + if (std::isfinite(status.remaining_seconds)) { + event_status.remaining_seconds = status.remaining_seconds; + } + + if (status.destination_folder.is_valid()) { + event_status.destination_name = + util::GetDisplayablePath(profile_, status.destination_folder) + .value_or(base::FilePath()) + .BaseName() + .value(); + } + + size_t processed = 0; + std::vector<storage::FileSystemURL> outputs; + for (const auto& file_status : status.outputs) { + if (file_status.error) { + if (status.type == file_manager::io_task::OperationType::kTrash && + file_status.error.value() == base::File::FILE_OK) { + // These entries are currently used to undo a TrashIOTask so only + // consider the successfully trashed files. + outputs.push_back(file_status.url); + } + processed++; + } + } + + event_status.num_remaining_items = status.sources.size() - processed; + event_status.item_count = status.sources.size(); + + // Get the last error occurrence in the `sources`. + for (const io_task::EntryStatus& source : base::Reversed(status.sources)) { + if (source.error && source.error.value() != base::File::FILE_OK) { + event_status.error_name = FileErrorToErrorName(source.error.value()); + } + } + // If we have no error on 'sources', check if an error came from 'outputs'. + if (status.state == io_task::State::kError && + event_status.error_name.empty()) { + for (const io_task::EntryStatus& dest : base::Reversed(status.outputs)) { + if (dest.error && dest.error.value() != base::File::FILE_OK) { + event_status.error_name = FileErrorToErrorName(dest.error.value()); + } + } + } + + if (status.sources.size() > 0) { + event_status.source_name = + util::GetDisplayablePath(profile_, status.sources.front().url) + .value_or(base::FilePath()) + .BaseName() + .value(); + } + event_status.bytes_transferred = status.bytes_transferred; + event_status.total_bytes = status.total_bytes; + + // The TrashIOTask is the only IOTask that uses the output Entry's, so don't + // try to resolve the outputs for all other IOTasks. + if (GetIOTaskType(status.type) != file_manager_private::IO_TASK_TYPE_TRASH || + outputs.size() == 0) { + BroadcastIOTask(std::move(event_status)); + return; + } + + // All FileSystemURLs in the output come from the same FileSystemContext, so + // use the first URL to obtain the context. + auto* file_system_context = util::GetFileSystemContextForSourceURL( + profile_, outputs[0].origin().GetURL()); + if (file_system_context == nullptr) { + LOG(ERROR) << "Could not find file system context"; + BroadcastIOTask(std::move(event_status)); + return; + } + + file_manager::util::FileDefinitionList file_definition_list; + for (const auto& url : outputs) { + file_manager::util::FileDefinition file_definition; + if (file_manager::util::ConvertAbsoluteFilePathToRelativeFileSystemPath( + profile_, url.origin().GetURL(), url.path(), + &file_definition.virtual_path)) { + file_definition_list.push_back(std::move(file_definition)); + } + } + + file_manager::util::ConvertFileDefinitionListToEntryDefinitionList( + file_system_context, outputs[0].origin(), std::move(file_definition_list), + base::BindOnce( + &EventRouter::OnConvertFileDefinitionListToEntryDefinitionList, + weak_factory_.GetWeakPtr(), std::move(event_status))); } + +void EventRouter::OnConvertFileDefinitionListToEntryDefinitionList( + file_manager_private::ProgressStatus event_status, + std::unique_ptr<file_manager::util::EntryDefinitionList> + entry_definition_list) { + if (entry_definition_list == nullptr) { + BroadcastIOTask(std::move(event_status)); + return; + } + std::vector<OutputsType> outputs; + for (const auto& def : *entry_definition_list) { + if (def.error != base::File::FILE_OK) { + LOG(WARNING) << "File entry ignored: " << static_cast<int>(def.error); + continue; + } + OutputsType output_entry; + output_entry.additional_properties.SetStringKey("fileSystemName", + def.file_system_name); + output_entry.additional_properties.SetStringKey("fileSystemRoot", + def.file_system_root_url); + // The `full_path` comes back as relative to the file system root, but the + // UI requires it as an absolute path. + output_entry.additional_properties.SetStringKey( + "fileFullPath", base::FilePath("/").Append(def.full_path).value()); + output_entry.additional_properties.SetBoolKey("fileIsDirectory", + def.is_directory); + outputs.push_back(std::move(output_entry)); + } + event_status.outputs = + std::make_unique<std::vector<OutputsType>>(std::move(outputs)); + BroadcastIOTask(std::move(event_status)); +} + +void EventRouter::BroadcastIOTask( + const file_manager_private::ProgressStatus& event_status) { + BroadcastEvent( + profile_, + extensions::events::FILE_MANAGER_PRIVATE_ON_IO_TASK_PROGRESS_STATUS, + file_manager_private::OnIOTaskProgressStatus::kEventName, + file_manager_private::OnIOTaskProgressStatus::Create(event_status)); +} + void EventRouter::OnRegistered(guest_os::GuestOsMountProviderRegistry::Id id, guest_os::GuestOsMountProvider* provider) { OnMountableGuestsChanged();
diff --git a/chrome/browser/chromeos/extensions/file_manager/event_router.h b/chrome/browser/chromeos/extensions/file_manager/event_router.h index ecf43666..5bc8dfd 100644 --- a/chrome/browser/chromeos/extensions/file_manager/event_router.h +++ b/chrome/browser/chromeos/extensions/file_manager/event_router.h
@@ -45,6 +45,8 @@ class PrefChangeRegistrar; class Profile; +using OutputsType = + extensions::api::file_manager_private::ProgressStatus::OutputsType; using file_manager::util::EntryDefinition; namespace file_manager { @@ -206,6 +208,12 @@ guest_os::GuestOsMountProvider* provider) override; void OnUnregistered(guest_os::GuestOsMountProviderRegistry::Id id) override; + // Use this method for unit tests to bypass checking if there are any SWA + // windows. + void ForceBroadcastingForTesting(bool enabled) { + force_broadcasting_for_testing_ = enabled; + } + private: FRIEND_TEST_ALL_PREFIXES(EventRouterTest, PopulateCrostiniEvent); @@ -276,6 +284,17 @@ // Called to refresh the list of guests and broadcast it. void OnMountableGuestsChanged(); + // After resolving all file definitions, ensure they are available on the + // `event_status`. + void OnConvertFileDefinitionListToEntryDefinitionList( + file_manager_private::ProgressStatus event_status, + std::unique_ptr<file_manager::util::EntryDefinitionList> + entry_definition_list); + + // Broadcast the `event_status` to all open SWA windows. + void BroadcastIOTask( + const file_manager_private::ProgressStatus& event_status); + base::Time last_copy_progress_event_; std::map<base::FilePath, std::unique_ptr<FileWatcher>> file_watchers_; @@ -291,6 +310,9 @@ DispatchDirectoryChangeEventImplCallback dispatch_directory_change_event_impl_; + // Set this to true to ignore the DoFilesSwaWindowsExist check for testing. + bool force_broadcasting_for_testing_ = false; + // Note: This should remain the last member so it'll be destroyed and // invalidate the weak pointers before any other members are destroyed. base::WeakPtrFactory<EventRouter> weak_factory_{this};
diff --git a/chrome/browser/chromeos/extensions/file_manager/event_router_unittest.cc b/chrome/browser/chromeos/extensions/file_manager/event_router_unittest.cc index 83aa0587..83105c8 100644 --- a/chrome/browser/chromeos/extensions/file_manager/event_router_unittest.cc +++ b/chrome/browser/chromeos/extensions/file_manager/event_router_unittest.cc
@@ -3,9 +3,32 @@ // found in the LICENSE file. #include "chrome/browser/chromeos/extensions/file_manager/event_router.h" + +#include <memory> + +#include "base/files/file_path.h" +#include "base/files/file_util.h" +#include "base/files/scoped_temp_dir.h" +#include "base/rand_util.h" +#include "base/run_loop.h" +#include "base/test/bind.h" +#include "base/test/gmock_callback_support.h" #include "base/values.h" +#include "chrome/browser/ash/file_manager/fake_disk_mount_manager.h" +#include "chrome/browser/ash/file_manager/io_task.h" +#include "chrome/browser/ash/file_manager/path_util.h" +#include "chrome/browser/ash/file_manager/volume_manager_factory.h" +#include "chrome/browser/chromeos/extensions/file_manager/event_router_factory.h" +#include "chrome/test/base/testing_profile.h" +#include "content/public/test/browser_task_environment.h" +#include "extensions/browser/event_router.h" +#include "extensions/browser/test_event_router.h" #include "extensions/common/extension.h" +#include "storage/browser/file_system/external_mount_points.h" +#include "storage/browser/test/test_file_system_context.h" +#include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/public/common/storage_key/storage_key.h" #include "url/gurl.h" #include "url/origin.h" @@ -54,4 +77,157 @@ EXPECT_EQ(swa_event.entries[0].additional_properties, swa_props); } +namespace { + +using ::base::test::RunClosure; +using ::testing::_; +using ::testing::AllOf; +using ::testing::Field; + +// Observes the `BroadcastEvent` operation that is emitted by the event router. +// The mock methods are used to assert expectations on the return results. +class TestEventRouterObserver + : public extensions::TestEventRouter::EventObserver { + public: + explicit TestEventRouterObserver(extensions::TestEventRouter* event_router) + : event_router_(event_router) { + event_router_->AddEventObserver(this); + } + ~TestEventRouterObserver() override { + event_router_->RemoveEventObserver(this); + } + TestEventRouterObserver(const TestEventRouterObserver&) = delete; + TestEventRouterObserver& operator=(const TestEventRouterObserver&) = delete; + + // TestEventRouter::EventObserver: + MOCK_METHOD(void, OnBroadcastEvent, (const extensions::Event&), (override)); + MOCK_METHOD(void, + OnDispatchEventToExtension, + (const std::string&, const extensions::Event&), + (override)); + + private: + raw_ptr<extensions::TestEventRouter> event_router_; +}; + +class FileManagerEventRouterTest : public testing::Test { + public: + FileManagerEventRouterTest() = default; + FileManagerEventRouterTest(const FileManagerEventRouterTest&) = delete; + FileManagerEventRouterTest& operator=(const FileManagerEventRouterTest&) = + delete; + + void SetUp() override { + ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); + + profile_ = + std::make_unique<TestingProfile>(base::FilePath(temp_dir_.GetPath())); + file_system_context_ = storage::CreateFileSystemContextForTesting( + nullptr, temp_dir_.GetPath()); + + VolumeManagerFactory::GetInstance()->SetTestingFactory( + profile_.get(), + base::BindLambdaForTesting([this](content::BrowserContext* context) { + return std::unique_ptr<KeyedService>(std::make_unique<VolumeManager>( + Profile::FromBrowserContext(context), nullptr, nullptr, + &disk_mount_manager_, nullptr, + VolumeManager::GetMtpStorageInfoCallback())); + })); + + storage::ExternalMountPoints::GetSystemInstance()->RegisterFileSystem( + file_manager::util::GetDownloadsMountPointName(profile_.get()), + storage::kFileSystemTypeLocal, storage::FileSystemMountOption(), + temp_dir_.GetPath()); + + file_manager::util::GetFileSystemContextForSourceURL( + profile_.get(), GURL("chrome-extension://abc")) + ->external_backend() + ->GrantFileAccessToOrigin( + url::Origin::Create(GURL("chrome-extension://abc")), + base::FilePath(file_manager::util::GetDownloadsMountPointName( + profile_.get()))); + } + + const io_task::EntryStatus CreateSuccessfulEntryStatusForFileName( + const std::string& file_name) { + const base::FilePath file_path = temp_dir_.GetPath().Append(file_name); + EXPECT_TRUE(base::WriteFile(file_path, base::RandBytesAsString(32))); + + storage::FileSystemURL url = + file_system_context_->CreateCrackedFileSystemURL( + kTestStorageKey, storage::kFileSystemTypeTest, file_path); + + return io_task::EntryStatus(std::move(url), base::File::FILE_OK); + } + + content::BrowserTaskEnvironment task_environment_; + base::ScopedTempDir temp_dir_; + std::unique_ptr<TestingProfile> profile_; + const blink::StorageKey kTestStorageKey = + blink::StorageKey::CreateFromStringForTesting("chrome-extension://abc"); + scoped_refptr<storage::FileSystemContext> file_system_context_; + file_manager::FakeDiskMountManager disk_mount_manager_; +}; + +// A matcher that matches an `extensions::Event::event_args` and attempts to +// extract the "outputs" key. It then looks at the output at `index` and matches +// the `field` against the `expected_value`. +MATCHER_P3(ExpectEventArgString, index, field, expected_value, "") { + EXPECT_EQ((*arg).type(), base::Value::Type::LIST) + << "Supplied value must be of type LIST"; + EXPECT_GE((*arg).GetList().size(), 1); + base::Value* outputs = + (*arg).GetList()[0].FindKeyOfType("outputs", base::Value::Type::LIST); + EXPECT_TRUE(outputs) << "The outputs field is not available on the event"; + EXPECT_GT((*outputs).GetList().size(), index) + << "The supplied index on outputs is not available, size: " + << (*outputs).GetList().size() << ", index: " << index; + std::string* actual_value = (*outputs).GetList()[index].FindStringKey(field); + EXPECT_TRUE(actual_value) << "Could not find the string with key: " << field; + return testing::ExplainMatchResult(expected_value, *actual_value, + result_listener); +} + +TEST_F(FileManagerEventRouterTest, OnIOTaskStatusForTrash) { + // Setup event routers. + extensions::TestEventRouter* test_event_router = + extensions::CreateAndUseTestEventRouter(profile_.get()); + TestEventRouterObserver observer(test_event_router); + auto event_router = std::make_unique<EventRouter>(profile_.get()); + event_router->ForceBroadcastingForTesting(true); + + io_task::EntryStatus source_entry = + CreateSuccessfulEntryStatusForFileName("foo.txt"); + io_task::EntryStatus output_entry = + CreateSuccessfulEntryStatusForFileName("bar.txt"); + + std::vector<io_task::EntryStatus> source_entries; + source_entries.push_back(std::move(source_entry)); + std::vector<io_task::EntryStatus> output_entries; + output_entries.push_back(std::move(output_entry)); + + // Setup the ProgressStatus event that expects + file_manager::io_task::ProgressStatus status; + status.type = file_manager::io_task::OperationType::kTrash; + status.state = file_manager::io_task::State::kSuccess; + status.sources = std::move(source_entries); + status.outputs = std::move(output_entries); + + base::RunLoop run_loop; + EXPECT_CALL( + observer, + OnBroadcastEvent(Field( + &extensions::Event::event_args, + AllOf(ExpectEventArgString(0, "fileFullPath", "/bar.txt"), + ExpectEventArgString(0, "fileSystemName", "Downloads"), + ExpectEventArgString( + 0, "fileSystemRoot", + "filesystem:chrome-extension://abc/external/Downloads/"))))) + .WillOnce(RunClosure(run_loop.QuitClosure())); + + event_router->OnIOTaskStatus(status); + run_loop.Run(); +} + +} // namespace } // namespace file_manager
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.cc index c707d57..2197db6 100644 --- a/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.cc +++ b/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.cc
@@ -41,6 +41,7 @@ #include "chrome/browser/ash/file_manager/fileapi_util.h" #include "chrome/browser/ash/file_manager/io_task.h" #include "chrome/browser/ash/file_manager/path_util.h" +#include "chrome/browser/ash/file_manager/trash_io_task.h" #include "chrome/browser/ash/file_manager/volume_manager.h" #include "chrome/browser/ash/file_manager/zip_io_task.h" #include "chrome/browser/ash/policy/dlp/dlp_files_controller.h" @@ -995,14 +996,14 @@ *entry_definition_list)))); } -FileManagerPrivateInternalGetFilesRestrictedByDlpFunction:: - FileManagerPrivateInternalGetFilesRestrictedByDlpFunction() = default; +FileManagerPrivateInternalGetDlpMetadataFunction:: + FileManagerPrivateInternalGetDlpMetadataFunction() = default; -FileManagerPrivateInternalGetFilesRestrictedByDlpFunction:: - ~FileManagerPrivateInternalGetFilesRestrictedByDlpFunction() = default; +FileManagerPrivateInternalGetDlpMetadataFunction:: + ~FileManagerPrivateInternalGetDlpMetadataFunction() = default; ExtensionFunction::ResponseAction -FileManagerPrivateInternalGetFilesRestrictedByDlpFunction::Run() { +FileManagerPrivateInternalGetDlpMetadataFunction::Run() { if (!base::FeatureList::IsEnabled( features::kDataLeakPreventionFilesRestriction)) { return RespondNow(OneArgument(base::Value(base::Value::Type::LIST))); @@ -1014,8 +1015,7 @@ return RespondNow(OneArgument(base::Value(base::Value::Type::LIST))); } - using extensions::api::file_manager_private_internal:: - GetFilesRestrictedByDlp::Params; + using extensions::api::file_manager_private_internal::GetDlpMetadata::Params; const std::unique_ptr<Params> params(Params::Create(args())); EXTENSION_FUNCTION_VALIDATE(params); @@ -1033,48 +1033,29 @@ } files_controller_ = std::make_unique<policy::DlpFilesController>(); - files_controller_->GetFilesRestrictedByAnyRule( + files_controller_->GetDlpMetadata( source_urls_, base::BindOnce( - &FileManagerPrivateInternalGetFilesRestrictedByDlpFunction:: - OnGetFilesRestrictedByDlp, + &FileManagerPrivateInternalGetDlpMetadataFunction::OnGetDlpMetadata, this)); return RespondLater(); } -void FileManagerPrivateInternalGetFilesRestrictedByDlpFunction:: - OnGetFilesRestrictedByDlp( - std::vector<storage::FileSystemURL> restricted_files) { - file_manager::util::FileDefinitionList file_definition_list; - for (const auto& file : restricted_files) { - file_manager::util::FileDefinition file_definition; - file_definition.is_directory = false; - file_definition.virtual_path = file.virtual_path(); - file_definition.absolute_path = file.path(); - file_definition_list.emplace_back(std::move(file_definition)); +void FileManagerPrivateInternalGetDlpMetadataFunction::OnGetDlpMetadata( + std::vector<policy::DlpFilesController::DlpFileMetadata> + dlp_metadata_list) { + using extensions::api::file_manager_private::DlpMetadata; + std::vector<DlpMetadata> converted_list; + for (const auto& md : dlp_metadata_list) { + DlpMetadata metadata; + metadata.is_dlp_restricted = md.is_dlp_restricted; + metadata.source_url = md.source_url; + converted_list.emplace_back(std::move(metadata)); } - - file_manager::util::ConvertFileDefinitionListToEntryDefinitionList( - file_manager::util::GetFileSystemContextForSourceURL( - Profile::FromBrowserContext(browser_context()), source_url()), - url::Origin::Create(source_url().DeprecatedGetOriginAsURL()), - file_definition_list, // Safe, since copied internally. - base::BindOnce( - &FileManagerPrivateInternalGetFilesRestrictedByDlpFunction:: - OnConvertFileDefinitionListToEntryDefinitionList, - this)); -} - -void FileManagerPrivateInternalGetFilesRestrictedByDlpFunction:: - OnConvertFileDefinitionListToEntryDefinitionList( - std::unique_ptr<file_manager::util::EntryDefinitionList> - entry_definition_list) { - DCHECK(entry_definition_list); - - Respond(OneArgument(base::Value::FromUniquePtrValue( - file_manager::util::ConvertEntryDefinitionListToListValue( - *entry_definition_list)))); + Respond(ArgumentList( + api::file_manager_private_internal::GetDlpMetadata::Results::Create( + converted_list))); } FileManagerPrivateInternalStartCopyFunction:: @@ -1655,6 +1636,15 @@ task = std::make_unique<file_manager::io_task::DeleteIOTask>( std::move(source_urls), file_system_context); break; + case file_manager::io_task::OperationType::kTrash: + if (base::FeatureList::IsEnabled(chromeos::features::kFilesTrash)) { + task = std::make_unique<file_manager::io_task::TrashIOTask>( + std::move(source_urls), profile, file_system_context, + /*base_path=*/base::FilePath()); + break; + } else { + return RespondNow(Error("Invalid operation type")); + } case file_manager::io_task::OperationType::kExtract: if (base::FeatureList::IsEnabled( chromeos::features::kFilesExtractArchive)) {
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.h b/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.h index 8a0a4d5..4149d20 100644 --- a/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.h +++ b/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.h
@@ -299,28 +299,24 @@ storage::FileSystemURL destination_url_; }; -// Implements the chrome.fileManagerPrivate.getFilesRestrictedByDlp method. -class FileManagerPrivateInternalGetFilesRestrictedByDlpFunction +// Implements the chrome.fileManagerPrivateInternal.getDlpMetadata method. +class FileManagerPrivateInternalGetDlpMetadataFunction : public LoggedExtensionFunction { public: - FileManagerPrivateInternalGetFilesRestrictedByDlpFunction(); + FileManagerPrivateInternalGetDlpMetadataFunction(); - DECLARE_EXTENSION_FUNCTION( - "fileManagerPrivateInternal.getFilesRestrictedByDlp", - FILEMANAGERPRIVATEINTERNAL_GETFILESRESTRICTEDBYDLP) + DECLARE_EXTENSION_FUNCTION("fileManagerPrivateInternal.getDlpMetadata", + FILEMANAGERPRIVATEINTERNAL_GETDLPMETADATA) protected: - ~FileManagerPrivateInternalGetFilesRestrictedByDlpFunction() override; + ~FileManagerPrivateInternalGetDlpMetadataFunction() override; // ExtensionFunction overrides. ResponseAction Run() override; private: - void OnGetFilesRestrictedByDlp( - std::vector<storage::FileSystemURL> restricted_files); - void OnConvertFileDefinitionListToEntryDefinitionList( - std::unique_ptr<file_manager::util::EntryDefinitionList> - entry_definition_list); + void OnGetDlpMetadata( + std::vector<policy::DlpFilesController::DlpFileMetadata> dlp_metadata); std::unique_ptr<policy::DlpFilesController> files_controller_; std::vector<storage::FileSystemURL> source_urls_;
diff --git a/chrome/browser/chromeos/extensions/install_limiter.h b/chrome/browser/chromeos/extensions/install_limiter.h index 2328951e..457140a 100644 --- a/chrome/browser/chromeos/extensions/install_limiter.h +++ b/chrome/browser/chromeos/extensions/install_limiter.h
@@ -20,11 +20,6 @@ namespace extensions { -// TODO(hendrich, https://crbug.com/1046302) -// Add a test for the InstallLimiter, which checks that small extensions are -// installed before large extensions and that we don't have to wait the entire -// 5s when the OnAllExternalProvidersReady() signal was called. - // InstallLimiter defers big app installs after all small app installs and then // runs big app installs one by one. This improves first-time login experience. // See http://crbug.com/166296
diff --git a/chrome/browser/chromeos/extensions/install_limiter_unittest.cc b/chrome/browser/chromeos/extensions/install_limiter_unittest.cc index 6929dfdc..421be2de 100644 --- a/chrome/browser/chromeos/extensions/install_limiter_unittest.cc +++ b/chrome/browser/chromeos/extensions/install_limiter_unittest.cc
@@ -5,34 +5,59 @@ #include "chrome/browser/chromeos/extensions/install_limiter.h" #include "ash/components/tpm/stub_install_attributes.h" +#include "base/files/file_path.h" +#include "base/files/file_util.h" +#include "base/test/task_environment.h" +#include "base/time/time.h" #include "chrome/browser/ash/login/demo_mode/demo_mode_test_helper.h" #include "chrome/browser/ash/login/demo_mode/demo_session.h" #include "chrome/browser/ash/login/users/fake_chrome_user_manager.h" +#include "chrome/browser/chrome_notification_types.h" +#include "chrome/browser/extensions/crx_installer.h" +#include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/extensions/extension_service_test_base.h" #include "components/user_manager/scoped_user_manager.h" +#include "content/public/browser/notification_service.h" #include "content/public/test/browser_task_environment.h" +#include "extensions/browser/crx_file_info.h" #include "extensions/common/constants.h" +#include "extensions/common/extension.h" +#include "extensions/common/verifier_formats.h" +#include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" using extensions::InstallLimiter; +using testing::Field; +using testing::Invoke; +using testing::Mock; namespace { constexpr char kRandomExtensionId[] = "abacabadabacabaeabacabadabacabaf"; + constexpr int kLargeExtensionSize = 2000000; constexpr int kSmallExtensionSize = 200000; +constexpr char kLargeExtensionCrx[] = "large.crx"; +constexpr char kSmallExtensionCrx[] = "small.crx"; + +constexpr base::TimeDelta kLessThanExpectedWaitTime = base::Seconds(4); +constexpr base::TimeDelta kTimeDeltaUntilExpectedWaitTime = base::Seconds(1); + } // namespace -class InstallLimiterTest +class InstallLimiterShouldDeferInstallTest : public testing::TestWithParam<ash::DemoSession::DemoModeConfig> { public: - InstallLimiterTest() + InstallLimiterShouldDeferInstallTest() : scoped_user_manager_(std::make_unique<ash::FakeChromeUserManager>()) {} - InstallLimiterTest(const InstallLimiterTest&) = delete; - InstallLimiterTest& operator=(const InstallLimiterTest&) = delete; + InstallLimiterShouldDeferInstallTest( + const InstallLimiterShouldDeferInstallTest&) = delete; + InstallLimiterShouldDeferInstallTest& operator=( + const InstallLimiterShouldDeferInstallTest&) = delete; - ~InstallLimiterTest() override = default; + ~InstallLimiterShouldDeferInstallTest() override = default; private: content::BrowserTaskEnvironment task_environment_; @@ -40,7 +65,7 @@ user_manager::ScopedUserManager scoped_user_manager_; }; -TEST_P(InstallLimiterTest, ShouldDeferInstall) { +TEST_P(InstallLimiterShouldDeferInstallTest, ShouldDeferInstall) { const std::vector<std::string> screensaver_ids = { extension_misc::kScreensaverAppId, extension_misc::kScreensaverAtlasAppId, extension_misc::kScreensaverKraneZdksAppId}; @@ -66,6 +91,179 @@ INSTANTIATE_TEST_SUITE_P( DemoModeConfig, - InstallLimiterTest, + InstallLimiterShouldDeferInstallTest, ::testing::Values(ash::DemoSession::DemoModeConfig::kNone, ash::DemoSession::DemoModeConfig::kOnline)); + +namespace extensions { + +// A mock around CrxInstaller to track extension installations. +class MockCrxInstaller : public CrxInstaller { + public: + explicit MockCrxInstaller(ExtensionService* frontend) + : CrxInstaller(frontend->AsWeakPtr(), nullptr, nullptr) {} + + MOCK_METHOD(void, InstallCrxFile, (const CRXFileInfo& source_file)); + + private: + ~MockCrxInstaller() override = default; +}; + +} // namespace extensions + +class InstallLimiterTest : public extensions::ExtensionServiceTestBase { + public: + InstallLimiterTest() + : extensions::ExtensionServiceTestBase( + std::make_unique<content::BrowserTaskEnvironment>( + base::test::TaskEnvironment::MainThreadType::IO, + content::BrowserTaskEnvironment::TimeSource::MOCK_TIME)) {} + + InstallLimiterTest(const InstallLimiterTest&) = delete; + InstallLimiterTest& operator=(const InstallLimiterTest&) = delete; + + ~InstallLimiterTest() override = default; + + void NotifyCrxInstallerDone() { + content::NotificationService::current()->Notify( + extensions::NOTIFICATION_CRX_INSTALLER_DONE, + content::Source<extensions::MockCrxInstaller>(mock_installer_.get()), + content::Details<const extensions::Extension>(NULL)); + } + + protected: + void SetUp() override { + extensions::ExtensionServiceTestBase::SetUp(); + + extensions::ExtensionServiceTestBase::ExtensionServiceInitParams params = + CreateDefaultInitParams(); + params.enable_install_limiter = true; + InitializeExtensionService(params); + + install_limiter_ = InstallLimiter::Get(profile()); + + mock_installer_ = + base::MakeRefCounted<extensions::MockCrxInstaller>(service()); + } + + extensions::CRXFileInfo CreateTestExtensionCrx(const base::FilePath& path, + int extension_size) { + const std::string data(extension_size, 0); + EXPECT_TRUE(base::WriteFile(path, data)); + extensions::CRXFileInfo crx_info(path, extensions::GetTestVerifierFormat()); + crx_info.extension_id = kRandomExtensionId; + return crx_info; + } + + InstallLimiter* install_limiter_; + scoped_refptr<extensions::MockCrxInstaller> mock_installer_; +}; + +// Test that small extensions are installed immediately. +TEST_F(InstallLimiterTest, DontDeferSmallExtensionInstallation) { + const base::FilePath path = + extensions_install_dir().AppendASCII(kSmallExtensionCrx); + extensions::CRXFileInfo crx_info_small = + CreateTestExtensionCrx(path, kSmallExtensionSize); + + EXPECT_CALL(*mock_installer_, + InstallCrxFile(Field(&extensions::CRXFileInfo::path, path))); + install_limiter_->Add(mock_installer_, crx_info_small); + task_environment()->RunUntilIdle(); + Mock::VerifyAndClearExpectations(mock_installer_.get()); +} + +// Test that large extension installations are deferred. +TEST_F(InstallLimiterTest, DeferLargeExtensionInstallation) { + const base::FilePath path = + extensions_install_dir().AppendASCII(kLargeExtensionCrx); + extensions::CRXFileInfo crx_info_large = + CreateTestExtensionCrx(path, kLargeExtensionSize); + + // Check that the large extension will not be installed immediately. + EXPECT_CALL(*mock_installer_, + InstallCrxFile(Field(&extensions::CRXFileInfo::path, path))) + .Times(0); + install_limiter_->Add(mock_installer_, crx_info_large); + task_environment()->FastForwardBy(kLessThanExpectedWaitTime); + task_environment()->RunUntilIdle(); + Mock::VerifyAndClearExpectations(mock_installer_.get()); + + // The installation starts only after the wait time is elapsed. + EXPECT_CALL(*mock_installer_, + InstallCrxFile(Field(&extensions::CRXFileInfo::path, path))); + task_environment()->FastForwardBy(kTimeDeltaUntilExpectedWaitTime); + task_environment()->RunUntilIdle(); + Mock::VerifyAndClearExpectations(mock_installer_.get()); +} + +// Test that deferred installations are run before the wait time expires if the +// OnAllExternalProvidersReady() signal was called. +TEST_F(InstallLimiterTest, RunDeferredInstallsWhenAllExternalProvidersReady) { + const base::FilePath path = + extensions_install_dir().AppendASCII(kLargeExtensionCrx); + extensions::CRXFileInfo crx_info_large = + CreateTestExtensionCrx(path, kLargeExtensionSize); + + // Check that the large extension will not be installed immediately. + EXPECT_CALL(*mock_installer_, + InstallCrxFile(Field(&extensions::CRXFileInfo::path, path))) + .Times(0); + install_limiter_->Add(mock_installer_, crx_info_large); + task_environment()->FastForwardBy(kLessThanExpectedWaitTime); + task_environment()->RunUntilIdle(); + Mock::VerifyAndClearExpectations(mock_installer_.get()); + + // The installation starts before the wait time is elapsed if + // OnAllExternalProvidersReady() is called. + EXPECT_CALL(*mock_installer_, + InstallCrxFile(Field(&extensions::CRXFileInfo::path, path))); + install_limiter_->OnAllExternalProvidersReady(); + task_environment()->RunUntilIdle(); + Mock::VerifyAndClearExpectations(mock_installer_.get()); +} + +// Test that small extensions are installed before large extensions. +TEST_F(InstallLimiterTest, InstallSmallBeforeLargeExtensions) { + // Create a large test extension crx file. + const base::FilePath crx_path_large = + extensions_install_dir().AppendASCII(kLargeExtensionCrx); + extensions::CRXFileInfo crx_info_large = + CreateTestExtensionCrx(crx_path_large, kLargeExtensionSize); + + // Create a small test extension crx file. + const base::FilePath crx_path_small = + extensions_install_dir().AppendASCII(kSmallExtensionCrx); + extensions::CRXFileInfo crx_info_small = + CreateTestExtensionCrx(crx_path_small, kSmallExtensionSize); + + base::RunLoop run_loop; + + // When adding a large extension and then a small extension, the small + // extension will be installed first. The mock function call will trigger a + // CRX_INSTALLER_DONE notification which will notify the install limiter to + // continue with any deferred installations. This will then start the + // installation of the large extension. + { + testing::InSequence s; + + EXPECT_CALL( + *mock_installer_, + InstallCrxFile(Field(&extensions::CRXFileInfo::path, crx_path_small))) + .WillOnce(Invoke(this, &InstallLimiterTest::NotifyCrxInstallerDone)); + EXPECT_CALL( + *mock_installer_, + InstallCrxFile(Field(&extensions::CRXFileInfo::path, crx_path_large))) + .WillOnce(Invoke(&run_loop, &base::RunLoop::Quit)); + } + + install_limiter_->Add(mock_installer_, crx_info_large); + // Ensure that AddWithSize() is called for the large extension before also + // adding the small extension. + task_environment()->RunUntilIdle(); + install_limiter_->Add(mock_installer_, crx_info_small); + + run_loop.Run(); + + Mock::VerifyAndClearExpectations(mock_installer_.get()); +}
diff --git a/chrome/browser/extensions/crx_installer.h b/chrome/browser/extensions/crx_installer.h index 608e0d9..5a50106 100644 --- a/chrome/browser/extensions/crx_installer.h +++ b/chrome/browser/extensions/crx_installer.h
@@ -44,6 +44,7 @@ class ExtensionService; class ExtensionUpdaterTest; enum class InstallationStage; +class MockCrxInstaller; class PreloadCheckGroup; // This class installs a crx file into a profile. @@ -119,7 +120,7 @@ void InstallCrx(const base::FilePath& source_file); // Install the crx in |source_file|. - void InstallCrxFile(const CRXFileInfo& source_file); + virtual void InstallCrxFile(const CRXFileInfo& source_file); // Install the unpacked crx in |unpacked_dir|. // If |delete_source_| is true, |unpacked_dir| will be removed at the end of @@ -262,6 +263,7 @@ friend class ::ExtensionServiceTest; friend class BookmarkAppInstallFinalizerTest; friend class ExtensionUpdaterTest; + friend class MockCrxInstaller; CrxInstaller(base::WeakPtr<ExtensionService> service_weak, std::unique_ptr<ExtensionInstallPrompt> client,
diff --git a/chrome/browser/extensions/extension_service_test_base.cc b/chrome/browser/extensions/extension_service_test_base.cc index c10561b..2276c5d 100644 --- a/chrome/browser/extensions/extension_service_test_base.cc +++ b/chrome/browser/extensions/extension_service_test_base.cc
@@ -412,7 +412,8 @@ service_->shared_module_service()); #if BUILDFLAG(IS_CHROMEOS_ASH) - InstallLimiter::Get(profile())->DisableForTest(); + if (!params.enable_install_limiter) + InstallLimiter::Get(profile())->DisableForTest(); #endif }
diff --git a/chrome/browser/extensions/extension_service_test_base.h b/chrome/browser/extensions/extension_service_test_base.h index ff00127..0e29bec 100644 --- a/chrome/browser/extensions/extension_service_test_base.h +++ b/chrome/browser/extensions/extension_service_test_base.h
@@ -70,6 +70,7 @@ bool profile_is_supervised = false; bool profile_is_guest = false; bool enable_bookmark_model = false; + bool enable_install_limiter = false; raw_ptr<policy::PolicyService> policy_service = nullptr;
diff --git a/chrome/browser/first_run/first_run.cc b/chrome/browser/first_run/first_run.cc index ac23c38..8f73f74e 100644 --- a/chrome/browser/first_run/first_run.cc +++ b/chrome/browser/first_run/first_run.cc
@@ -68,7 +68,6 @@ // Flags for functions of similar name. bool g_should_show_welcome_page = false; -bool g_should_do_autofill_personal_data_manager_first_run = false; // Indicates whether this is first run. Populated when IsChromeFirstRun // is invoked, then used as a cache on subsequent calls. @@ -378,16 +377,6 @@ GURL(chrome::kChromeUIWelcomeURL); } -void SetShouldDoPersonalDataManagerFirstRun() { - g_should_do_autofill_personal_data_manager_first_run = true; -} - -bool ShouldDoPersonalDataManagerFirstRun() { - bool retval = g_should_do_autofill_personal_data_manager_first_run; - g_should_do_autofill_personal_data_manager_first_run = false; - return retval; -} - void SetInitialPrefsPathForTesting(const base::FilePath& initial_prefs) { GetInitialPrefsPathForTesting() = initial_prefs; } @@ -504,7 +493,6 @@ ProcessDefaultBrowserPolicy(make_chrome_default_for_user); SetShouldShowWelcomePage(); - SetShouldDoPersonalDataManagerFirstRun(); internal::DoPostImportPlatformSpecificTasks(profile); }
diff --git a/chrome/browser/first_run/first_run.h b/chrome/browser/first_run/first_run.h index 97800b7..8984ee5 100644 --- a/chrome/browser/first_run/first_run.h +++ b/chrome/browser/first_run/first_run.h
@@ -122,18 +122,6 @@ // Returns true if |contents| hosts one of the welcome pages. bool IsOnWelcomePage(content::WebContents* contents); -// Sets a flag that will cause ShouldDoPersonalDataManagerFirstRun() -// to return true exactly once, so that the browser loads -// PersonalDataManager once the main message loop gets going. -void SetShouldDoPersonalDataManagerFirstRun(); - -// Returns true if the autofill personal data manager first-run action -// should be taken. -// -// This will return true only once, the first time it is called after -// SetShouldDoPersonalDataManagerFirstRun() is called. -bool ShouldDoPersonalDataManagerFirstRun(); - // Automatically imports items requested by |profile|'s configuration (sum of // policies and initial prefs). Also imports bookmarks from file if // |import_bookmarks_path| is not empty.
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index ce8e511c..aac03935 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -1035,8 +1035,8 @@ }, { "name": "crostini-ime-support", - "owners": [ "timloh", "davidmunro@google.com" ], - "expiry_milestone": 104 + "owners": [ "timloh", "sophialin@google.com" ], + "expiry_milestone": 111 }, { "name": "crostini-multi-container", @@ -1055,8 +1055,8 @@ }, { "name": "crostini-virtual-keyboard-support", - "owners": [ "timloh", "davidmunro@google.com" ], - "expiry_milestone": 104 + "owners": [ "timloh", "sophialin@google.com" ], + "expiry_milestone": 111 }, { "name": "cryptauth-v2-dedup-device-last-activity-time", @@ -1750,11 +1750,6 @@ "expiry_milestone": 97 }, { - "name": "enable-cros-language-settings-update-2", - "owners": [ "cros-borders@google.com" ], - "expiry_milestone": 100 - }, - { "name": "enable-cros-language-settings-update-japanese", "owners": [ "keithlee", "essential-inputs-team@google.com" ], "expiry_milestone": 110
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index 67dad774..3d079ca 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -4474,11 +4474,6 @@ "When enabled, crosh (ChromeOS Shell) will run as a tabbed System Web App " "rather than a normal browser tab."; -const char kCrosLanguageSettingsUpdate2Name[] = "Language Settings Update 2"; -const char kCrosLanguageSettingsUpdate2Description[] = - "Enables the second language settings update. Requires " - "#enable-cros-language-settings-update to be enabled."; - const char kCrosLanguageSettingsUpdateJapaneseName[] = "Language Settings Update Japanese"; const char kCrosLanguageSettingsUpdateJapaneseDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index 4cf9dcbeb..c9947d8 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -2560,9 +2560,6 @@ extern const char kCroshSWAName[]; extern const char kCroshSWADescription[]; -extern const char kCrosLanguageSettingsUpdate2Name[]; -extern const char kCrosLanguageSettingsUpdate2Description[]; - extern const char kCrosLanguageSettingsUpdateJapaneseName[]; extern const char kCrosLanguageSettingsUpdateJapaneseDescription[];
diff --git a/chrome/browser/lacros/browser_service_lacros.cc b/chrome/browser/lacros/browser_service_lacros.cc index 79e90f0..a10501a 100644 --- a/chrome/browser/lacros/browser_service_lacros.cc +++ b/chrome/browser/lacros/browser_service_lacros.cc
@@ -258,6 +258,15 @@ void BrowserServiceLacros::NewTab(bool should_trigger_session_restore, NewTabCallback callback) { + if (ProfilePicker::ShouldShowAtLaunch() && + chrome::GetTotalBrowserCount() == 0) { + // The first browser window will trigger session restore if needed. + ProfilePicker::Show(ProfilePicker::Params::FromEntryPoint( + ProfilePicker::EntryPoint::kNewSessionOnExistingProcess)); + std::move(callback).Run(); + return; + } + LoadMainProfile( base::BindOnce(&BrowserServiceLacros::NewTabWithProfile, weak_ptr_factory_.GetWeakPtr(),
diff --git a/chrome/browser/lacros/browser_service_lacros_browsertest.cc b/chrome/browser/lacros/browser_service_lacros_browsertest.cc index f763c8e..25286dd6 100644 --- a/chrome/browser/lacros/browser_service_lacros_browsertest.cc +++ b/chrome/browser/lacros/browser_service_lacros_browsertest.cc
@@ -9,6 +9,7 @@ #include "chrome/browser/chromeos/app_mode/app_session.h" #include "chrome/browser/lacros/app_mode/kiosk_session_service_lacros.h" #include "chrome/browser/lacros/browser_service_lacros.h" +#include "chrome/browser/lifetime/application_lifetime.h" #include "chrome/browser/prefs/incognito_mode_prefs.h" #include "chrome/browser/prefs/session_startup_pref.h" #include "chrome/browser/profiles/keep_alive/profile_keep_alive_types.h" @@ -111,6 +112,20 @@ EXPECT_EQ(web_content->GetVisibleURL(), kNavigationUrl); } + void NewWindowSync(bool incognito, bool should_trigger_session_restore) { + base::RunLoop run_loop; + browser_service()->NewWindow(incognito, should_trigger_session_restore, + run_loop.QuitClosure()); + run_loop.Run(); + } + + void NewTabSync(bool should_trigger_session_restore) { + base::RunLoop run_loop; + browser_service()->NewTab(should_trigger_session_restore, + run_loop.QuitClosure()); + run_loop.Run(); + } + BrowserServiceLacros* browser_service() const { return browser_service_.get(); } @@ -156,37 +171,87 @@ base::FilePath path_profile2 = profile_manager->user_data_dir().Append(FILE_PATH_LITERAL("Profile 2")); - base::RunLoop run_loop; - Profile* profile2; - profile_manager->CreateProfileAsync( - path_profile2, base::BindLambdaForTesting( - [&](Profile* profile, Profile::CreateStatus status) { - if (status == Profile::CREATE_STATUS_INITIALIZED) { - profile2 = profile; - run_loop.Quit(); - } - })); - run_loop.Run(); + Profile* profile2 = + profiles::testing::CreateProfileSync(profile_manager, path_profile2); // Open a browser window to make it the last used profile. chrome::NewEmptyWindow(profile2); ui_test_utils::WaitForBrowserToOpen(); // Profile picker does _not_ open for incognito windows. Instead, the // incognito window for the last used profile is directly opened. - base::RunLoop run_loop2; - browser_service()->NewWindow( - /*incognito=*/true, /*should_trigger_session_restore=*/false, - /*callback=*/base::BindLambdaForTesting([&]() { run_loop2.Quit(); })); - run_loop2.Run(); + NewWindowSync(/*incognito=*/true, /*should_trigger_session_restore=*/false); EXPECT_FALSE(ProfilePicker::IsOpen()); Profile* profile = BrowserList::GetInstance()->GetLastActive()->profile(); // Main profile should be always used. EXPECT_EQ(profile->GetPath(), main_profile->GetPath()); EXPECT_TRUE(profile->IsOffTheRecord()); - browser_service()->NewWindow( - /*incognito=*/false, /*should_trigger_session_restore=*/false, - /*callback=*/base::BindLambdaForTesting([]() {})); + NewWindowSync(/*incognito=*/false, /*should_trigger_session_restore=*/false); + EXPECT_TRUE(ProfilePicker::IsOpen()); +} + +IN_PROC_BROWSER_TEST_F(BrowserServiceLacrosBrowserTest, + NewTab_OpensProfilePicker_SingleProfile) { + // Keep the browser process running during the test while the browser is + // closed. + ScopedKeepAlive keep_alive(KeepAliveOrigin::BROWSER, + KeepAliveRestartOption::DISABLED); + // Start in a state with no browser windows opened. + CloseBrowserSynchronously(browser()); + EXPECT_EQ(0u, chrome::GetTotalBrowserCount()); + + // `NewTab()` should create a new window if the system has only one + // profile. + NewTabSync(/*should_trigger_session_restore=*/true); + ui_test_utils::WaitForBrowserToOpen(); + EXPECT_EQ(1u, chrome::GetTotalBrowserCount()); + EXPECT_FALSE(ProfilePicker::IsOpen()); + ProfileManager* profile_manager = g_browser_process->profile_manager(); + auto* main_profile = profile_manager->GetProfileByPath( + profile_manager->GetPrimaryUserProfilePath()); + auto* browser = chrome::FindBrowserWithProfile(main_profile); + auto* tab_strip = browser->tab_strip_model(); + EXPECT_EQ(1, tab_strip->count()); + + // Consequent `NewTab()` should add a new tab to an existing browser. + NewTabSync(/*should_trigger_session_restore=*/true); + EXPECT_EQ(2, tab_strip->count()); + EXPECT_FALSE(ProfilePicker::IsOpen()); +} + +IN_PROC_BROWSER_TEST_F(BrowserServiceLacrosBrowserTest, + NewTab_OpensProfilePicker_MultiProfile) { + // Keep the browser process running during the test while the browser is + // closed. + ScopedKeepAlive keep_alive(KeepAliveOrigin::BROWSER, + KeepAliveRestartOption::DISABLED); + + // Create and open an additional profile to move Chrome to the multi-profile + // mode. + ProfileManager* profile_manager = g_browser_process->profile_manager(); + base::FilePath profile2_path = + profile_manager->user_data_dir().Append(FILE_PATH_LITERAL("Profile 2")); + Profile* profile2 = + profiles::testing::CreateProfileSync(profile_manager, profile2_path); + chrome::NewEmptyWindow(profile2); + ui_test_utils::WaitForBrowserToOpen(); + EXPECT_EQ(2u, chrome::GetTotalBrowserCount()); + auto* tab_strip = browser()->tab_strip_model(); + EXPECT_EQ(1, tab_strip->count()); + + // `NewTab()` should add a tab to the main profile window; + NewTabSync(/*should_trigger_session_restore=*/true); + EXPECT_EQ(2, tab_strip->count()); + + chrome::CloseAllBrowsers(); + // Wait for two browsers to be closed. + ui_test_utils::WaitForBrowserToClose(); + ui_test_utils::WaitForBrowserToClose(); + EXPECT_EQ(0u, chrome::GetTotalBrowserCount()); + + // `NewTab()` should open the profile picker. + NewTabSync(/*should_trigger_session_restore=*/true); + EXPECT_EQ(0u, chrome::GetTotalBrowserCount()); EXPECT_TRUE(ProfilePicker::IsOpen()); } @@ -232,11 +297,7 @@ // Opening a new window should suppress the profile picker and the crash // restore bubble should be showing. - base::RunLoop run_loop; - browser_service()->NewWindow( - /*incognito=*/false, /*should_trigger_session_restore=*/true, - /*callback=*/base::BindLambdaForTesting([&]() { run_loop.Quit(); })); - run_loop.Run(); + NewWindowSync(/*incognito=*/false, /*should_trigger_session_restore=*/true); EXPECT_FALSE(ProfilePicker::IsOpen()); views::BubbleDialogDelegate* crash_bubble_delegate = @@ -431,9 +492,7 @@ // Trigger a new tab with session restore. base::RunLoop run_loop; testing::SessionsRestoredWaiter restore_waiter(run_loop.QuitClosure(), 1); - browser_service()->NewTab( - /*should_trigger_session_restore=*/true, - /*callback=*/base::DoNothing()); + NewTabSync(/*should_trigger_session_restore=*/true); run_loop.Run(); EXPECT_EQ(1u, BrowserList::GetInstance()->size()); @@ -449,11 +508,7 @@ // A second call to NewTab() ignores session restore and adds a new tab to // the existing browser. - base::RunLoop run_loop2; - browser_service()->NewTab( - /*should_trigger_session_restore=*/true, - /*callback=*/run_loop2.QuitClosure()); - run_loop2.Run(); + NewTabSync(/*should_trigger_session_restore=*/true); EXPECT_EQ(1u, BrowserList::GetInstance()->size()); ASSERT_EQ(3, new_tab_strip->count()); @@ -471,11 +526,7 @@ IncognitoModePrefs::SetAvailability( main_profile->GetPrefs(), IncognitoModePrefs::Availability::kDisabled); // Request a new incognito window. - base::RunLoop run_loop; - browser_service()->NewWindow( - /*incognito=*/true, /*should_trigger_session_restore=*/false, - /*callback=*/base::BindLambdaForTesting([&]() { run_loop.Quit(); })); - run_loop.Run(); + NewWindowSync(/*incognito=*/true, /*should_trigger_session_restore=*/false); // A regular window opens instead. EXPECT_FALSE(ProfilePicker::IsOpen()); Profile* profile = BrowserList::GetInstance()->GetLastActive()->profile();
diff --git a/chrome/browser/net/network_context_configuration_browsertest.cc b/chrome/browser/net/network_context_configuration_browsertest.cc index dbcccc4..7b2f03b 100644 --- a/chrome/browser/net/network_context_configuration_browsertest.cc +++ b/chrome/browser/net/network_context_configuration_browsertest.cc
@@ -1451,7 +1451,9 @@ EXPECT_FALSE(GetCookies(embedded_test_server()->base_url()).empty()); } -IN_PROC_BROWSER_TEST_P(NetworkContextConfigurationBrowserTest, CookiesEnabled) { +// Disabled due to flakiness. See https://crbug.com/1273903. +IN_PROC_BROWSER_TEST_P(NetworkContextConfigurationBrowserTest, + DISABLED_CookiesEnabled) { if (IsRestartStateWithInProcessNetworkService()) return; // Check that the cookie from the first stage of the test was / was not
diff --git a/chrome/browser/notifications/BUILD.gn b/chrome/browser/notifications/BUILD.gn index dc8457ee..1af211e 100644 --- a/chrome/browser/notifications/BUILD.gn +++ b/chrome/browser/notifications/BUILD.gn
@@ -103,9 +103,12 @@ testonly = true sources = [ + "android/java/src/org/chromium/chrome/browser/notifications/NotificationBuilderBaseTest.java", "android/java/src/org/chromium/chrome/browser/notifications/NotificationIntentInterceptorTest.java", "android/java/src/org/chromium/chrome/browser/notifications/NotificationSystemStatusUtilUnitTest.java", + "android/java/src/org/chromium/chrome/browser/notifications/NotificationTestUtil.java", "android/java/src/org/chromium/chrome/browser/notifications/PendingIntentProviderTest.java", + "android/java/src/org/chromium/chrome/browser/notifications/StandardNotificationBuilderTest.java", "android/java/src/org/chromium/chrome/browser/notifications/ThrottlingNotificationSchedulerTest.java", "android/java/src/org/chromium/chrome/browser/notifications/channels/ChromeChannelDefinitionsTest.java", "android/java/src/org/chromium/chrome/browser/notifications/permissions/NotificationPermissionChangeReceiverTest.java", @@ -123,8 +126,10 @@ "//chrome/browser/preferences:java", "//chrome/test/android:chrome_java_unit_test_support", "//components/browser_ui/notifications/android:java", + "//components/embedder_support/android:junit_test_support", "//third_party/android_deps:espresso_java", "//third_party/android_deps:robolectric_all_java", + "//third_party/androidx:androidx_annotation_annotation_java", "//third_party/androidx:androidx_test_core_java", "//third_party/androidx:androidx_test_core_java", "//third_party/androidx:androidx_test_ext_junit_java", @@ -142,10 +147,8 @@ sources = [ "android/java/src/org/chromium/chrome/browser/notifications/CustomNotificationBuilderTest.java", - "android/java/src/org/chromium/chrome/browser/notifications/NotificationBuilderBaseTest.java", "android/java/src/org/chromium/chrome/browser/notifications/NotificationTestUtil.java", "android/java/src/org/chromium/chrome/browser/notifications/NotificationWrapperBuilderFactoryTest.java", - "android/java/src/org/chromium/chrome/browser/notifications/StandardNotificationBuilderTest.java", "android/java/src/org/chromium/chrome/browser/notifications/channels/ChannelsInitializerTest.java", "android/java/src/org/chromium/chrome/browser/notifications/channels/ChannelsUpdaterTest.java", ]
diff --git a/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/NotificationBuilderBaseTest.java b/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/NotificationBuilderBaseTest.java index 7c1751f9..2cd2385 100644 --- a/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/NotificationBuilderBaseTest.java +++ b/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/NotificationBuilderBaseTest.java
@@ -7,40 +7,46 @@ import android.content.Context; import android.content.res.Resources; import android.graphics.Bitmap; -import android.support.test.InstrumentationRegistry; -import androidx.test.filters.MediumTest; - +import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; -import org.chromium.base.test.BaseJUnit4ClassRunner; -import org.chromium.base.test.util.Batch; +import org.chromium.base.test.BaseRobolectricTestRunner; import org.chromium.base.test.util.Feature; import org.chromium.chrome.browser.notifications.channels.ChromeChannelDefinitions; import org.chromium.components.browser_ui.notifications.NotificationMetadata; import org.chromium.components.browser_ui.notifications.NotificationWrapper; import org.chromium.components.browser_ui.widget.RoundedIconGenerator; +import org.chromium.components.embedder_support.util.ShadowUrlUtilities; import org.chromium.components.embedder_support.util.UrlUtilities; -import org.chromium.content_public.browser.test.NativeLibraryTestUtils; /** - * Instrumentation unit tests for NotificationBuilderBase. + * Unit tests for NotificationBuilderBase. * - * Extends NativeLibraryTestBase so that {@link UrlUtilities#getDomainAndRegistry} can access - * native GetDomainAndRegistry, when called by {@link RoundedIconGenerator#getIconTextForUrl} - * during testEnsureNormalizedIconBehavior(). + * Uses ShadowUrlUtilities so that we can mock out {@link UrlUtilities#getDomainAndRegistry} called + * by {@link RoundedIconGenerator#getIconTextForUrl} during testEnsureNormalizedIconBehavior(). */ -@RunWith(BaseJUnit4ClassRunner.class) -@Batch(Batch.UNIT_TESTS) +@RunWith(BaseRobolectricTestRunner.class) +@Config(manifest = Config.NONE, shadows = {ShadowUrlUtilities.class}) public class NotificationBuilderBaseTest { @Before public void setUp() { - // Not initializing the browser process is safe because GetDomainAndRegistry() is - // stand-alone. - NativeLibraryTestUtils.loadNativeLibraryNoBrowserProcess(); + ShadowUrlUtilities.setTestImpl(new ShadowUrlUtilities.TestImpl() { + @Override + public String getDomainAndRegistry(String uri, boolean includePrivateRegistries) { + return uri; + } + }); + } + + @After + public void tearDown() { + ShadowUrlUtilities.reset(); } /** @@ -50,13 +56,10 @@ * (3) Smaller bitmaps should be left alone. */ @Test - @MediumTest @Feature({"Browser", "Notifications"}) public void testEnsureNormalizedIconBehavior() { // Get the dimensions of the notification icon that will be presented to the user. - Context appContext = InstrumentationRegistry.getInstrumentation() - .getTargetContext() - .getApplicationContext(); + Context appContext = RuntimeEnvironment.getApplication(); Resources resources = appContext.getResources(); int largeIconWidthPx =
diff --git a/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/StandardNotificationBuilderTest.java b/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/StandardNotificationBuilderTest.java index 1c9abe0..0b84088e 100644 --- a/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/StandardNotificationBuilderTest.java +++ b/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/StandardNotificationBuilderTest.java
@@ -15,46 +15,47 @@ import android.graphics.BitmapFactory; import android.graphics.Color; import android.os.Build; -import android.support.test.InstrumentationRegistry; import android.text.SpannableStringBuilder; -import androidx.test.filters.SmallTest; - +import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; -import org.chromium.base.test.BaseJUnit4ClassRunner; -import org.chromium.base.test.util.Batch; +import org.chromium.base.test.BaseRobolectricTestRunner; import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.MinAndroidSdkLevel; import org.chromium.chrome.R; import org.chromium.chrome.browser.notifications.channels.ChromeChannelDefinitions; import org.chromium.components.browser_ui.notifications.NotificationMetadata; import org.chromium.components.browser_ui.notifications.PendingIntentProvider; -import org.chromium.components.browser_ui.widget.RoundedIconGenerator; -import org.chromium.components.embedder_support.util.UrlUtilities; -import org.chromium.content_public.browser.test.NativeLibraryTestUtils; +import org.chromium.components.embedder_support.util.ShadowUrlUtilities; /** - * Instrumentation unit tests for StandardNotificationBuilder. - * - * Extends NativeLibraryTestBase so that {@link UrlUtilities#getDomainAndRegistry} can access - * native GetDomainAndRegistry, when called by {@link RoundedIconGenerator#getIconTextForUrl} - * during notification construction. + * Robolectric unit tests for StandardNotificationBuilder. */ -@RunWith(BaseJUnit4ClassRunner.class) -@Batch(Batch.UNIT_TESTS) +@RunWith(BaseRobolectricTestRunner.class) +@Config(manifest = Config.NONE, shadows = {ShadowUrlUtilities.class}) public class StandardNotificationBuilderTest { private static final String NOTIFICATION_TAG = "TestNotificationTag"; private static final int NOTIFICATION_ID = 99; @Before public void setUp() { - // Not initializing the browser process is safe because GetDomainAndRegistry() is - // stand-alone. - NativeLibraryTestUtils.loadNativeLibraryNoBrowserProcess(); + ShadowUrlUtilities.setTestImpl(new ShadowUrlUtilities.TestImpl() { + @Override + public String getDomainAndRegistry(String uri, boolean includePrivateRegistries) { + return uri; + } + }); + } + + @After + public void tearDown() { + ShadowUrlUtilities.reset(); } private NotificationBuilderBase createAllOptionsBuilder( @@ -63,7 +64,7 @@ throw new IllegalArgumentException(); } - Context context = InstrumentationRegistry.getTargetContext(); + Context context = RuntimeEnvironment.getApplication(); outContentAndDeleteIntents[0] = createIntent(context, "content"); outContentAndDeleteIntents[1] = createIntent(context, "delete"); @@ -105,7 +106,6 @@ } @Test - @SmallTest @Feature({"Browser", "Notifications"}) public void testSetAll() { PendingIntentProvider[] contentAndDeleteIntents = new PendingIntentProvider[2]; @@ -124,7 +124,7 @@ Assert.assertNotNull(picture); Assert.assertTrue(picture.getWidth() > 0 && picture.getHeight() > 0); - Context context = InstrumentationRegistry.getTargetContext(); + Context context = RuntimeEnvironment.getApplication(); Bitmap smallIcon = BitmapFactory.decodeResource(context.getResources(), R.drawable.ic_chrome); Assert.assertTrue(smallIcon.sameAs( @@ -161,7 +161,6 @@ } @Test - @SmallTest @Feature({"Browser", "Notifications"}) public void testBigTextStyle() { PendingIntentProvider[] contentAndDeleteIntents = new PendingIntentProvider[2]; @@ -173,10 +172,9 @@ } @Test - @SmallTest @Feature({"Browser", "Notifications"}) public void testSetSmallIcon() { - Context context = InstrumentationRegistry.getTargetContext(); + Context context = RuntimeEnvironment.getApplication(); NotificationBuilderBase notificationBuilder = new StandardNotificationBuilder(context); Bitmap bitmap = @@ -217,10 +215,9 @@ */ @Test @MinAndroidSdkLevel(Build.VERSION_CODES.M) - @SmallTest @Feature({"Browser", "Notifications"}) public void testRenotifyWithCustomBadgeDoesNotCrash() { - Context context = InstrumentationRegistry.getTargetContext(); + Context context = RuntimeEnvironment.getApplication(); NotificationBuilderBase builder = new StandardNotificationBuilder(context) @@ -245,10 +242,9 @@ } @Test - @SmallTest @Feature({"Browser", "Notifications"}) public void testAddTextActionSetsRemoteInput() { - Context context = InstrumentationRegistry.getTargetContext(); + Context context = RuntimeEnvironment.getApplication(); NotificationBuilderBase notificationBuilder = new StandardNotificationBuilder(context) .setChannelId(ChromeChannelDefinitions.ChannelId.SITES)
diff --git a/chrome/browser/prefetch/search_prefetch/base_search_prefetch_request.cc b/chrome/browser/prefetch/search_prefetch/base_search_prefetch_request.cc index 16d8ca9..10b14eb 100644 --- a/chrome/browser/prefetch/search_prefetch/base_search_prefetch_request.cc +++ b/chrome/browser/prefetch/search_prefetch/base_search_prefetch_request.cc
@@ -6,10 +6,12 @@ #include <vector> +#include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" #include "base/trace_event/base_tracing.h" #include "build/build_config.h" #include "chrome/browser/prefetch/prefetch_headers.h" +#include "chrome/browser/prerender/prerender_manager.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/search_engines/template_url_service_factory.h" #include "chrome/common/pref_names.h" @@ -106,10 +108,12 @@ } // namespace BaseSearchPrefetchRequest::BaseSearchPrefetchRequest( + const std::u16string& prefetch_search_terms, const GURL& prefetch_url, bool navigation_prefetch, base::OnceCallback<void(bool)> report_error_callback) - : prefetch_url_(prefetch_url), + : prefetch_search_terms_(prefetch_search_terms), + prefetch_url_(prefetch_url), navigation_prefetch_(navigation_prefetch), report_error_callback_(std::move(report_error_callback)) {} @@ -234,12 +238,6 @@ auto* default_search = template_url_service->GetDefaultSearchProvider(); DCHECK(default_search); - std::u16string prefetch_url_search_terms; - - default_search->ExtractSearchTermsFromURL( - prefetch_url_, template_url_service->search_terms_data(), - &prefetch_url_search_terms); - bool should_defer = false; { TRACE_EVENT0( @@ -269,7 +267,7 @@ resource_request->url, template_url_service->search_terms_data(), &new_url_search_terms); - if (should_defer || new_url_search_terms != prefetch_url_search_terms || + if (should_defer || new_url_search_terms != prefetch_search_terms_ || cancel_or_pause_delegate.cancelled_or_paused()) { return false; } @@ -291,6 +289,50 @@ current_status_ == SearchPrefetchStatus::kCanBeServed); current_status_ = SearchPrefetchStatus::kRequestCancelled; StopPrefetch(); + StopPrerender(); +} + +void BaseSearchPrefetchRequest::MaybeStartPrerenderSearchResult( + PrerenderManager& prerender_manager) { + // Prerendering is supposed to be requested after prefetch received a servable + // response and take over the prefetched main resource response. When + // prerendering is requested while prefetching is still running, it has to + // wait until the completion of that. This procedure depends on the progress + // of prefetching as follows: + // *1 | *2 | *3 | *4 + // prefetch started received prerender started + + switch (current_status_) { + case SearchPrefetchStatus::kNotStarted: + // Case1: This request has been canceled before it starts sending network + // requests (see `StartPrefetchRequest`), so prerender should not be + // triggered. + return; + case SearchPrefetchStatus::kInFlight: + case SearchPrefetchStatus::kCanBeServed: + case SearchPrefetchStatus::kCanBeServedAndUserClicked: + case SearchPrefetchStatus::kComplete: + break; + case SearchPrefetchStatus::kRequestCancelled: + case SearchPrefetchStatus::kRequestFailed: + // Case N: The prefetch request failed, or has failed. Prerender cannot + // reuse the response and will fail for sure, so this does not start + // prerendering. + return; + case SearchPrefetchStatus::kServed: + NOTREACHED(); + } + + if (servable_response_code_received_) { + // Case 3, 4: This can start prerendering because it has received a + // response. + prerender_manager.StartPrerenderSearchResult(prefetch_search_terms_, + prefetch_url_); + } else { + // Case 2: this will start prerendering after it receives a + // servable response. + prerender_manager_ = prerender_manager.GetWeakPtr(); + } } void BaseSearchPrefetchRequest::ErrorEncountered() { @@ -301,11 +343,23 @@ StopPrefetch(); } +void BaseSearchPrefetchRequest::OnServableResponseCodeReceived() { + servable_response_code_received_ = true; + if (prerender_manager_) { + prerender_manager_->StartPrerenderSearchResult(prefetch_search_terms_, + prefetch_url_); + } +} + void BaseSearchPrefetchRequest::MarkPrefetchAsServable() { DCHECK(current_status_ == SearchPrefetchStatus::kInFlight); current_status_ = SearchPrefetchStatus::kCanBeServed; } +void BaseSearchPrefetchRequest::ResetPrerenderUpgrader() { + prerender_manager_ = nullptr; +} + void BaseSearchPrefetchRequest::MarkPrefetchAsComplete() { DCHECK(current_status_ == SearchPrefetchStatus::kInFlight || current_status_ == SearchPrefetchStatus::kCanBeServed || @@ -329,3 +383,10 @@ void BaseSearchPrefetchRequest::RecordClickTime() { time_clicked_ = base::TimeTicks::Now(); } + +void BaseSearchPrefetchRequest::StopPrerender() { + if (prerender_manager_) { + prerender_manager_->StopPrerenderSearchResult(prefetch_search_terms_); + prerender_manager_ = nullptr; + } +}
diff --git a/chrome/browser/prefetch/search_prefetch/base_search_prefetch_request.h b/chrome/browser/prefetch/search_prefetch/base_search_prefetch_request.h index f281a70..c38f13c 100644 --- a/chrome/browser/prefetch/search_prefetch/base_search_prefetch_request.h +++ b/chrome/browser/prefetch/search_prefetch/base_search_prefetch_request.h
@@ -12,6 +12,7 @@ #include "services/network/public/cpp/resource_request.h" #include "url/gurl.h" +class PrerenderManager; class Profile; class SearchPrefetchURLLoader; @@ -46,11 +47,17 @@ }; // A class representing a prefetch used by the Search Prefetch Service. +// It plays the following roles to support search preloading. +// - Preparing a resource request to prefetch a search terms. +// - Starting prerendering upon the request succeeding to upgrade prefetch to +// prerender after the Search Prefetch Service tells it that the prefetched +// term is prerenderable. // Implementors should provide the fetch and storage functionality as well as // updating |current_status_|. class BaseSearchPrefetchRequest { public: BaseSearchPrefetchRequest( + const std::u16string& prefetch_search_terms, const GURL& prefetch_url, bool navigation_prefetch, base::OnceCallback<void(bool)> report_error_callback); @@ -72,12 +79,19 @@ // Marks a prefetch as canceled and stops any ongoing fetch. void CancelPrefetch(); + // Called when SearchPrefetchService receives the hint that this prefetch + // request can be upgraded to a prerender attempt. + void MaybeStartPrerenderSearchResult(PrerenderManager& prerender_manager); + // Called when the prefetch encounters an error. void ErrorEncountered(); // Called when the prefetch encounters an error. void ErrorEncounteredUsingFallback(); + // Called on the URL loader receives servable response. + void OnServableResponseCodeReceived(); + // Update the status when the request is serveable. void MarkPrefetchAsServable(); @@ -91,6 +105,11 @@ // stack. void MarkPrefetchAsServed(); + // Called when AutocompleteMatches changes. It resets PrerenderUpgrader. + // And if the AutocompleteMatches suggests to prerender a search result, + // `MaybeStartPrerenderSearchResult` will be called soon. + void ResetPrerenderUpgrader(); + // Record the time at which the user clicked a suggestion matching this // prefetch. void RecordClickTime(); @@ -119,8 +138,16 @@ TakeSearchPrefetchURLLoader() = 0; protected: + // Whether the request has received a servable response. See + // `CanServePrefetchRequest` in ./streaming_search_prefetch_url_loader.cc for + // the definition of servable response. + bool servable_response_code_received_ = false; + SearchPrefetchStatus current_status_ = SearchPrefetchStatus::kNotStarted; + // The search terms that this request is prefetching. + const std::u16string prefetch_search_terms_; + // The URL to prefetch the search terms from. GURL prefetch_url_; @@ -132,6 +159,14 @@ // The time at which the prefetched URL was clicked in the Omnibox. base::TimeTicks time_clicked_; + + // Once set, this request will trigger search prerender upon receiving success + // response. + base::WeakPtr<PrerenderManager> prerender_manager_; + + private: + // Cancels ongoing and pending prerender. + void StopPrerender(); }; #endif // CHROME_BROWSER_PREFETCH_SEARCH_PREFETCH_BASE_SEARCH_PREFETCH_REQUEST_H_
diff --git a/chrome/browser/prefetch/search_prefetch/field_trial_settings.cc b/chrome/browser/prefetch/search_prefetch/field_trial_settings.cc index fcc8edc..af69c0c 100644 --- a/chrome/browser/prefetch/search_prefetch/field_trial_settings.cc +++ b/chrome/browser/prefetch/search_prefetch/field_trial_settings.cc
@@ -8,6 +8,7 @@ #include "base/metrics/field_trial_params.h" #include "base/system/sys_info.h" +#include "chrome/browser/prerender/prerender_utils.h" const base::Feature kSearchPrefetchServicePrefetching{ "SearchPrefetchServicePrefetching", base::FEATURE_ENABLED_BY_DEFAULT}; @@ -15,6 +16,9 @@ const base::Feature kSearchPrefetchBlockBeforeHeaders{ "SearchPrefetchBlockBeforeHeaders", base::FEATURE_DISABLED_BY_DEFAULT}; +const base::Feature kSearchPrefetchUpgradeToPrerender{ + "SearchPrefetchUpgradeToPrerender", base::FEATURE_DISABLED_BY_DEFAULT}; + bool SearchPrefetchBlockBeforeHeadersIsEnabled() { return base::FeatureList::IsEnabled(kSearchPrefetchBlockBeforeHeaders); } @@ -30,6 +34,12 @@ 3000); } +bool SearchPrefetchUpgradeToPrerenderIsEnabled() { + if (!prerender_utils::IsSearchSuggestionPrerenderEnabled()) + return false; + return base::FeatureList::IsEnabled(kSearchPrefetchUpgradeToPrerender); +} + const base::Feature kSearchPrefetchUsesNetworkCache{ "SearchPrefetchUsesNetworkCache", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/chrome/browser/prefetch/search_prefetch/field_trial_settings.h b/chrome/browser/prefetch/search_prefetch/field_trial_settings.h index 5c603dd4..890f9cb 100644 --- a/chrome/browser/prefetch/search_prefetch/field_trial_settings.h +++ b/chrome/browser/prefetch/search_prefetch/field_trial_settings.h
@@ -12,6 +12,8 @@ extern const base::Feature kSearchPrefetchBlockBeforeHeaders; +extern const base::Feature kSearchPrefetchUpgradeToPrerender; + extern const base::Feature kSearchPrefetchUsesNetworkCache; // Whether matching prefetches can block navigation until they are determined to @@ -21,6 +23,9 @@ // Whether the search prefetch service actually initiates prefetches. bool SearchPrefetchServicePrefetchingIsEnabled(); +// Whether supporting upgrading a prefetch response to prerender page. +bool SearchPrefetchUpgradeToPrerenderIsEnabled(); + // Whether the search prefetch service uses the network cache instead of the in // memory cache. bool SearchPrefetchUsesNetworkCache();
diff --git a/chrome/browser/prefetch/search_prefetch/search_prefetch_service.cc b/chrome/browser/prefetch/search_prefetch/search_prefetch_service.cc index c56c03bc..6926206e0 100644 --- a/chrome/browser/prefetch/search_prefetch/search_prefetch_service.cc +++ b/chrome/browser/prefetch/search_prefetch/search_prefetch_service.cc
@@ -6,6 +6,7 @@ #include "base/bind.h" #include "base/callback.h" +#include "base/containers/contains.h" #include "base/json/values_util.h" #include "base/location.h" #include "base/metrics/histogram_macros.h" @@ -25,6 +26,7 @@ #include "chrome/common/pref_names.h" #include "components/content_settings/core/browser/host_content_settings_map.h" #include "components/content_settings/core/common/content_settings.h" +#include "components/omnibox/browser/autocomplete_match.h" #include "components/omnibox/browser/autocomplete_result.h" #include "components/omnibox/browser/base_search_provider.h" #include "components/omnibox/browser/omnibox_event_global_tracker.h" @@ -98,6 +100,13 @@ } } +bool ShouldPrefetch(const AutocompleteMatch& match) { + // Prerender's threshold should definitely be higher than prefetch's. So a + // prerender hints can be treated as a prefetch hint. + return BaseSearchProvider::ShouldPrefetch(match) || + BaseSearchProvider::ShouldPrerender(match); +} + } // namespace // static @@ -209,7 +218,7 @@ std::unique_ptr<BaseSearchPrefetchRequest> prefetch_request = std::make_unique<StreamingSearchPrefetchRequest>( - url, navigation_prefetch, + search_terms, url, navigation_prefetch, base::BindOnce(&SearchPrefetchService::ReportFetchResult, base::Unretained(this))); @@ -464,9 +473,18 @@ for (const auto& kv_pair : prefetches_) { const auto& search_terms = kv_pair.first; auto& prefetch_request = kv_pair.second; + if (prefetch_request->current_status() != SearchPrefetchStatus::kInFlight && prefetch_request->current_status() != SearchPrefetchStatus::kCanBeServed) { + // Reset all pending prerenders. It will be set soon if service still + // wants clients to prerender a SearchTerms. + // TODO(https://crbug.com/1295170): Unlike prefetch, which does not + // discard completed response to avoid wasting, prerender would like + // to cancel itself given the cost of a prerender. For now prenderer is + // canceled when the prerender hints changed, we need to revisit this + // decision. + prefetch_request->ResetPrerenderUpgrader(); continue; } bool should_cancel_request = true; @@ -486,16 +504,32 @@ if (should_cancel_request) { prefetch_request->CancelPrefetch(); } + + // Reset all pending prerenders. It will be set soon if service still wants + // clients to prerender a SearchTerms. + prefetch_request->ResetPrerenderUpgrader(); } + // Do not perform preloading if there is no active tab. + if (!web_contents) + return; for (const auto& match : result) { + if (SearchPrefetchUpgradeToPrerenderIsEnabled()) { + if (!ShouldPrefetch(match)) + continue; + CoordinatePrefetchWithPrerender(match, *web_contents, + template_url_service); + continue; + } + if (BaseSearchProvider::ShouldPrefetch(match)) { MaybePrefetchURL(GetPrefetchURLFromMatch(match, template_url_service)); } if (prerender_utils::IsSearchSuggestionPrerenderEnabled() && - BaseSearchProvider::ShouldPrerender(match) && web_contents) { + BaseSearchProvider::ShouldPrerender(match)) { PrerenderManager::CreateForWebContents(web_contents); auto* prerender_manager = PrerenderManager::FromWebContents(web_contents); + DCHECK(prerender_manager); prerender_manager->StartPrerenderSearchSuggestion(match); } } @@ -684,3 +718,23 @@ base::Unretained(this))); } } + +void SearchPrefetchService::CoordinatePrefetchWithPrerender( + const AutocompleteMatch& match, + content::WebContents& web_contents, + TemplateURLService* template_url_service) { + GURL prefetch_url = GetPrefetchURLFromMatch(match, template_url_service); + MaybePrefetchURL(prefetch_url); + if (!BaseSearchProvider::ShouldPrerender(match)) + return; + + if (auto prefetch_request_iter = + prefetches_.find(match.search_terms_args->search_terms); + prefetch_request_iter != prefetches_.end()) { + PrerenderManager::CreateForWebContents(&web_contents); + auto* prerender_manager = PrerenderManager::FromWebContents(&web_contents); + DCHECK(prerender_manager); + prefetch_request_iter->second->MaybeStartPrerenderSearchResult( + *prerender_manager); + } +}
diff --git a/chrome/browser/prefetch/search_prefetch/search_prefetch_service.h b/chrome/browser/prefetch/search_prefetch/search_prefetch_service.h index 0c31132a..b40769e 100644 --- a/chrome/browser/prefetch/search_prefetch/search_prefetch_service.h +++ b/chrome/browser/prefetch/search_prefetch/search_prefetch_service.h
@@ -22,6 +22,7 @@ #include "third_party/abseil-cpp/absl/types/optional.h" #include "url/gurl.h" +struct AutocompleteMatch; struct OmniboxLog; class PrefRegistrySimple; class Profile; @@ -179,6 +180,17 @@ bool LoadFromPrefs(); void SaveToPrefs() const; + // Called when this receives preloadable hints, and iff the + // SearchPrefetchUpgradeToPrerender feature is enabled. The feature is running + // on the assumption that Prerender is triggered after Prefetch receives + // servable response, so some specific logic is required and implemented by + // this method, e.g., it prefetches a prerender hint regardless of whether it + // is a prefetch hint, since a prerenderable result should be prefetchable. + void CoordinatePrefetchWithPrerender( + const AutocompleteMatch& match, + content::WebContents& web_contents, + TemplateURLService* template_url_service); + // Prefetches that are started are stored using search terms as a key. Only // one prefetch should be started for a given search term until the old // prefetch expires.
diff --git a/chrome/browser/prefetch/search_prefetch/search_preload_unified_browsertest.cc b/chrome/browser/prefetch/search_prefetch/search_preload_unified_browsertest.cc index a1402f1..63ca9a6a 100644 --- a/chrome/browser/prefetch/search_prefetch/search_preload_unified_browsertest.cc +++ b/chrome/browser/prefetch/search_prefetch/search_preload_unified_browsertest.cc
@@ -6,9 +6,11 @@ #include "base/bind.h" #include "base/containers/adapters.h" +#include "base/containers/contains.h" #include "base/files/file_path.h" #include "base/path_service.h" #include "base/strings/string_number_conversions.h" +#include "base/test/metrics/histogram_tester.h" #include "build/build_config.h" #include "chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.h" #include "chrome/browser/prefetch/search_prefetch/field_trial_settings.h" @@ -36,7 +38,7 @@ #if BUILDFLAG(IS_ANDROID) #include "chrome/test/base/android/android_browser_test.h" -#else +#else // BUILDFLAG(IS_ANDROID) #include "chrome/test/base/in_process_browser_test.h" #endif // BUILDFLAG(IS_ANDROID) @@ -60,7 +62,8 @@ {kSearchPrefetchServicePrefetching, {{"max_attempts_per_caching_duration", "3"}, {"cache_size", "1"}, - {"device_memory_threshold_MB", "0"}}}}, + {"device_memory_threshold_MB", "0"}}}, + {kSearchPrefetchUpgradeToPrerender, {}}}, /*disabled_features=*/{kSearchPrefetchBlockBeforeHeaders}); } @@ -109,8 +112,24 @@ std::unique_ptr<net::test_server::HttpResponse> HandleSearchRequest( const net::test_server::HttpRequest& request) { - if (request.GetURL().spec().find("favicon") != std::string::npos) + if (request.GetURL().spec().find("favicon") != std::string::npos) { return nullptr; + } + if (request.GetURL().spec().find("failed_terms") != std::string::npos) { + std::unique_ptr<net::test_server::BasicHttpResponse> resp = + std::make_unique<net::test_server::BasicHttpResponse>(); + resp->set_code(net::HTTP_SERVICE_UNAVAILABLE); + return resp; + } + if (request.GetURL().spec().find("hang_response") != std::string::npos) { + return std::make_unique<net::test_server::HungResponse>(); + } + if (request.GetURL().spec().find("hang_body") != std::string::npos) { + base::StringPairs headers = {{"Content-Length", "100"}, + {"content-type", "text/html"}}; + return std::make_unique<net::test_server::HungAfterHeadersHttpResponse>( + headers); + } std::unique_ptr<net::test_server::BasicHttpResponse> resp = std::make_unique<net::test_server::BasicHttpResponse>(); @@ -147,6 +166,10 @@ return chrome_test_utils::GetActiveWebContents(this); } + protected: + enum class PrerenderHint { kEnabled, kDisabled }; + enum class PrefetchHint { kEnabled, kDisabled }; + void SetUpContext() { // Have SearchPrefetchService and PrerenderManager prepared. PrerenderManager::CreateForWebContents(GetActiveWebContents()); @@ -160,23 +183,36 @@ Profile* GetProfile() { return chrome_test_utils::GetProfile(this); } - AutocompleteMatch CreateSearchSuggestionMatch( - const std::string& original_query, - const std::string& search_terms, - bool is_prerender_hint, - bool is_prefetch_hint) { - AutocompleteMatch match; - match.search_terms_args = std::make_unique<TemplateURLRef::SearchTermsArgs>( - base::UTF8ToUTF16(search_terms)); - match.search_terms_args->original_query = base::UTF8ToUTF16(original_query); - match.destination_url = - GetSearchUrl(search_terms, /*attach_prefetch_flag=*/false); - match.keyword = base::UTF8ToUTF16(original_query); - if (is_prerender_hint) - match.RecordAdditionalInfo("should_prerender", "true"); - if (is_prefetch_hint) - match.RecordAdditionalInfo("should_prefetch", "true"); - return match; + void ChangeAutocompleteResult(const std::string& original_query, + const std::string& search_terms, + PrerenderHint prerender_hint, + PrefetchHint prefetch_hint) { + AutocompleteInput input(base::ASCIIToUTF16(original_query), + metrics::OmniboxEventProto::BLANK, + ChromeAutocompleteSchemeClassifier( + chrome_test_utils::GetProfile(this))); + AutocompleteMatch autocomplete_match = CreateSearchSuggestionMatch( + original_query, search_terms, prerender_hint, prefetch_hint); + AutocompleteResult autocomplete_result; + autocomplete_result.AppendMatches({autocomplete_match}); + search_prefetch_service()->OnResultChanged(GetActiveWebContents(), + autocomplete_result); + } + + void WaitUntilStatusChangesTo( + std::u16string search_terms, + std::vector<SearchPrefetchStatus> acceptable_status) { + while (true) { + if (absl::optional<SearchPrefetchStatus> current_status = + search_prefetch_service()->GetSearchPrefetchStatusForTesting( + search_terms); + current_status && + base::Contains(acceptable_status, current_status.value())) { + break; + } + base::RunLoop run_loop; + run_loop.RunUntilIdle(); + } } content::test::PrerenderTestHelper& prerender_helper() { @@ -190,6 +226,25 @@ } private: + AutocompleteMatch CreateSearchSuggestionMatch( + const std::string& original_query, + const std::string& search_terms, + PrerenderHint prerender_hint, + PrefetchHint prefetch_hint) { + AutocompleteMatch match; + match.search_terms_args = std::make_unique<TemplateURLRef::SearchTermsArgs>( + base::UTF8ToUTF16(search_terms)); + match.search_terms_args->original_query = base::UTF8ToUTF16(original_query); + match.destination_url = + GetSearchUrl(search_terms, /*attach_prefetch_flag=*/false); + match.keyword = base::UTF8ToUTF16(original_query); + if (prerender_hint == PrerenderHint::kEnabled) + match.RecordAdditionalInfo("should_prerender", "true"); + if (prefetch_hint == PrefetchHint::kEnabled) + match.RecordAdditionalInfo("should_prefetch", "true"); + return match; + } + constexpr static char kSearchDomain[] = "a.test"; constexpr static char16_t kSearchDomain16[] = u"a.test"; raw_ptr<PrerenderManager> prerender_manager_ = nullptr; @@ -200,9 +255,10 @@ base::test::ScopedFeatureList scoped_feature_list_; }; -// Tests that the SearchSuggestionService can trigger prerendering when it -// receives prerender hints. -IN_PROC_BROWSER_TEST_F(SearchPreloadUnifiedBrowserTest, PrerenderBeTriggered) { +// Tests that the SearchSuggestionService can trigger prerendering after the +// corresponding prefetch request succeeds. +IN_PROC_BROWSER_TEST_F(SearchPreloadUnifiedBrowserTest, + PrerenderHintReceivedBeforeSucceed) { const GURL kInitialUrl = embedded_test_server()->GetURL("/empty.html"); ASSERT_TRUE(GetActiveWebContents()); ASSERT_TRUE(content::NavigateToURL(GetActiveWebContents(), kInitialUrl)); @@ -216,16 +272,8 @@ content::test::PrerenderHostRegistryObserver registry_observer( *GetActiveWebContents()); - AutocompleteInput input( - base::ASCIIToUTF16(search_query), metrics::OmniboxEventProto::BLANK, - ChromeAutocompleteSchemeClassifier(chrome_test_utils::GetProfile(this))); - AutocompleteMatch autocomplete_match = CreateSearchSuggestionMatch( - search_query, prerender_query, /*is_prerender_hint=*/true, - /*is_prefetch_hint=*/true); - AutocompleteResult autocomplete_result; - autocomplete_result.AppendMatches({autocomplete_match}); - search_prefetch_service()->OnResultChanged(GetActiveWebContents(), - autocomplete_result); + ChangeAutocompleteResult(search_query, prerender_query, + PrerenderHint::kEnabled, PrefetchHint::kEnabled); // The suggestion service should hint expected_prerender_url, and prerendering // for this url should start. @@ -233,10 +281,181 @@ prerender_helper().WaitForPrerenderLoadCompletion(*GetActiveWebContents(), expected_prerender_url); // Prefetch should be triggered as well. - auto prefetch_status = + absl::optional<SearchPrefetchStatus> prefetch_status = search_prefetch_service()->GetSearchPrefetchStatusForTesting( base::ASCIIToUTF16(prerender_query)); EXPECT_TRUE(prefetch_status.has_value()); } +// Tests that the SearchSuggestionService can trigger prerendering if it +// receives prerender hints after the previous prefetch request succeeds. +IN_PROC_BROWSER_TEST_F(SearchPreloadUnifiedBrowserTest, + PrerenderHintReceivedAfterSucceed) { + base::HistogramTester histogram_tester; + const GURL kInitialUrl = embedded_test_server()->GetURL("/empty.html"); + ASSERT_TRUE(GetActiveWebContents()); + ASSERT_TRUE(content::NavigateToURL(GetActiveWebContents(), kInitialUrl)); + SetUpContext(); + + std::string search_query_1 = "pre"; + std::string prerender_query = "prerender"; + GURL expected_prerender_url = + GetSearchUrl(prerender_query, /*attach_prefetch_flag=*/true); + + content::test::PrerenderHostRegistryObserver registry_observer( + *GetActiveWebContents()); + + ChangeAutocompleteResult(search_query_1, prerender_query, + PrerenderHint::kDisabled, PrefetchHint::kEnabled); + + // Wait until prefetch request succeeds. + absl::optional<SearchPrefetchStatus> prefetch_status = + search_prefetch_service()->GetSearchPrefetchStatusForTesting( + base::ASCIIToUTF16(prerender_query)); + EXPECT_TRUE(prefetch_status.has_value()); + WaitUntilStatusChangesTo( + base::ASCIIToUTF16(prerender_query), + {SearchPrefetchStatus::kCanBeServed, SearchPrefetchStatus::kComplete}); + + std::string search_query_2 = "prer"; + ChangeAutocompleteResult(search_query_2, prerender_query, + PrerenderHint::kEnabled, PrefetchHint::kEnabled); + + // The suggestion service should hint `expected_prerender_url`, and + // prerendering for this url should start. + registry_observer.WaitForTrigger(expected_prerender_url); + prerender_helper().WaitForPrerenderLoadCompletion(*GetActiveWebContents(), + expected_prerender_url); + + // Activate. + content::TestActivationManager activation_manager(GetActiveWebContents(), + expected_prerender_url); + GetActiveWebContents()->OpenURL(content::OpenURLParams( + expected_prerender_url, content::Referrer(), + WindowOpenDisposition::CURRENT_TAB, + ui::PageTransitionFromInt(ui::PAGE_TRANSITION_GENERATED | + ui::PAGE_TRANSITION_FROM_ADDRESS_BAR), + /*is_renderer_initiated=*/false)); + activation_manager.WaitForNavigationFinished(); + EXPECT_TRUE(activation_manager.was_activated()); +} + +// Tests that the SearchSuggestionService will not trigger prerender if the +// prefetch failed. +IN_PROC_BROWSER_TEST_F(SearchPreloadUnifiedBrowserTest, + FailedPrefetchCannotBeUpgraded) { + base::HistogramTester histogram_tester; + const GURL kInitialUrl = embedded_test_server()->GetURL("/empty.html"); + ASSERT_TRUE(GetActiveWebContents()); + ASSERT_TRUE(content::NavigateToURL(GetActiveWebContents(), kInitialUrl)); + SetUpContext(); + + std::string search_query = "fail"; + std::string prerender_query = "failed_terms"; + + ChangeAutocompleteResult(search_query, prerender_query, + PrerenderHint::kEnabled, PrefetchHint::kEnabled); + + // Prefetch should be triggered, and the prefetch request should fail. + absl::optional<SearchPrefetchStatus> prefetch_status = + search_prefetch_service()->GetSearchPrefetchStatusForTesting( + base::ASCIIToUTF16(prerender_query)); + EXPECT_TRUE(prefetch_status.has_value()); + WaitUntilStatusChangesTo(base::ASCIIToUTF16(prerender_query), + {SearchPrefetchStatus::kRequestFailed}); + EXPECT_FALSE(prerender_manager()->HasSearchResultPagePrerendered()); +} + +// Tests that the SearchSuggestionService will not trigger prerender if the +// suggestions changes before SearchSuggestionService receives a servable +// response. +IN_PROC_BROWSER_TEST_F(SearchPreloadUnifiedBrowserTest, + SuggestionChangeBeforeStartPrerender) { + base::HistogramTester histogram_tester; + const GURL kInitialUrl = embedded_test_server()->GetURL("/empty.html"); + ASSERT_TRUE(GetActiveWebContents()); + ASSERT_TRUE(content::NavigateToURL(GetActiveWebContents(), kInitialUrl)); + SetUpContext(); + + // 1. Type the first query. + std::string search_query_1 = "hang"; + std::string prerender_query_1 = "hang_response"; + GURL expected_prerender_url = + GetSearchUrl(prerender_query_1, /*attach_prefetch_flag=*/true); + ChangeAutocompleteResult(search_query_1, prerender_query_1, + PrerenderHint::kEnabled, PrefetchHint::kEnabled); + + // 2. Prefetch should be triggered. + auto prefetch_status = + search_prefetch_service()->GetSearchPrefetchStatusForTesting( + base::ASCIIToUTF16(prerender_query_1)); + EXPECT_TRUE(prefetch_status.has_value()); + WaitUntilStatusChangesTo(base::ASCIIToUTF16(prerender_query_1), + {SearchPrefetchStatus::kInFlight}); + + // 3. Type a different query which results in different suggestions. + std::string search_query_2 = "pre"; + ChangeAutocompleteResult(search_query_2, search_query_2, + PrerenderHint::kDisabled, PrefetchHint::kEnabled); + + // 4. The old prefetch should be cancelled. + prefetch_status = + search_prefetch_service()->GetSearchPrefetchStatusForTesting( + base::ASCIIToUTF16(prerender_query_1)); + EXPECT_TRUE(prefetch_status.has_value()); + WaitUntilStatusChangesTo(base::ASCIIToUTF16(prerender_query_1), + {SearchPrefetchStatus::kRequestCancelled}); + + EXPECT_FALSE(prerender_manager()->HasSearchResultPagePrerendered()); +} + +// Tests prerender is cancelled after SearchPrefetchService cancels prefetch +// requests. +IN_PROC_BROWSER_TEST_F(SearchPreloadUnifiedBrowserTest, + SuggestionChangeAfterStartPrerender) { + base::HistogramTester histogram_tester; + const GURL kInitialUrl = embedded_test_server()->GetURL("/empty.html"); + ASSERT_TRUE(GetActiveWebContents()); + ASSERT_TRUE(content::NavigateToURL(GetActiveWebContents(), kInitialUrl)); + SetUpContext(); + content::test::PrerenderHostRegistryObserver registry_observer( + *GetActiveWebContents()); + + // 1. Type the first query. + std::string search_query_1 = "hang"; + std::string prerender_query_1 = "hang_body"; + GURL expected_prerender_url = + GetSearchUrl(prerender_query_1, /*attach_prefetch_flag=*/true); + ChangeAutocompleteResult(search_query_1, prerender_query_1, + PrerenderHint::kEnabled, PrefetchHint::kEnabled); + + // 2. Prefetch should be triggered, and chrome is receiving the response body. + absl::optional<SearchPrefetchStatus> prefetch_status = + search_prefetch_service()->GetSearchPrefetchStatusForTesting( + base::ASCIIToUTF16(prerender_query_1)); + EXPECT_TRUE(prefetch_status.has_value()); + WaitUntilStatusChangesTo(base::ASCIIToUTF16(prerender_query_1), + {SearchPrefetchStatus::kCanBeServed}); + + // 3. prerendering should be triggered. + registry_observer.WaitForTrigger(expected_prerender_url); + EXPECT_TRUE(prerender_manager()->HasSearchResultPagePrerendered()); + + // 4. Type a different query which results in different suggestions. + std::string search_query_2 = "pre"; + ChangeAutocompleteResult(search_query_2, search_query_2, + PrerenderHint::kDisabled, PrefetchHint::kEnabled); + + // 5. The old prefetch should be cancelled. + prefetch_status = + search_prefetch_service()->GetSearchPrefetchStatusForTesting( + base::ASCIIToUTF16(prerender_query_1)); + EXPECT_TRUE(prefetch_status.has_value()); + WaitUntilStatusChangesTo(base::ASCIIToUTF16(prerender_query_1), + {SearchPrefetchStatus::kRequestCancelled}); + + // 6. Prerender should be cancelled as well. + EXPECT_FALSE(prerender_manager()->HasSearchResultPagePrerendered()); +} + } // namespace
diff --git a/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_request.cc b/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_request.cc index 11bb21e..5c8ceeea 100644 --- a/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_request.cc +++ b/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_request.cc
@@ -11,10 +11,12 @@ #include "net/base/load_flags.h" StreamingSearchPrefetchRequest::StreamingSearchPrefetchRequest( + const std::u16string& prefetch_search_terms, const GURL& prefetch_url, bool navigation_prefetch, base::OnceCallback<void(bool)> report_error_callback) - : BaseSearchPrefetchRequest(prefetch_url, + : BaseSearchPrefetchRequest(prefetch_search_terms, + prefetch_url, navigation_prefetch, std::move(report_error_callback)) {}
diff --git a/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_request.h b/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_request.h index 51e8620..9b9a655 100644 --- a/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_request.h +++ b/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_request.h
@@ -26,6 +26,7 @@ class StreamingSearchPrefetchRequest : public BaseSearchPrefetchRequest { public: StreamingSearchPrefetchRequest( + const std::u16string& prefetch_search_terms, const GURL& prefetch_url, bool navigation_prefetch, base::OnceCallback<void(bool)> report_error_callback);
diff --git a/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_url_loader.cc b/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_url_loader.cc index f10594b..4d1da86 100644 --- a/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_url_loader.cc +++ b/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_url_loader.cc
@@ -104,6 +104,14 @@ streaming_prefetch_request_->MarkPrefetchAsServable(); } +void StreamingSearchPrefetchURLLoader::OnServableResponseCodeReceived() { + // This means that the navigation stack is already running for the navigation + // to this term, and chrome does not need to prerender. + if (!streaming_prefetch_request_) + return; + streaming_prefetch_request_->OnServableResponseCodeReceived(); +} + SearchPrefetchURLLoader::RequestHandler StreamingSearchPrefetchURLLoader::ServingResponseHandlerImpl( std::unique_ptr<SearchPrefetchURLLoader> loader) { @@ -244,6 +252,7 @@ } MarkPrefetchAsServable(); + OnServableResponseCodeReceived(); // Store head and pause new messages until the forwarding client is set up. resource_response_ = std::move(head);
diff --git a/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_url_loader.h b/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_url_loader.h index 13f6908..b84a83f 100644 --- a/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_url_loader.h +++ b/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_url_loader.h
@@ -151,6 +151,9 @@ // Marks the parent prefetch request as servable. Called as delayed task. void MarkPrefetchAsServable(); + // Called on `this` receives servable response. + void OnServableResponseCodeReceived(); + // The network URLLoader that fetches the prefetch URL and its receiver. mojo::Remote<network::mojom::URLLoader> network_url_loader_; mojo::Receiver<network::mojom::URLLoaderClient> url_loader_receiver_{this};
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc index 1d873735..92a3788a 100644 --- a/chrome/browser/prefs/browser_prefs.cc +++ b/chrome/browser/prefs/browser_prefs.cc
@@ -168,6 +168,7 @@ #if BUILDFLAG(ENABLE_EXTENSIONS) #include "chrome/browser/accessibility/animation_policy_prefs.h" #include "chrome/browser/apps/platform_apps/shortcut_manager.h" +#include "chrome/browser/ash/system_web_apps/system_web_app_manager.h" #include "chrome/browser/extensions/activity_log/activity_log.h" #include "chrome/browser/extensions/api/commands/command_service.h" #include "chrome/browser/extensions/api/cryptotoken_private/cryptotoken_private_api.h" @@ -1320,6 +1321,7 @@ extensions::RegisterSettingsOverriddenUiPrefs(registry); update_client::RegisterProfilePrefs(registry); web_app::WebAppProvider::RegisterProfilePrefs(registry); + ash::SystemWebAppManager::RegisterProfilePrefs(registry); #endif // BUILDFLAG(ENABLE_EXTENSIONS) #if BUILDFLAG(ENABLE_OFFLINE_PAGES)
diff --git a/chrome/browser/prefs/chrome_command_line_pref_store.cc b/chrome/browser/prefs/chrome_command_line_pref_store.cc index 3fdef6b..6543e497 100644 --- a/chrome/browser/prefs/chrome_command_line_pref_store.cc +++ b/chrome/browser/prefs/chrome_command_line_pref_store.cc
@@ -47,6 +47,7 @@ {switches::kAuthServerAllowlist, prefs::kAuthServerAllowlist}, {switches::kSSLVersionMin, prefs::kSSLVersionMin}, {switches::kSSLVersionMax, prefs::kSSLVersionMax}, + {switches::kWebRtcIPHandlingPolicy, prefs::kWebRTCIPHandlingPolicy}, #if BUILDFLAG(IS_ANDROID) {switches::kAuthAndroidNegotiateAccountType, prefs::kAuthAndroidNegotiateAccountType},
diff --git a/chrome/browser/prerender/prerender_manager.cc b/chrome/browser/prerender/prerender_manager.cc index f5ba6da0..8af7e4c 100644 --- a/chrome/browser/prerender/prerender_manager.cc +++ b/chrome/browser/prerender/prerender_manager.cc
@@ -332,26 +332,11 @@ TemplateURLRef::SearchTermsArgs& search_terms_args = *(match.search_terms_args); const std::u16string& search_terms = search_terms_args.search_terms; - // Do not re-prerender the same search result. - if (search_prerender_task_) { - // TODO(https://crbug.com/1278634): re-prerender the search result if the - // prerendered content has been removed. - if (search_prerender_task_->prerendered_search_terms() == search_terms) { - return; - } - base::UmaHistogramEnumeration( - internal::kHistogramPrerenderPredictionStatusDefaultSearchEngine, - PrerenderPredictionStatus::kCancelled); - search_prerender_task_.reset(); - } - - // web_contents() owns the instance that stores this callback, so it is safe - // to call std::ref. - base::RepeatingCallback<bool(const GURL&)> url_match_predicate = - base::BindRepeating(&IsSearchDestinationMatch, - search_terms_args.search_terms, - std::ref(*web_contents())); + // If the caller does not want to prerender a new result, this does not need + // to do anything. + if (!ResetSearchPrerenderTaskIfNecessary(search_terms)) + return; GURL prerender_url = match.destination_url; // Skip changing the prerender URL in tests as they may not have Profile or @@ -386,17 +371,30 @@ } DCHECK(!search_terms_args.is_prefetch); } - std::unique_ptr<content::PrerenderHandle> prerender_handle = - web_contents()->StartPrerendering( - prerender_url, content::PrerenderTriggerType::kEmbedder, - prerender_utils::kDefaultSearchEngineMetricSuffix, - ui::PageTransitionFromInt(ui::PAGE_TRANSITION_GENERATED | - ui::PAGE_TRANSITION_FROM_ADDRESS_BAR), - std::move(url_match_predicate)); - if (prerender_handle) { - search_prerender_task_ = std::make_unique<SearchPrerenderTask>( - search_terms, std::move(prerender_handle)); + StartPrerenderSearchResultInternal(search_terms, prerender_url); +} + +void PrerenderManager::StartPrerenderSearchResult( + const std::u16string& search_terms, + const GURL& prerendering_url) { + DCHECK(SearchPrefetchUpgradeToPrerenderIsEnabled()); + + // If the caller does not want to prerender a new result, this does not need + // to do anything. + if (!ResetSearchPrerenderTaskIfNecessary(search_terms)) + return; + StartPrerenderSearchResultInternal(search_terms, prerendering_url); +} + +void PrerenderManager::StopPrerenderSearchResult( + const std::u16string& search_terms) { + if (search_prerender_task_ && + search_prerender_task_->prerendered_search_terms() == search_terms) { + // TODO(https://crbug.com/1295170): Record + // PrerenderPredictionStatus::kCancelled here. And double check if we update + // kNotStarted. + search_prerender_task_.reset(); } } @@ -404,6 +402,10 @@ return !!search_prerender_task_; } +base::WeakPtr<PrerenderManager> PrerenderManager::GetWeakPtr() { + return weak_factory_.GetWeakPtr(); +} + const std::u16string PrerenderManager::GetPrerenderSearchTermForTesting() const { return search_prerender_task_ @@ -462,6 +464,48 @@ } } +bool PrerenderManager::ResetSearchPrerenderTaskIfNecessary( + const std::u16string& search_terms) { + if (!search_prerender_task_) + return true; + + // Do not re-prerender the same search result. + // TODO(https://crbug.com/1278634): re-prerender the search result if the + // prerendered content has been removed. + if (search_prerender_task_->prerendered_search_terms() == search_terms) { + return false; + } + + base::UmaHistogramEnumeration( + internal::kHistogramPrerenderPredictionStatusDefaultSearchEngine, + PrerenderPredictionStatus::kCancelled); + search_prerender_task_.reset(); + return true; +} + +void PrerenderManager::StartPrerenderSearchResultInternal( + const std::u16string& search_terms, + const GURL& prerendering_url) { + // web_contents() owns the instance that stores this callback, so it is safe + // to call std::ref. + base::RepeatingCallback<bool(const GURL&)> url_match_predicate = + base::BindRepeating(&IsSearchDestinationMatch, search_terms, + std::ref(*web_contents())); + + std::unique_ptr<content::PrerenderHandle> prerender_handle = + web_contents()->StartPrerendering( + prerendering_url, content::PrerenderTriggerType::kEmbedder, + prerender_utils::kDefaultSearchEngineMetricSuffix, + ui::PageTransitionFromInt(ui::PAGE_TRANSITION_GENERATED | + ui::PAGE_TRANSITION_FROM_ADDRESS_BAR), + std::move(url_match_predicate)); + + if (prerender_handle) { + search_prerender_task_ = std::make_unique<SearchPrerenderTask>( + search_terms, std::move(prerender_handle)); + } +} + PrerenderManager::PrerenderManager(content::WebContents* web_contents) : content::WebContentsObserver(web_contents), content::WebContentsUserData<PrerenderManager>(*web_contents) {}
diff --git a/chrome/browser/prerender/prerender_manager.h b/chrome/browser/prerender/prerender_manager.h index a3f0499..70c269128 100644 --- a/chrome/browser/prerender/prerender_manager.h +++ b/chrome/browser/prerender/prerender_manager.h
@@ -5,6 +5,8 @@ #ifndef CHROME_BROWSER_PRERENDER_PRERENDER_MANAGER_H_ #define CHROME_BROWSER_PRERENDER_PRERENDER_MANAGER_H_ +#include <string> + #include "components/omnibox/browser/autocomplete_match.h" #include "content/public/browser/prerender_handle.h" #include "content/public/browser/web_contents.h" @@ -52,11 +54,23 @@ void DidFinishNavigation( content::NavigationHandle* navigation_handle) override; - // The entry of prerender. - // Calling this method will lead to the cancellation of the previous prerender - // if the given `match`'s search terms differ from the ongoing one's. + // The entry of Default Search Engine prerender. Calling this method will lead + // to the cancellation of the previous prerender if the given `match`'s search + // terms differs from the ongoing one's. + // TODO(https://crbug.com/1295170): Remove this method after Search prerender + // work properly with Search prefetch. void StartPrerenderSearchSuggestion(const AutocompleteMatch& match); + // Calling this method will lead to the cancellation of the previous prerender + // if the given `search_terms` differs from the ongoing one's. + void StartPrerenderSearchResult(const std::u16string& search_terms, + const GURL& prerendering_url); + + // Cancels the prerender that is prerendering the given `search_terms`. + // TODO(https://crbug.com/1295170): Use the creator's address to identify the + // owner that can cancels the corresponding prerendering? + void StopPrerenderSearchResult(const std::u16string& search_terms); + // The entry of direct url input prerender. // Calling this method will return WeakPtr of the started prerender, and lead // to the cancellation of the previous prerender if the given url is different @@ -71,6 +85,8 @@ // inputs. bool HasSearchResultPagePrerendered() const; + base::WeakPtr<PrerenderManager> GetWeakPtr(); + // Returns the prerendered search terms if search_prerender_task_ exists. // Returns empty string otherwise. const std::u16string GetPrerenderSearchTermForTesting() const; @@ -88,6 +104,19 @@ void ResetPrerenderHandlesOnPrimaryPageChanged( content::NavigationHandle* navigation_handle); + // Maybe cancel the ongoing search prerender to restart a new one if this + // finds the callers' intentions changed. The number of concurrence search + // prerender is limited to 1, so it is needed to cancel the old one in order + // to start a new one. Returns true if this finds the caller wants to + // prerender another search result. + bool ResetSearchPrerenderTaskIfNecessary(const std::u16string& search_terms); + + void StartPrerenderSearchResultInternal(const std::u16string& search_terms, + const GURL& prerendering_url); + + // Stops search prefetch from being upgraded to prerender. + void UnregisterSearchPrerender(); + // Stores the prerender which serves for search results. It is responsible for // tracking a started search prerender, and it keeps alive even if the // prerender has been destroyed by the timer. With its help, PrerenderManager @@ -98,6 +127,8 @@ bool skip_template_url_service_for_testing_ = false; + base::WeakPtrFactory<PrerenderManager> weak_factory_{this}; + WEB_CONTENTS_USER_DATA_KEY_DECL(); };
diff --git a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc index c474322..16b1c4c 100644 --- a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc +++ b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
@@ -202,6 +202,7 @@ #include "apps/browser_context_keyed_service_factories.h" #include "chrome/browser/apps/platform_apps/api/browser_context_keyed_service_factories.h" #include "chrome/browser/apps/platform_apps/browser_context_keyed_service_factories.h" +#include "chrome/browser/ash/system_web_apps/system_web_app_manager_factory.h" #include "chrome/browser/extensions/browser_context_keyed_service_factories.h" #include "chrome/browser/ui/web_applications/web_app_metrics_factory.h" #include "chrome/browser/web_applications/adjustments/web_app_adjustments.h" @@ -579,6 +580,10 @@ web_app::WebAppMetricsFactory::GetInstance(); web_app::WebAppProviderFactory::GetInstance(); web_app::WebAppAdjustmentsFactory::GetInstance(); + // TODO(crbug.com/1321984): SystemWebAppManagerFactory is instantiated on WML + // and ChromeOS currently. Move it under the IS_CHROMEOS_ASH guard (compile it + // out). + ash::SystemWebAppManagerFactory::GetInstance(); #endif WebDataServiceFactory::GetInstance(); webrtc_event_logging::WebRtcEventLogManagerKeyedServiceFactory::GetInstance();
diff --git a/chrome/browser/resources/app_service_internals/app_service_internals.ts b/chrome/browser/resources/app_service_internals/app_service_internals.ts index 6562e8e..540e2fc 100644 --- a/chrome/browser/resources/app_service_internals/app_service_internals.ts +++ b/chrome/browser/resources/app_service_internals/app_service_internals.ts
@@ -24,10 +24,10 @@ } /** List containing debug information for all installed apps. */ - appList_: Array<AppInfo> = []; - hashChangeListener_ = () => this.onHashChanged_(); + private appList_: Array<AppInfo> = []; + private hashChangeListener_ = () => this.onHashChanged_(); /** List containing preferred app debug information for installed apps. */ - preferredAppList_: Array<PreferredAppInfo> = []; + private preferredAppList_: Array<PreferredAppInfo> = []; override ready() { super.ready();
diff --git a/chrome/browser/resources/chromeos/assistant_optin/assistant_related_info.js b/chrome/browser/resources/chromeos/assistant_optin/assistant_related_info.js index e7786e6..3a317e37 100644 --- a/chrome/browser/resources/chromeos/assistant_optin/assistant_related_info.js +++ b/chrome/browser/resources/chromeos/assistant_optin/assistant_related_info.js
@@ -90,7 +90,7 @@ * @private {string} */ this.urlTemplate_ = - 'https://www.gstatic.com/opa-android/oobe/a02187e41eed9e42/v3_omni_$.html'; + 'https://www.gstatic.com/opa-android/oobe/a02187e41eed9e42/v5_omni_$.html'; /** * Whether try to reload with the default url when a 404 error occurred. @@ -231,6 +231,13 @@ if (this.consentStringLoaded_) { this.onPageLoaded(); } + + // The webview animation only starts playing when it is focused (in order + // to make sure the animation and the caption are in sync). + this.webview_.focus(); + this.async(() => { + this.$['next-button'].focus(); + }, 300); } /**
diff --git a/chrome/browser/resources/chromeos/assistant_optin/assistant_value_prop.html b/chrome/browser/resources/chromeos/assistant_optin/assistant_value_prop.html index ebbae58..f4647b2 100644 --- a/chrome/browser/resources/chromeos/assistant_optin/assistant_value_prop.html +++ b/chrome/browser/resources/chromeos/assistant_optin/assistant_value_prop.html
@@ -76,7 +76,7 @@ </iron-icon> <h1 slot="title" id="title-text"></h1> <div id="animation-container"> - <webview id="value-prop-view" tabindex="-1"></webview> + <webview id="value-prop-view" tabindex="-1"></webview> </div> <div slot="content" id="content-container" class="landscape-vertical-centered">
diff --git a/chrome/browser/resources/chromeos/assistant_optin/assistant_value_prop.js b/chrome/browser/resources/chromeos/assistant_optin/assistant_value_prop.js index 2911a8c3..9ff6882 100644 --- a/chrome/browser/resources/chromeos/assistant_optin/assistant_value_prop.js +++ b/chrome/browser/resources/chromeos/assistant_optin/assistant_value_prop.js
@@ -53,7 +53,7 @@ */ urlTemplate_: { value: - 'https://www.gstatic.com/opa-android/oobe/a02187e41eed9e42/v4_omni_$.html', + 'https://www.gstatic.com/opa-android/oobe/a02187e41eed9e42/v5_omni_$.html', }, /**
diff --git a/chrome/browser/resources/extensions/activity_log/activity_log.ts b/chrome/browser/resources/extensions/activity_log/activity_log.ts index aa19c42..dfaa4e7 100644 --- a/chrome/browser/resources/extensions/activity_log/activity_log.ts +++ b/chrome/browser/resources/extensions/activity_log/activity_log.ts
@@ -95,7 +95,7 @@ extensionInfo: chrome.developerPrivate.ExtensionInfo| ActivityLogExtensionPlaceholder; delegate: ActivityLogDelegate; - selectedSubpage_: ActivityLogSubpage; + private selectedSubpage_: ActivityLogSubpage; private tabNames_: string[]; override ready() {
diff --git a/chrome/browser/resources/new_tab_page/modules/cart/module.html b/chrome/browser/resources/new_tab_page/modules/cart/module.html index 528a76bc..2a3dda5a 100644 --- a/chrome/browser/resources/new_tab_page/modules/cart/module.html +++ b/chrome/browser/resources/new_tab_page/modules/cart/module.html
@@ -82,7 +82,7 @@ width: 0; } - :host([discount-consent-visible_]) #consentContainer { + :host([discount-consent-visible]) #consentContainer { opacity: 1; width: 254px; }
diff --git a/chrome/browser/resources/new_tab_page/modules/cart/module.ts b/chrome/browser/resources/new_tab_page/modules/cart/module.ts index 93694944..d7a5f26 100644 --- a/chrome/browser/resources/new_tab_page/modules/cart/module.ts +++ b/chrome/browser/resources/new_tab_page/modules/cart/module.ts
@@ -93,7 +93,7 @@ {type: Array, computed: 'computeFirstThreeCartItems_(cartItems)'}, /** This is used for animation when the consent become invisible. */ - discountConsentVisible_: { + discountConsentVisible: { type: Boolean, reflectToAttribute: true, } @@ -104,8 +104,8 @@ headerChipText: string; headerDescriptionText: string; showDiscountConsent: boolean; - discountConsentVisible_: boolean; scrollBehavior: ScrollBehavior = 'smooth'; + discountConsentVisible: boolean; private showLeftScrollButton_: boolean; private showRightScrollButton_: boolean; private cartMenuHideItem_: string; @@ -421,7 +421,7 @@ } private onDiscountConsentHidden_() { - if (this.showDiscountConsent && !this.discountConsentVisible_ && + if (this.showDiscountConsent && !this.discountConsentVisible && this.consentStatus_ !== undefined) { this.showDiscountConsent = false; switch (this.consentStatus_) { @@ -452,7 +452,7 @@ private onDiscountConsentRejected_() { this.consentStatus_ = ConsentStatus.REJECTED; - this.discountConsentVisible_ = false; + this.discountConsentVisible = false; ChromeCartProxy.getHandler().onDiscountConsentAcknowledged(false); chrome.metricsPrivate.recordUserAction( 'NewTabPage.Carts.RejectDiscountConsent'); @@ -460,7 +460,7 @@ private onDiscountConsentAccepted_() { this.consentStatus_ = ConsentStatus.ACCEPTED; - this.discountConsentVisible_ = false; + this.discountConsentVisible = false; ChromeCartProxy.getHandler().onDiscountConsentAcknowledged(true); chrome.metricsPrivate.recordUserAction( 'NewTabPage.Carts.AcceptDiscountConsent'); @@ -468,7 +468,7 @@ private onDiscountConsentDismissed_() { this.consentStatus_ = ConsentStatus.DISMISSED; - this.discountConsentVisible_ = false; + this.discountConsentVisible = false; ChromeCartProxy.getHandler().onDiscountConsentDismissed(); chrome.metricsPrivate.recordUserAction( 'NewTabPage.Carts.DismissDiscountConsent'); @@ -556,7 +556,7 @@ } element.cartItems = carts; element.showDiscountConsent = consentVisible; - element.discountConsentVisible_ = consentVisible; + element.discountConsentVisible = consentVisible; return element; }
diff --git a/chrome/browser/resources/print_preview/ui/destination_list_item.ts b/chrome/browser/resources/print_preview/ui/destination_list_item.ts index f0e97acb..0fc85b6c 100644 --- a/chrome/browser/resources/print_preview/ui/destination_list_item.ts +++ b/chrome/browser/resources/print_preview/ui/destination_list_item.ts
@@ -29,9 +29,7 @@ static get properties() { return { destination: Object, - searchQuery: Object, - searchHint_: String, }; } @@ -46,7 +44,7 @@ destination: Destination; searchQuery: RegExp|null; - destinationIcon_: string; + private destinationIcon_: string; private searchHint_: string; private highlights_: Node[] = [];
diff --git a/chrome/browser/resources/print_preview/ui/destination_list_item_cros.ts b/chrome/browser/resources/print_preview/ui/destination_list_item_cros.ts index 5f4f037..4683d14 100644 --- a/chrome/browser/resources/print_preview/ui/destination_list_item_cros.ts +++ b/chrome/browser/resources/print_preview/ui/destination_list_item_cros.ts
@@ -43,9 +43,7 @@ static get properties() { return { destination: Object, - searchQuery: Object, - searchHint_: String, destinationIcon_: { @@ -96,7 +94,7 @@ destination: Destination; searchQuery: RegExp|null; - destinationIcon_: string; + private destinationIcon_: string; private searchHint_: string; private statusText_: string; private isDarkModeActive_: boolean;
diff --git a/chrome/browser/resources/settings/people_page/manage_profile.ts b/chrome/browser/resources/settings/people_page/manage_profile.ts index 8d5b3ad..e22b5ca 100644 --- a/chrome/browser/resources/settings/people_page/manage_profile.ts +++ b/chrome/browser/resources/settings/people_page/manage_profile.ts
@@ -112,7 +112,7 @@ availableIcons: Array<AvatarIcon>; syncStatus: SyncStatus|null; private isProfileShortcutSettingVisible_: boolean; - pattern_: string; + private pattern_: string; private browserProxy_: ManageProfileBrowserProxy = ManageProfileBrowserProxyImpl.getInstance();
diff --git a/chrome/browser/resources/settings/people_page/sync_account_control.ts b/chrome/browser/resources/settings/people_page/sync_account_control.ts index 068713a..09f83a40 100644 --- a/chrome/browser/resources/settings/people_page/sync_account_control.ts +++ b/chrome/browser/resources/settings/people_page/sync_account_control.ts
@@ -146,8 +146,8 @@ promoLabelWithNoAccount: string; promoSecondaryLabelWithAccount: string; promoSecondaryLabelWithNoAccount: string; - signedIn_: boolean; - storedAccounts_: Array<StoredAccount>; + private signedIn_: boolean; + private storedAccounts_: Array<StoredAccount>; private shownAccount_: StoredAccount|null; showingPromo: boolean; embeddedInSubpage: boolean;
diff --git a/chrome/browser/resources/settings/prefs/prefs_types.ts b/chrome/browser/resources/settings/prefs/prefs_types.ts index ec00d9e..69158f0 100644 --- a/chrome/browser/resources/settings/prefs/prefs_types.ts +++ b/chrome/browser/resources/settings/prefs/prefs_types.ts
@@ -11,7 +11,7 @@ class CrSettingsPrefsInternal { isInitialized: boolean = false; deferInitialization: boolean; - initializedResolver_: PromiseResolver<void> = new PromiseResolver(); + private initializedResolver_: PromiseResolver<void> = new PromiseResolver(); constructor() { /**
diff --git a/chrome/browser/resources/settings/privacy_sandbox/app.html b/chrome/browser/resources/settings/privacy_sandbox/app.html index 01d52ef..a80635f 100644 --- a/chrome/browser/resources/settings/privacy_sandbox/app.html +++ b/chrome/browser/resources/settings/privacy_sandbox/app.html
@@ -229,12 +229,12 @@ </div> <template is="dom-if" if="[[!showFragment_(privacySandboxSettingsViewEnum_.MAIN, - privacySandboxSettingsView_)]]" restamp> + privacySandboxSettingsView)]]" restamp> <cr-dialog id="dialogWrapper" show-on-attach on-close="onDialogClose_"> <template id="learnMoreDialog" is="dom-if" if="[[showFragment_( privacySandboxSettingsViewEnum_.LEARN_MORE_DIALOG, - privacySandboxSettingsView_)]]"> + privacySandboxSettingsView)]]"> <div slot="title">$i18n{privacySandboxLearnMoreDialogTitle}</div> <div slot="body"> <div class="learn-more-section-title"> @@ -292,7 +292,7 @@ <template id="adPersonalizationDialog" is="dom-if" if="[[showFragment_( privacySandboxSettingsViewEnum_.AD_PERSONALIZATION_DIALOG, - privacySandboxSettingsView_)]]"> + privacySandboxSettingsView)]]"> <div class="ad-personalization-title" slot="title"> $i18n{privacySandboxAdPersonalizationDialogTitle} </div> @@ -384,7 +384,7 @@ <template id="adPersonalizationRemovedDialog" is="dom-if" if="[[showFragment_( privacySandboxSettingsViewEnum_.AD_PERSONALIZATION_REMOVED_DIALOG, - privacySandboxSettingsView_)]]"> + privacySandboxSettingsView)]]"> <div class="ad-personalization-title" slot="title"> <cr-icon-button id="adPersonalizationBackButton" class="icon-arrow-back" aria-label="$i18n{back}" @@ -433,7 +433,7 @@ <template id="adMeasurementDialog" is="dom-if" if="[[showFragment_( privacySandboxSettingsViewEnum_.AD_MEASUREMENT_DIALOG, - privacySandboxSettingsView_)]]"> + privacySandboxSettingsView)]]"> <div slot="title">$i18n{privacySandboxAdMeasurementDialogTitle}</div> <div slot="body"> <div class="dialog-description"> @@ -449,7 +449,7 @@ <template id="spamAndFraudDialog" is="dom-if" if="[[showFragment_( privacySandboxSettingsViewEnum_.SPAM_AND_FRAUD_DIALOG, - privacySandboxSettingsView_)]]"> + privacySandboxSettingsView)]]"> <div slot="title">$i18n{privacySandboxSpamAndFraudDialogTitle}</div> <div slot="body"> <div class="dialog-description">
diff --git a/chrome/browser/resources/settings/privacy_sandbox/app.ts b/chrome/browser/resources/settings/privacy_sandbox/app.ts index ff4f1af..907cf8e8 100644 --- a/chrome/browser/resources/settings/privacy_sandbox/app.ts +++ b/chrome/browser/resources/settings/privacy_sandbox/app.ts
@@ -58,7 +58,7 @@ }, /** The current view. */ - privacySandboxSettingsView_: { + privacySandboxSettingsView: { type: String, value: PrivacySandboxSettingsView.MAIN, }, @@ -108,7 +108,7 @@ private privacySandboxBrowserProxy_: PrivacySandboxBrowserProxy = PrivacySandboxBrowserProxyImpl.getInstance(); private privacySandboxSettings3Enabled_: boolean; - privacySandboxSettingsView_: PrivacySandboxSettingsView; + privacySandboxSettingsView: PrivacySandboxSettingsView; private topTopics_: Array<PrivacySandboxInterest>; private blockedTopics_: Array<PrivacySandboxInterest>; private joiningSites_: Array<PrivacySandboxInterest>; @@ -153,10 +153,10 @@ const view = new URLSearchParams(window.location.search).get('view'); if (Object.values(PrivacySandboxSettingsView) .includes(view as PrivacySandboxSettingsView)) { - this.privacySandboxSettingsView_ = view as PrivacySandboxSettingsView; + this.privacySandboxSettingsView = view as PrivacySandboxSettingsView; } else { // If no view has been specified, then navigate to main page. - this.privacySandboxSettingsView_ = PrivacySandboxSettingsView.MAIN; + this.privacySandboxSettingsView = PrivacySandboxSettingsView.MAIN; } }); @@ -200,15 +200,15 @@ } private showFragment_(view: PrivacySandboxSettingsView): boolean { - return this.privacySandboxSettingsView_ === view; + return this.privacySandboxSettingsView === view; } private onDialogClose_() { // This function will only be called once, regardless of how the dialog is // shut (either via ESC or via the button), as in the latter the dialog is // not "closed", but rather removed from the DOM. - const lastView = this.privacySandboxSettingsView_; - this.privacySandboxSettingsView_ = PrivacySandboxSettingsView.MAIN; + const lastView = this.privacySandboxSettingsView; + this.privacySandboxSettingsView = PrivacySandboxSettingsView.MAIN; afterNextRender(this, async () => { switch (lastView) { case PrivacySandboxSettingsView.LEARN_MORE_DIALOG: @@ -238,14 +238,14 @@ e.stopPropagation(); this.metricsBrowserProxy_.recordAction( 'Settings.PrivacySandbox.AdPersonalization.LearnMoreClicked'); - this.privacySandboxSettingsView_ = + this.privacySandboxSettingsView = PrivacySandboxSettingsView.LEARN_MORE_DIALOG; } private onAdPersonalizationRowClick_() { this.metricsBrowserProxy_.recordAction( 'Settings.PrivacySandbox.AdPersonalization.Opened'); - this.privacySandboxSettingsView_ = + this.privacySandboxSettingsView = PrivacySandboxSettingsView.AD_PERSONALIZATION_DIALOG; } @@ -265,19 +265,19 @@ private onAdPersonalizationRemovedRowClick_() { this.metricsBrowserProxy_.recordAction( 'Settings.PrivacySandbox.RemovedInterests.Opened'); - this.privacySandboxSettingsView_ = + this.privacySandboxSettingsView = PrivacySandboxSettingsView.AD_PERSONALIZATION_REMOVED_DIALOG; } private onAdPersonalizationBackButtonClick_() { - this.privacySandboxSettingsView_ = + this.privacySandboxSettingsView = PrivacySandboxSettingsView.AD_PERSONALIZATION_DIALOG; } private onAdMeasurementRowClick_() { this.metricsBrowserProxy_.recordAction( 'Settings.PrivacySandbox.AdMeasurement.Opened'); - this.privacySandboxSettingsView_ = + this.privacySandboxSettingsView = PrivacySandboxSettingsView.AD_MEASUREMENT_DIALOG; } @@ -291,7 +291,7 @@ private onSpamAndFraudRowClick_() { this.metricsBrowserProxy_.recordAction( 'Settings.PrivacySandbox.SpamFraud.Opened'); - this.privacySandboxSettingsView_ = + this.privacySandboxSettingsView = PrivacySandboxSettingsView.SPAM_AND_FRAUD_DIALOG; }
diff --git a/chrome/browser/resources/settings/search_page/search_page.ts b/chrome/browser/resources/settings/search_page/search_page.ts index c296603..df7721b 100644 --- a/chrome/browser/resources/settings/search_page/search_page.ts +++ b/chrome/browser/resources/settings/search_page/search_page.ts
@@ -74,7 +74,7 @@ } prefs: Object; - searchEnginesPageTitle_: String; + private searchEnginesPageTitle_: String; private isActiveSearchEnginesFlagEnabled_: boolean; private searchEngines_: Array<SearchEngine>; private searchEnginesFilter_: string;
diff --git a/chrome/browser/resources/signin/profile_customization/profile_customization_app.html b/chrome/browser/resources/signin/profile_customization/profile_customization_app.html index fdadeb4..b63bcbb 100644 --- a/chrome/browser/resources/signin/profile_customization/profile_customization_app.html +++ b/chrome/browser/resources/signin/profile_customization/profile_customization_app.html
@@ -157,11 +157,11 @@ </cr-input> <div id="pickThemeContainer"> - <cr-customize-themes id="themeSelector" auto-confirm-theme-changes> + <cr-customize-themes id="themeSelector"> </cr-customize-themes> </div> - <div class$="action-container + <div class$="action-container [[getDialogDesignClass_(profileCustomizationInDialogDesign_)]]"> <cr-button id="doneButton" class="action-button" disabled="[[isDoneButtonDisabled_(profileName_)]]" @@ -169,8 +169,8 @@ $i18n{profileCustomizationDoneLabel} </cr-button> <template is="dom-if" if="[[profileCustomizationInDialogDesign_]]"> - <!-- TODO: add action on Skip --> - <cr-button id="skipButton" class="cancel-button"> + <cr-button id="skipButton" class="cancel-button" + on-click="onSkipCustomizationClicked_"> $i18n{profileCustomizationSkipLabel} </cr-button> </template>
diff --git a/chrome/browser/resources/signin/profile_customization/profile_customization_app.ts b/chrome/browser/resources/signin/profile_customization/profile_customization_app.ts index e48e05b..5dd83f51 100644 --- a/chrome/browser/resources/signin/profile_customization/profile_customization_app.ts +++ b/chrome/browser/resources/signin/profile_customization/profile_customization_app.ts
@@ -12,6 +12,7 @@ import './signin_shared.css.js'; import './signin_vars.css.js'; +import {CustomizeThemesElement} from 'chrome://resources/cr_components/customize_themes/customize_themes.js'; import {CrButtonElement} from 'chrome://resources/cr_elements/cr_button/cr_button.m.js'; import {CrInputElement} from 'chrome://resources/cr_elements/cr_input/cr_input.m.js'; import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js'; @@ -27,6 +28,7 @@ doneButton: CrButtonElement, nameInput: CrInputElement, title: HTMLElement, + themeSelector: CustomizeThemesElement, }; } @@ -96,6 +98,7 @@ * native. */ private onDoneCustomizationClicked_() { + this.$.themeSelector.confirmThemeChanges(); this.profileCustomizationBrowserProxy_.done(this.profileName_); } @@ -111,6 +114,10 @@ this.welcomeTitle_ = profileInfo.welcomeTitle; } + private onSkipCustomizationClicked_() { + this.profileCustomizationBrowserProxy_.skip(); + } + private getDialogDesignClass_(inDialogDesign: boolean): string { return inDialogDesign ? 'in-dialog-design' : ''; }
diff --git a/chrome/browser/resources/signin/profile_customization/profile_customization_browser_proxy.ts b/chrome/browser/resources/signin/profile_customization/profile_customization_browser_proxy.ts index c1b9855..47a7a75 100644 --- a/chrome/browser/resources/signin/profile_customization/profile_customization_browser_proxy.ts +++ b/chrome/browser/resources/signin/profile_customization/profile_customization_browser_proxy.ts
@@ -23,6 +23,9 @@ // Called when the user clicks the done button. done(profileName: string): void; + + // Called when the user clicks the skip button. + skip(): void; } export class ProfileCustomizationBrowserProxyImpl implements @@ -35,6 +38,10 @@ chrome.send('done', [profileName]); } + skip() { + chrome.send('skip'); + } + static getInstance(): ProfileCustomizationBrowserProxy { return instance || (instance = new ProfileCustomizationBrowserProxyImpl()); }
diff --git a/chrome/browser/resources/tab_search/app.ts b/chrome/browser/resources/tab_search/app.ts index 59ae9b7..f93fd1f 100644 --- a/chrome/browser/resources/tab_search/app.ts +++ b/chrome/browser/resources/tab_search/app.ts
@@ -119,7 +119,7 @@ private searchText_: string; private availableHeight_: number; - filteredItems_: Array<TitleItem|TabData|TabGroupData>; + private filteredItems_: Array<TitleItem|TabData|TabGroupData>; private fuzzySearchOptions_: FuzzySearchOptions<TabData|TabGroupData>; private moveActiveTabToBottom_: boolean; private recentlyClosedDefaultItemDisplayCount_: number;
diff --git a/chrome/browser/ui/app_list/app_service/app_service_app_icon_loader.cc b/chrome/browser/ui/app_list/app_service/app_service_app_icon_loader.cc index 20c9d02..a6c1fc32 100644 --- a/chrome/browser/ui/app_list/app_service/app_service_app_icon_loader.cc +++ b/chrome/browser/ui/app_list/app_service/app_service_app_icon_loader.cc
@@ -188,13 +188,6 @@ } } -void AppServiceAppIconLoader::OnLoadMojomIcon( - const std::string& app_id, - apps::mojom::IconValuePtr icon_value) { - OnLoadIcon(app_id, - apps::ConvertMojomIconValueToIconValue(std::move(icon_value))); -} - bool AppServiceAppIconLoader::Exist(const std::string& app_id) { if (!base::Contains(shelf_app_id_map_, app_id)) { return false;
diff --git a/chrome/browser/ui/app_list/app_service/app_service_app_icon_loader.h b/chrome/browser/ui/app_list/app_service/app_service_app_icon_loader.h index d5b8933..13ae22c4 100644 --- a/chrome/browser/ui/app_list/app_service/app_service_app_icon_loader.h +++ b/chrome/browser/ui/app_list/app_service/app_service_app_icon_loader.h
@@ -54,11 +54,6 @@ // Callback invoked when the icon is loaded. void OnLoadIcon(const std::string& app_id, apps::IconValuePtr icon_value); - // Callback invoked when the icon is loaded. - // TODO(crbug.com/1251501): Remove this mojom callback. - void OnLoadMojomIcon(const std::string& app_id, - apps::mojom::IconValuePtr icon_value); - // Returns true if the app_id does exist in icon_map_. bool Exist(const std::string& app_id);
diff --git a/chrome/browser/ui/app_list/app_service/app_service_app_model_builder_unittest.cc b/chrome/browser/ui/app_list/app_service/app_service_app_model_builder_unittest.cc index 246c862..c4ab347 100644 --- a/chrome/browser/ui/app_list/app_service/app_service_app_model_builder_unittest.cc +++ b/chrome/browser/ui/app_list/app_service/app_service_app_model_builder_unittest.cc
@@ -619,25 +619,23 @@ apps::IconEffects icon_effects = apps::IconEffects::kCrOsStandardIcon; base::RunLoop run_loop; - apps::mojom::IconValuePtr dst_icon; + apps::IconValuePtr dst_icon; apps::LoadIconFromExtension( apps::IconType::kCompressed, ash::SharedAppListConfig::instance().default_grid_icon_dimension(), profile(), kPackagedApp1Id, icon_effects, - apps::IconValueToMojomIconValueCallback( - base::BindLambdaForTesting([&](apps::mojom::IconValuePtr icon) { - dst_icon = std::move(icon); - run_loop.Quit(); - }))); + base::BindLambdaForTesting([&](apps::IconValuePtr icon) { + dst_icon = std::move(icon); + run_loop.Quit(); + })); run_loop.Run(); - ASSERT_FALSE(dst_icon.is_null()); - ASSERT_EQ(apps::mojom::IconType::kCompressed, dst_icon->icon_type); + ASSERT_TRUE(dst_icon); + ASSERT_EQ(apps::IconType::kCompressed, dst_icon->icon_type); ASSERT_FALSE(dst_icon->is_placeholder_icon); - ASSERT_TRUE(dst_icon->compressed.has_value()); - ASSERT_FALSE(dst_icon->compressed.value().empty()); + ASSERT_FALSE(dst_icon->compressed.empty()); - ASSERT_EQ(src_data, dst_icon->compressed.value()); + ASSERT_EQ(src_data, dst_icon->compressed); } // This test adds a web app to the app list.
diff --git a/chrome/browser/ui/ash/shelf/browser_app_shelf_controller.cc b/chrome/browser/ui/ash/shelf/browser_app_shelf_controller.cc index ab483b0..9983ffd 100644 --- a/chrome/browser/ui/ash/shelf/browser_app_shelf_controller.cc +++ b/chrome/browser/ui/ash/shelf/browser_app_shelf_controller.cc
@@ -8,8 +8,6 @@ #include "ash/public/cpp/window_properties.h" #include "base/debug/dump_without_crashing.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/browser_app_instance.h" #include "chrome/browser/apps/app_service/browser_app_instance_registry.h" #include "chrome/browser/ash/crosapi/browser_util.h" @@ -49,6 +47,7 @@ BrowserAppShelfController::BrowserAppShelfController( Profile* profile, + apps::BrowserAppInstanceRegistry& browser_app_instance_registry, ash::ShelfModel& model, ChromeShelfItemFactory& shelf_item_factory, ShelfSpinnerController& shelf_spinner_controller) @@ -56,9 +55,7 @@ model_(model), shelf_item_factory_(shelf_item_factory), shelf_spinner_controller_(shelf_spinner_controller), - browser_app_instance_registry_( - *apps::AppServiceProxyFactory::GetForProfile(profile) - ->BrowserAppInstanceRegistry()) { + browser_app_instance_registry_(browser_app_instance_registry) { CHECK(web_app::IsWebAppsCrosapiEnabled()); registry_observation_.Observe(&browser_app_instance_registry_); shelf_model_observation_.Observe(&model);
diff --git a/chrome/browser/ui/ash/shelf/browser_app_shelf_controller.h b/chrome/browser/ui/ash/shelf/browser_app_shelf_controller.h index 0801bc1..9849a66 100644 --- a/chrome/browser/ui/ash/shelf/browser_app_shelf_controller.h +++ b/chrome/browser/ui/ash/shelf/browser_app_shelf_controller.h
@@ -42,10 +42,12 @@ class BrowserAppShelfController : public apps::BrowserAppInstanceObserver, public ash::ShelfModelObserver { public: - BrowserAppShelfController(Profile* profile, - ash::ShelfModel& model, - ChromeShelfItemFactory& shelf_item_factory, - ShelfSpinnerController& shelf_spinner_controller); + BrowserAppShelfController( + Profile* profile, + apps::BrowserAppInstanceRegistry& browser_app_instance_registry, + ash::ShelfModel& model, + ChromeShelfItemFactory& shelf_item_factory, + ShelfSpinnerController& shelf_spinner_controller); BrowserAppShelfController(const BrowserAppShelfController&) = delete; BrowserAppShelfController& operator=(const BrowserAppShelfController&) =
diff --git a/chrome/browser/ui/ash/shelf/chrome_shelf_controller.cc b/chrome/browser/ui/ash/shelf/chrome_shelf_controller.cc index 072095bb..53d2848 100644 --- a/chrome/browser/ui/ash/shelf/chrome_shelf_controller.cc +++ b/chrome/browser/ui/ash/shelf/chrome_shelf_controller.cc
@@ -256,9 +256,14 @@ std::make_unique<AppServiceAppWindowShelfController>(this); app_service_app_window_controller_ = app_service_controller.get(); app_window_controllers_.emplace_back(std::move(app_service_controller)); - if (web_app::IsWebAppsCrosapiEnabled()) { + if (web_app::IsWebAppsCrosapiEnabled() && + apps::AppServiceProxyFactory::IsAppServiceAvailableForProfile(profile)) { + apps::AppServiceProxy* proxy = + apps::AppServiceProxyFactory::GetForProfile(profile); + DCHECK(proxy); browser_app_shelf_controller_ = std::make_unique<BrowserAppShelfController>( - profile, *model_, *shelf_item_factory_, *shelf_spinner_controller_); + profile, *proxy->BrowserAppInstanceRegistry(), *model_, + *shelf_item_factory_, *shelf_spinner_controller_); } else { // Create the browser monitor which will inform the shelf of status changes. browser_status_monitor_ = std::make_unique<BrowserStatusMonitor>(this);
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 9612edb3..f66efaa 100644 --- a/chrome/browser/ui/ash/shelf/chrome_shelf_controller_unittest.cc +++ b/chrome/browser/ui/ash/shelf/chrome_shelf_controller_unittest.cc
@@ -532,13 +532,15 @@ virtual bool StartWebAppProviderForMainProfile() const { return true; } void StartWebAppProvider(Profile* profile) { - auto system_web_app_manager = - std::make_unique<web_app::TestSystemWebAppManager>(profile); - auto* provider = web_app::FakeWebAppProvider::Get(profile); - provider->SetSystemWebAppManager(std::move(system_web_app_manager)); + + auto* system_web_app_manager = + web_app::TestSystemWebAppManager::Get(profile); + provider->SetRunSubsystemStartupTasks(true); provider->Start(); + + system_web_app_manager->ScheduleStart(); } ui::BaseWindow* GetLastActiveWindowForItemController( @@ -1697,6 +1699,20 @@ EXPECT_FALSE(proxy()->InstanceRegistry().ContainsAppId(kDummyAppId)); } +// Regression test for crash. crbug.com/1296949 +TEST_F(ChromeShelfControllerLacrosPrimaryTest, WithoutAppService) { + Profile* const controller_profile = profile()->GetOffTheRecordProfile( + Profile::OTRProfileID::CreateUniqueForTesting(), + /*create_if_needed=*/true); + EXPECT_FALSE(apps::AppServiceProxyFactory::IsAppServiceAvailableForProfile( + controller_profile)); + + ChromeShelfPrefs::SkipPinnedAppsFromSyncForTest(); + ash::ShelfModel model; + FakeChromeShelfItemFactory shelf_item_factory(controller_profile); + ChromeShelfController(controller_profile, &model, &shelf_item_factory).Init(); +} + TEST_F(ChromeShelfControllerWithArcTest, ArcAppsHiddenFromLaunchCanBePinned) { InitShelfController();
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc index ffd7b80..458af71 100644 --- a/chrome/browser/ui/browser.cc +++ b/chrome/browser/ui/browser.cc
@@ -34,7 +34,6 @@ #include "build/chromeos_buildflags.h" #include "chrome/app/chrome_command_ids.h" #include "chrome/browser/app_mode/app_mode_utils.h" -#include "chrome/browser/autofill/personal_data_manager_factory.h" #include "chrome/browser/background/background_contents.h" #include "chrome/browser/background/background_contents_service.h" #include "chrome/browser/background/background_contents_service_factory.h" @@ -90,7 +89,6 @@ #include "chrome/browser/themes/theme_service.h" #include "chrome/browser/themes/theme_service_factory.h" #include "chrome/browser/translate/chrome_translate_client.h" -#include "chrome/browser/ui/autofill/chrome_autofill_client.h" #include "chrome/browser/ui/blocked_content/chrome_popup_navigation_delegate.h" #include "chrome/browser/ui/blocked_content/framebust_block_tab_helper.h" #include "chrome/browser/ui/bookmarks/bookmark_tab_helper.h" @@ -251,7 +249,6 @@ #include <shellapi.h> #include "chrome/browser/ui/view_ids.h" -#include "components/autofill/core/browser/autofill_ie_toolbar_import_win.h" #include "ui/base/win/shell.h" #endif // BUILDFLAG(IS_WIN) @@ -558,15 +555,6 @@ if (service) service->WindowOpened(this); - // TODO(beng): move to ChromeBrowserMain: - if (first_run::ShouldDoPersonalDataManagerFirstRun()) { -#if BUILDFLAG(IS_WIN) - // Notify PDM that this is a first run. - ImportAutofillDataWin( - autofill::PersonalDataManagerFactory::GetForProfile(profile_)); -#endif // BUILDFLAG(IS_WIN) - } - exclusive_access_manager_ = std::make_unique<ExclusiveAccessManager>( window_->GetExclusiveAccessContext());
diff --git a/chrome/browser/ui/signin_intercept_first_run_experience_dialog.cc b/chrome/browser/ui/signin_intercept_first_run_experience_dialog.cc index c8372f72..d59a15de 100644 --- a/chrome/browser/ui/signin_intercept_first_run_experience_dialog.cc +++ b/chrome/browser/ui/signin_intercept_first_run_experience_dialog.cc
@@ -373,7 +373,7 @@ DCHECK(web_ui); web_ui->Initialize( base::BindOnce(&SigninInterceptFirstRunExperienceDialog:: - OnProfileCustomizationDoneButtonClicked, + ProfileCustomizationCloseOnCompletion, // Unretained is fine because `this` owns the web contents. base::Unretained(this))); } @@ -397,7 +397,15 @@ } void SigninInterceptFirstRunExperienceDialog:: - OnProfileCustomizationDoneButtonClicked() { - RecordDialogEvent(DialogEvent::kProfileCustomizationClickDone); + ProfileCustomizationCloseOnCompletion( + ProfileCustomizationHandler::CustomizationResult customization_result) { + switch (customization_result) { + case ProfileCustomizationHandler::CustomizationResult::kDone: + RecordDialogEvent(DialogEvent::kProfileCustomizationClickDone); + break; + case ProfileCustomizationHandler::CustomizationResult::kSkip: + RecordDialogEvent(DialogEvent::kProfileCustomizationClickSkip); + break; + } DoNextStep(Step::kProfileCustomization, Step::kProfileSwitchIPHAndCloseModal); }
diff --git a/chrome/browser/ui/signin_intercept_first_run_experience_dialog.h b/chrome/browser/ui/signin_intercept_first_run_experience_dialog.h index aa37dcd..6def12d 100644 --- a/chrome/browser/ui/signin_intercept_first_run_experience_dialog.h +++ b/chrome/browser/ui/signin_intercept_first_run_experience_dialog.h
@@ -12,6 +12,7 @@ #include "chrome/browser/ui/signin/profile_customization_synced_theme_waiter.h" #include "chrome/browser/ui/signin_modal_dialog.h" #include "chrome/browser/ui/signin_view_controller_delegate.h" +#include "chrome/browser/ui/webui/signin/profile_customization_handler.h" #include "google_apis/gaia/core_account_id.h" class Browser; @@ -49,8 +50,10 @@ kShowProfileCustomization = 5, // The user completed profile customization. kProfileCustomizationClickDone = 6, + // The user skipped profile customization. + kProfileCustomizationClickSkip = 7, - kMaxValue = kProfileCustomizationClickDone + kMaxValue = kProfileCustomizationClickSkip }; explicit SigninInterceptFirstRunExperienceDialog( @@ -103,7 +106,8 @@ void PreloadProfileCustomizationUI(); void OnSyncedThemeReady( ProfileCustomizationSyncedThemeWaiter::Outcome outcome); - void OnProfileCustomizationDoneButtonClicked(); + void ProfileCustomizationCloseOnCompletion( + ProfileCustomizationHandler::CustomizationResult customization_result); const raw_ptr<Browser> browser_; const CoreAccountId account_id_;
diff --git a/chrome/browser/ui/signin_intercept_first_run_experience_dialog_browsertest.cc b/chrome/browser/ui/signin_intercept_first_run_experience_dialog_browsertest.cc index b144996..403f6291 100644 --- a/chrome/browser/ui/signin_intercept_first_run_experience_dialog_browsertest.cc +++ b/chrome/browser/ui/signin_intercept_first_run_experience_dialog_browsertest.cc
@@ -24,6 +24,7 @@ #include "chrome/browser/ui/views/profiles/avatar_toolbar_button.h" #include "chrome/browser/ui/webui/signin/login_ui_service.h" #include "chrome/browser/ui/webui/signin/login_ui_service_factory.h" +#include "chrome/browser/ui/webui/signin/profile_customization_handler.h" #include "chrome/browser/ui/webui/signin/turn_sync_on_helper.h" #include "chrome/test/base/in_process_browser_test.h" #include "components/feature_engagement/public/feature_constants.h" @@ -196,8 +197,14 @@ ->SyncConfirmationUIClosed(result); } - void SimulateProfileCustomizationUIClosing() { - dialog()->OnProfileCustomizationDoneButtonClicked(); + void SimulateProfileCustomizationDoneButtonClicked() { + dialog()->ProfileCustomizationCloseOnCompletion( + ProfileCustomizationHandler::CustomizationResult::kDone); + } + + void SimulateProfileCustomizationSkipButtonClicked() { + dialog()->ProfileCustomizationCloseOnCompletion( + ProfileCustomizationHandler::CustomizationResult::kSkip); } void ExpectRecordedEvents(DialogEventSet events) { @@ -325,7 +332,7 @@ dialog()->GetModalDialogWebContentsForTesting()->GetLastCommittedURL(), kProfileCustomizationUrl); - SimulateProfileCustomizationUIClosing(); + SimulateProfileCustomizationDoneButtonClicked(); EXPECT_FALSE(controller()->ShowsModalDialog()); EXPECT_TRUE(ProfileSwitchPromoHasBeenShown()); ExpectRecordedEvents({DialogEvent::kStart, DialogEvent::kShowSyncConfirmation, @@ -335,6 +342,55 @@ ExpectSigninHistogramsRecorded(); } +// Goes through all steps of the fre dialog and skips profile customization. +// The user enables sync. +IN_PROC_BROWSER_TEST_F(SigninInterceptFirstRunExperienceDialogBrowserTest, + AcceptSync_SkipCustomization) { + SignIn(kConsumerEmail); + content::TestNavigationObserver sync_confirmation_observer( + kSyncConfirmationUrl); + content::TestNavigationObserver profile_customization_observer( + kProfileCustomizationUrl); + sync_confirmation_observer.StartWatchingNewWebContents(); + profile_customization_observer.StartWatchingNewWebContents(); + + controller()->ShowModalInterceptFirstRunExperienceDialog( + account_id(), /* is_forced_intercept = */ false); + EXPECT_TRUE(controller()->ShowsModalDialog()); + sync_confirmation_observer.Wait(); + EXPECT_EQ( + dialog()->GetModalDialogWebContentsForTesting()->GetLastCommittedURL(), + kSyncConfirmationUrl); + + SimulateSyncConfirmationUIClosing(LoginUIService::SYNC_WITH_DEFAULT_SETTINGS); + ExpectPrimaryAccountWithExactConsentLevel(signin::ConsentLevel::kSync); + // The dialog still shows the sync confirmation while waiting for the synced + // theme to be applied. + EXPECT_TRUE(controller()->ShowsModalDialog()); + EXPECT_EQ( + dialog()->GetModalDialogWebContentsForTesting()->GetLastCommittedURL(), + kSyncConfirmationUrl); + + theme_service()->GetThemeSyncableService()->NotifyOnSyncStartedForTesting( + ThemeSyncableService::ThemeSyncState::kApplied); + + profile_customization_observer.Wait(); + EXPECT_EQ( + dialog()->GetModalDialogWebContentsForTesting()->GetLastCommittedURL(), + kProfileCustomizationUrl); + + SimulateProfileCustomizationSkipButtonClicked(); + EXPECT_FALSE(controller()->ShowsModalDialog()); + EXPECT_TRUE(ProfileSwitchPromoHasBeenShown()); + ExpectRecordedEvents({DialogEvent::kStart, DialogEvent::kShowSyncConfirmation, + DialogEvent::kSyncConfirmationClickConfirm, + DialogEvent::kShowProfileCustomization, + DialogEvent::kProfileCustomizationClickSkip}); + ExpectSigninHistogramsRecorded(); + // TODO(https://crbug.com/1282157): test that the Skip button undoes the + // changes in the theme color and the profile name. +} + // The user enables sync and has a synced extension theme. Tests that the dialog // waits on the sync confirmation page until the extension theme is applied. IN_PROC_BROWSER_TEST_F(SigninInterceptFirstRunExperienceDialogBrowserTest, @@ -383,7 +439,7 @@ dialog()->GetModalDialogWebContentsForTesting()->GetLastCommittedURL(), kProfileCustomizationUrl); - SimulateProfileCustomizationUIClosing(); + SimulateProfileCustomizationDoneButtonClicked(); EXPECT_FALSE(controller()->ShowsModalDialog()); EXPECT_TRUE(ProfileSwitchPromoHasBeenShown()); } @@ -446,7 +502,7 @@ dialog()->GetModalDialogWebContentsForTesting()->GetLastCommittedURL(), kProfileCustomizationUrl); - SimulateProfileCustomizationUIClosing(); + SimulateProfileCustomizationDoneButtonClicked(); EXPECT_FALSE(controller()->ShowsModalDialog()); EXPECT_TRUE(ProfileSwitchPromoHasBeenShown()); ExpectRecordedEvents({DialogEvent::kStart, DialogEvent::kShowSyncConfirmation, @@ -582,7 +638,7 @@ // Sync consent is granted even though Sync cannot be enabled. ExpectPrimaryAccountWithExactConsentLevel(signin::ConsentLevel::kSync); - SimulateProfileCustomizationUIClosing(); + SimulateProfileCustomizationDoneButtonClicked(); EXPECT_FALSE(controller()->ShowsModalDialog()); EXPECT_TRUE(ProfileSwitchPromoHasBeenShown()); ExpectRecordedEvents({DialogEvent::kStart, @@ -609,7 +665,7 @@ dialog()->GetModalDialogWebContentsForTesting()->GetLastCommittedURL(), kProfileCustomizationUrl); - SimulateProfileCustomizationUIClosing(); + SimulateProfileCustomizationDoneButtonClicked(); EXPECT_FALSE(controller()->ShowsModalDialog()); EXPECT_TRUE(ProfileSwitchPromoHasBeenShown()); ExpectRecordedEvents({DialogEvent::kStart,
diff --git a/chrome/browser/ui/views/extensions/extension_popup_interactive_uitest.cc b/chrome/browser/ui/views/extensions/extension_popup_interactive_uitest.cc index 6eac1ee..57008e3 100644 --- a/chrome/browser/ui/views/extensions/extension_popup_interactive_uitest.cc +++ b/chrome/browser/ui/views/extensions/extension_popup_interactive_uitest.cc
@@ -125,9 +125,9 @@ // The permission may be shown using a chip UI instead of a popped-up bubble. // If so, click on the chip to open the bubble. BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser()); - PermissionChip* chip = browser_view->toolbar()->location_bar()->chip(); - if (chip) { - views::test::ButtonTestApi(chip->button()) + LocationBarView* lbv = browser_view->toolbar()->location_bar(); + if (lbv->IsChipActive() && !lbv->chip()->IsBubbleShowing()) { + views::test::ButtonTestApi(lbv->chip()->button()) .NotifyClick(ui::MouseEvent(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, 0));
diff --git a/chrome/browser/ui/views/extensions/extensions_request_access_button_hover_card_browsertest.cc b/chrome/browser/ui/views/extensions/extensions_request_access_button_hover_card_browsertest.cc index 046b4a2..5d2a58da 100644 --- a/chrome/browser/ui/views/extensions/extensions_request_access_button_hover_card_browsertest.cc +++ b/chrome/browser/ui/views/extensions/extensions_request_access_button_hover_card_browsertest.cc
@@ -6,6 +6,7 @@ #include "chrome/browser/ui/toolbar/test_toolbar_action_view_controller.h" #include "chrome/browser/ui/views/extensions/extensions_dialogs_browsertest.h" +#include "chrome/browser/ui/views/extensions/extensions_request_access_button.h" #include "chrome/browser/ui/views/extensions/extensions_toolbar_container.h" #include "content/public/test/browser_test.h" #include "extensions/common/extension.h" @@ -31,11 +32,10 @@ auto controllerA = std::make_unique<TestToolbarActionViewController>("A"); std::vector<ToolbarActionViewController*> extensions_requesting_access; extensions_requesting_access.push_back(controllerA.get()); - extensions_container() - ->GetExtensionsToolbarControls() - ->UpdateRequestAccessButton(extensions_requesting_access); + request_access_button()->UpdateExtensionsRequestingAccess( + extensions_requesting_access); + request_access_button()->SetVisible(true); - EXPECT_TRUE(request_access_button()->GetVisible()); request_access_button()->MaybeShowHoverCard(); }
diff --git a/chrome/browser/ui/views/extensions/extensions_toolbar_container.cc b/chrome/browser/ui/views/extensions/extensions_toolbar_container.cc index 64e065a71..2007bef 100644 --- a/chrome/browser/ui/views/extensions/extensions_toolbar_container.cc +++ b/chrome/browser/ui/views/extensions/extensions_toolbar_container.cc
@@ -120,6 +120,8 @@ SetVisible(false); model_observation_.Observe(model_.get()); + permissions_manager_observation_.Observe( + extensions::PermissionsManager::Get(browser_->profile())); const views::FlexSpecification hide_icon_flex_specification = views::FlexSpecification(views::LayoutOrientation::kHorizontal, @@ -536,6 +538,11 @@ drop_weak_ptr_factory_.InvalidateWeakPtrs(); } +void ExtensionsToolbarContainer::UserPermissionsSettingsChanged( + const extensions::PermissionsManager::UserPermissionsSettings& settings) { + UpdateControlsVisibility(); +} + void ExtensionsToolbarContainer::ReorderViews() { const auto& pinned_action_ids = model_->pinned_action_ids(); for (size_t i = 0; i < pinned_action_ids.size(); ++i) @@ -864,17 +871,14 @@ return; content::WebContents* web_contents = GetCurrentWebContents(); + if (!web_contents) + return; - extensions_controls_->UpdateSiteAccessButtonVisibility( - ExtensionActionViewController::AnyActionHasCurrentSiteAccess( - actions_, web_contents)); - - std::vector<ToolbarActionViewController*> extensions_requesting_access; - for (const auto& action : actions_) { - if (action->IsRequestingSiteAccess(web_contents)) - extensions_requesting_access.push_back(action.get()); - } - extensions_controls_->UpdateRequestAccessButton(extensions_requesting_access); + extensions::PermissionsManager::UserSiteSetting site_setting = + extensions::PermissionsManager::Get(browser_->profile()) + ->GetUserSiteSetting( + web_contents->GetMainFrame()->GetLastCommittedOrigin()); + extensions_controls_->UpdateControls(actions_, site_setting, web_contents); } BEGIN_METADATA(ExtensionsToolbarContainer, ToolbarIconContainerView)
diff --git a/chrome/browser/ui/views/extensions/extensions_toolbar_container.h b/chrome/browser/ui/views/extensions/extensions_toolbar_container.h index 4955db35..e21c435 100644 --- a/chrome/browser/ui/views/extensions/extensions_toolbar_container.h +++ b/chrome/browser/ui/views/extensions/extensions_toolbar_container.h
@@ -31,12 +31,14 @@ // Container for extensions shown in the toolbar. These include pinned // extensions and extensions that are 'popped out' transitively to show dialogs // or be called out to the user. -class ExtensionsToolbarContainer : public ToolbarIconContainerView, - public ExtensionsContainer, - public TabStripModelObserver, - public ToolbarActionsModel::Observer, - public ToolbarActionView::Delegate, - public views::WidgetObserver { +class ExtensionsToolbarContainer + : public ToolbarIconContainerView, + public ExtensionsContainer, + public TabStripModelObserver, + public ToolbarActionsModel::Observer, + public ToolbarActionView::Delegate, + public views::WidgetObserver, + public extensions::PermissionsManager::Observer { public: METADATA_HEADER(ExtensionsToolbarContainer); @@ -239,6 +241,11 @@ void OnToolbarModelInitialized() override; void OnToolbarPinnedActionsChanged() override; + // PermissionsManager::Observer: + void UserPermissionsSettingsChanged( + const extensions::PermissionsManager::UserPermissionsSettings& settings) + override; + // views::WidgetObserver: void OnWidgetDestroying(views::Widget* widget) override; @@ -255,8 +262,13 @@ const raw_ptr<Browser> browser_; const raw_ptr<ToolbarActionsModel> model_; + base::ScopedObservation<ToolbarActionsModel, ToolbarActionsModel::Observer> model_observation_{this}; + base::ScopedObservation<extensions::PermissionsManager, + extensions::PermissionsManager::Observer> + permissions_manager_observation_{this}; + // TODO(emiliapaz): Remove `extensions_button_` once // `extensions_features::kExtensionsMenuAccessControl` experiment is released. // Exactly one of `extensions_button_ and `extensions_controls_` is created;
diff --git a/chrome/browser/ui/views/extensions/extensions_toolbar_controls.cc b/chrome/browser/ui/views/extensions/extensions_toolbar_controls.cc index 26a6c0a4..420c29bc 100644 --- a/chrome/browser/ui/views/extensions/extensions_toolbar_controls.cc +++ b/chrome/browser/ui/views/extensions/extensions_toolbar_controls.cc
@@ -6,9 +6,11 @@ #include <memory> +#include "chrome/browser/ui/extensions/extension_action_view_controller.h" #include "chrome/browser/ui/toolbar/toolbar_action_view_controller.h" #include "chrome/browser/ui/views/extensions/extensions_request_access_button.h" #include "chrome/browser/ui/views/extensions/extensions_toolbar_button.h" +#include "content/public/browser/web_contents.h" #include "ui/base/metadata/metadata_impl_macros.h" ExtensionsToolbarControls::ExtensionsToolbarControls( @@ -29,15 +31,48 @@ void ExtensionsToolbarControls::UpdateAllIcons() {} -void ExtensionsToolbarControls::UpdateSiteAccessButtonVisibility( - bool visibility) { - site_access_button_->SetVisible(visibility); +void ExtensionsToolbarControls::UpdateControls( + const std::vector<std::unique_ptr<ToolbarActionViewController>>& actions, + extensions::PermissionsManager::UserSiteSetting site_setting, + content::WebContents* current_web_contents) { + UpdateSiteAccessButton(actions, current_web_contents); + UpdateRequestAccessButton(actions, site_setting, current_web_contents); - ResetLayout(); + // Resets the layout since layout animation does not handle host view + // visibility changing. This should be called after any visibility changes. + GetAnimatingLayoutManager()->ResetLayout(); +} + +void ExtensionsToolbarControls::UpdateSiteAccessButton( + const std::vector<std::unique_ptr<ToolbarActionViewController>>& actions, + content::WebContents* web_contents) { + site_access_button_->SetVisible( + ExtensionActionViewController::AnyActionHasCurrentSiteAccess( + actions, web_contents)); } void ExtensionsToolbarControls::UpdateRequestAccessButton( - std::vector<ToolbarActionViewController*> extensions_requesting_access) { + const std::vector<std::unique_ptr<ToolbarActionViewController>>& actions, + extensions::PermissionsManager::UserSiteSetting site_setting, + content::WebContents* web_contents) { + // User site settings takes precedence over extension site access. If the user + // has allowed or blocked all extensions, individual extensions cannot grant + // access to the page and therefore the request access button is not + // displayed. + if (site_setting == extensions::PermissionsManager::UserSiteSetting:: + kGrantAllExtensions || + site_setting == extensions::PermissionsManager::UserSiteSetting:: + kBlockAllExtensions) { + request_access_button_->SetVisible(false); + return; + } + + // Request access button is displayed if any extension requests access. + std::vector<ToolbarActionViewController*> extensions_requesting_access; + for (const auto& action : actions) { + if (action->IsRequestingSiteAccess(web_contents)) + extensions_requesting_access.push_back(action.get()); + } if (extensions_requesting_access.empty()) { request_access_button_->SetVisible(false); } else { @@ -50,12 +85,6 @@ extensions_requesting_access); request_access_button_->SetVisible(true); } - - ResetLayout(); -} - -void ExtensionsToolbarControls::ResetLayout() { - GetAnimatingLayoutManager()->ResetLayout(); } BEGIN_METADATA(ExtensionsToolbarControls, ToolbarIconContainerView)
diff --git a/chrome/browser/ui/views/extensions/extensions_toolbar_controls.h b/chrome/browser/ui/views/extensions/extensions_toolbar_controls.h index 910c2aa..8f912d0 100644 --- a/chrome/browser/ui/views/extensions/extensions_toolbar_controls.h +++ b/chrome/browser/ui/views/extensions/extensions_toolbar_controls.h
@@ -8,9 +8,12 @@ #include <memory> #include "base/memory/raw_ptr.h" -#include "chrome/browser/ui/views/extensions/extensions_request_access_button.h" #include "chrome/browser/ui/views/toolbar/toolbar_icon_container_view.h" -#include "content/public/browser/web_contents.h" +#include "extensions/browser/permissions_manager.h" + +namespace content { +class WebContents; +} class ExtensionsToolbarButton; class ExtensionsRequestAccessButton; @@ -41,22 +44,29 @@ return request_access_button_; } - // Updates `site_access_button_` visibility to the given one. - void UpdateSiteAccessButtonVisibility(bool visibility); - - // Updates `request_access_button_` visibility and content based on the given - // `count_requesting_extensions`. - void UpdateRequestAccessButton( - std::vector<ToolbarActionViewController*> extensions_requesting_access); - - // Resets the layout since layout animation does not handle host view - // visibility changing. This should be called after any visibility changes. - void ResetLayout(); + // Update the controls given `actions` and the user `site_setting` in the + // `current_web_contents`. + void UpdateControls( + const std::vector<std::unique_ptr<ToolbarActionViewController>>& actions, + extensions::PermissionsManager::UserSiteSetting site_setting, + content::WebContents* current_web_contents); // ToolbarIconContainerView: void UpdateAllIcons() override; private: + // Updates `site_access_button_` visibility given `actions` in `web_contents`. + void UpdateSiteAccessButton( + const std::vector<std::unique_ptr<ToolbarActionViewController>>& actions, + content::WebContents* web_contents); + + // Updates `request_access_button_` visibility given the user `site_setting` + // and `actions` in `web_contents`. + void UpdateRequestAccessButton( + const std::vector<std::unique_ptr<ToolbarActionViewController>>& actions, + extensions::PermissionsManager::UserSiteSetting site_setting, + content::WebContents* web_contents); + const raw_ptr<ExtensionsRequestAccessButton> request_access_button_; const raw_ptr<ExtensionsToolbarButton> site_access_button_; const raw_ptr<ExtensionsToolbarButton> extensions_button_;
diff --git a/chrome/browser/ui/views/extensions/extensions_toolbar_controls_unittest.cc b/chrome/browser/ui/views/extensions/extensions_toolbar_controls_unittest.cc index 28cdd8e..0aa9b7f1 100644 --- a/chrome/browser/ui/views/extensions/extensions_toolbar_controls_unittest.cc +++ b/chrome/browser/ui/views/extensions/extensions_toolbar_controls_unittest.cc
@@ -5,6 +5,8 @@ #include "chrome/browser/ui/views/extensions/extensions_toolbar_controls.h" #include "chrome/browser/extensions/extension_context_menu_model.h" +#include "chrome/browser/extensions/site_permissions_helper.h" +#include "chrome/browser/ui/views/extensions/extensions_request_access_button.h" #include "chrome/browser/ui/views/extensions/extensions_toolbar_button.h" #include "chrome/browser/ui/views/extensions/extensions_toolbar_container.h" #include "chrome/browser/ui/views/extensions/extensions_toolbar_unittest.h" @@ -12,7 +14,9 @@ #include "content/public/browser/notification_service.h" #include "extensions/browser/notification_types.h" #include "extensions/common/extension_features.h" +#include "extensions/test/permissions_manager_waiter.h" #include "ui/views/view_utils.h" +#include "url/origin.h" class ExtensionsToolbarControlsUnitTest : public ExtensionsToolbarUnitTest { public: @@ -306,3 +310,60 @@ InstallExtensionWithPermissions("Extension", {"activeTab"}); EXPECT_FALSE(IsRequestAccessButtonVisible()); } + +// Test that request access button is visible based on the user site setting +// selected. +TEST_F(ExtensionsToolbarControlsUnitTest, + RequestAccessButtonVisibility_UserSiteSetting) { + content::WebContentsTester* web_contents_tester = + AddWebContentsAndGetTester(); + const GURL url("http://www.url.com"); + auto url_origin = url::Origin::Create(url); + + // Install an extension and withhold permissions so request access button can + // be visible. + auto extension = + InstallExtensionWithHostPermissions("Extension", {"<all_urls>"}); + WithholdHostPermissions(extension.get()); + + web_contents_tester->NavigateAndCommit(url); + WaitForAnimation(); + + // A site has "customize by extensions" site setting by default, + ASSERT_EQ( + GetUserSiteSetting(url), + extensions::PermissionsManager::UserSiteSetting::kCustomizeByExtension); + EXPECT_TRUE(IsRequestAccessButtonVisible()); + + auto* manager = extensions::PermissionsManager::Get(profile()); + { + // Request access button is not visible in permitted sites. + extensions::PermissionsManagerWaiter manager_waiter( + extensions::PermissionsManager::Get(profile())); + manager->AddUserPermittedSite(url_origin); + manager_waiter.WaitForPermissionsChange(); + WaitForAnimation(); + EXPECT_FALSE(IsRequestAccessButtonVisible()); + } + + { + // Request access button is not visible in restricted sites. + extensions::PermissionsManagerWaiter manager_waiter( + extensions::PermissionsManager::Get(profile())); + manager->AddUserRestrictedSite(url_origin); + manager_waiter.WaitForPermissionsChange(); + WaitForAnimation(); + EXPECT_FALSE(IsRequestAccessButtonVisible()); + } + + { + // Request acesss button is visible if site is not permitted or restricted, + // and at least one extension is requesting access. + extensions::PermissionsManagerWaiter manager_waiter( + extensions::PermissionsManager::Get(profile())); + manager->RemoveUserRestrictedSite(url_origin); + manager_waiter.WaitForPermissionsChange(); + WaitForAnimation(); + EXPECT_TRUE(IsRequestAccessButtonVisible()); + } +}
diff --git a/chrome/browser/ui/views/permission_bubble/permission_bubble_interactive_uitest.cc b/chrome/browser/ui/views/permission_bubble/permission_bubble_interactive_uitest.cc index 4928dc5f..0eb630f 100644 --- a/chrome/browser/ui/views/permission_bubble/permission_bubble_interactive_uitest.cc +++ b/chrome/browser/ui/views/permission_bubble/permission_bubble_interactive_uitest.cc
@@ -108,9 +108,9 @@ // click on the chip to trigger showing the prompt. BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser()); - PermissionChip* chip = browser_view->toolbar()->location_bar()->chip(); - if (chip) { - views::test::ButtonTestApi(chip->button()) + LocationBarView* lbv = browser_view->toolbar()->location_bar(); + if (lbv->IsChipActive() && !lbv->chip()->IsBubbleShowing()) { + views::test::ButtonTestApi(lbv->chip()->button()) .NotifyClick(ui::MouseEvent(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, 0)); @@ -162,8 +162,7 @@ EXPECT_EQ(0u, views::test::WidgetTest::GetAllWidgets().size()); } -#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_CHROMEOS_ASH) -// TODO(crbug.com/1336247): Flaky on Chrome OS. +#if BUILDFLAG(IS_MAC) // TODO(crbug.com/1324444): For Mac builders, the test fails after activating // the browser and cannot spot the widget. Needs investigation and fix. #define MAYBE_SwitchTabs DISABLED_SwitchTabs
diff --git a/chrome/browser/ui/views/permission_bubble/permission_chip_interactive_test.cc b/chrome/browser/ui/views/permission_bubble/permission_chip_interactive_test.cc index 1bee088..ef418501 100644 --- a/chrome/browser/ui/views/permission_bubble/permission_chip_interactive_test.cc +++ b/chrome/browser/ui/views/permission_bubble/permission_chip_interactive_test.cc
@@ -97,11 +97,15 @@ PermissionChip* GetChip() { BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser()); - return browser_view->toolbar()->location_bar()->chip(); + LocationBarView* lbv = browser_view->toolbar()->location_bar(); + + return lbv->chip(); } void ClickOnChip(PermissionChip* chip) { ASSERT_TRUE(chip != nullptr); + ASSERT_TRUE(chip->IsActive()); + ASSERT_TRUE(!chip->IsBubbleShowing()); views::test::ButtonTestApi(chip->button()) .NotifyClick(ui::MouseEvent(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), ui::EventTimeForNow(),
diff --git a/chrome/browser/ui/views/permission_bubble/permission_prompt_impl.cc b/chrome/browser/ui/views/permission_bubble/permission_prompt_impl.cc index acbfad10..ec348f2 100644 --- a/chrome/browser/ui/views/permission_bubble/permission_prompt_impl.cc +++ b/chrome/browser/ui/views/permission_bubble/permission_prompt_impl.cc
@@ -255,7 +255,7 @@ LocationBarView* lbv = GetLocationBarView(); - return lbv->chip() + return lbv->IsChipActive() && lbv->chip()->IsBubbleShowing() ? lbv->chip()->GetPromptBubbleWidgetForTesting() // IN-TEST : nullptr; }
diff --git a/chrome/browser/ui/views/profiles/profile_customization_bubble_view.cc b/chrome/browser/ui/views/profiles/profile_customization_bubble_view.cc index 93a4dcc..46517529 100644 --- a/chrome/browser/ui/views/profiles/profile_customization_bubble_view.cc +++ b/chrome/browser/ui/views/profiles/profile_customization_bubble_view.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/ui/views/profiles/profile_customization_bubble_view.h" +#include "base/callback_helpers.h" #include "base/feature_list.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/signin/dice_web_signin_interceptor_delegate.h" @@ -62,7 +63,7 @@ SetInitiallyFocusedView(web_view.get()); DCHECK(web_ui); web_ui->Initialize( - base::BindOnce(&ProfileCustomizationBubbleView::OnDoneButtonClicked, + base::BindOnce(&ProfileCustomizationBubbleView::OnCompletionButtonClicked, // Unretained is fine because this owns the web view. base::Unretained(this))); AddChildView(std::move(web_view)); @@ -72,11 +73,20 @@ SetLayoutManager(std::make_unique<views::FillLayout>()); } -void ProfileCustomizationBubbleView::OnDoneButtonClicked() { +void ProfileCustomizationBubbleView::OnCompletionButtonClicked( + ProfileCustomizationHandler::CustomizationResult customization_result) { BrowserView* browser_view = BrowserView::GetBrowserViewForNativeWindow( GetAnchorView()->GetWidget()->GetNativeWindow()); - GetWidget()->CloseWithReason( - views::Widget::ClosedReason::kCloseButtonClicked); + views::Widget::ClosedReason closed_reason; + switch (customization_result) { + case ProfileCustomizationHandler::CustomizationResult::kDone: + closed_reason = views::Widget::ClosedReason::kAcceptButtonClicked; + break; + case ProfileCustomizationHandler::CustomizationResult::kSkip: + closed_reason = views::Widget::ClosedReason::kCancelButtonClicked; + break; + } + GetWidget()->CloseWithReason(closed_reason); browser_view->MaybeShowProfileSwitchIPH(); }
diff --git a/chrome/browser/ui/views/profiles/profile_customization_bubble_view.h b/chrome/browser/ui/views/profiles/profile_customization_bubble_view.h index b1a85047..ea1ae53 100644 --- a/chrome/browser/ui/views/profiles/profile_customization_bubble_view.h +++ b/chrome/browser/ui/views/profiles/profile_customization_bubble_view.h
@@ -6,6 +6,7 @@ #define CHROME_BROWSER_UI_VIEWS_PROFILES_PROFILE_CUSTOMIZATION_BUBBLE_VIEW_H_ #include "base/gtest_prod_util.h" +#include "chrome/browser/ui/webui/signin/profile_customization_handler.h" #include "ui/base/metadata/metadata_header_macros.h" #include "ui/views/bubble/bubble_dialog_delegate_view.h" @@ -37,8 +38,9 @@ ProfileCustomizationBubbleView(Profile* profile, views::View* anchor_view); - // Called when the "Done" button is clicked in the inner WebUI. - void OnDoneButtonClicked(); + // Called when the "Done" or "Skip" button is clicked in the inner WebUI. + void OnCompletionButtonClicked( + ProfileCustomizationHandler::CustomizationResult customization_result); }; #endif // CHROME_BROWSER_UI_VIEWS_PROFILES_PROFILE_CUSTOMIZATION_BUBBLE_VIEW_H_
diff --git a/chrome/browser/ui/views/profiles/profile_customization_bubble_view_browsertest.cc b/chrome/browser/ui/views/profiles/profile_customization_bubble_view_browsertest.cc index 1a71b99..8a390c65 100644 --- a/chrome/browser/ui/views/profiles/profile_customization_bubble_view_browsertest.cc +++ b/chrome/browser/ui/views/profiles/profile_customization_bubble_view_browsertest.cc
@@ -18,6 +18,7 @@ #include "chrome/browser/ui/views/frame/toolbar_button_provider.h" #include "chrome/browser/ui/views/profiles/avatar_toolbar_button.h" #include "chrome/browser/ui/views/user_education/browser_feature_promo_controller.h" +#include "chrome/browser/ui/webui/signin/profile_customization_handler.h" #include "components/feature_engagement/public/feature_constants.h" #include "components/feature_engagement/public/tracker.h" #include "components/feature_engagement/test/test_tracker.h" @@ -99,7 +100,8 @@ tracker->GetTriggerState(feature_engagement::kIPHProfileSwitchFeature), feature_engagement::Tracker::TriggerState::HAS_BEEN_DISPLAYED); - bubble->OnDoneButtonClicked(); + bubble->OnCompletionButtonClicked( + ProfileCustomizationHandler::CustomizationResult::kDone); base::RunLoop loop; tracker->AddOnInitializedCallback(
diff --git a/chrome/browser/ui/views/profiles/signin_view_controller_delegate_views.cc b/chrome/browser/ui/views/profiles/signin_view_controller_delegate_views.cc index 27dbd7ff..3818ef1 100644 --- a/chrome/browser/ui/views/profiles/signin_view_controller_delegate_views.cc +++ b/chrome/browser/ui/views/profiles/signin_view_controller_delegate_views.cc
@@ -5,6 +5,7 @@ #include "chrome/browser/ui/views/profiles/signin_view_controller_delegate_views.h" #include "base/bind.h" +#include "base/callback_helpers.h" #include "base/memory/weak_ptr.h" #include "build/build_config.h" #include "chrome/browser/profiles/profile.h" @@ -65,7 +66,9 @@ } #if BUILDFLAG(ENABLE_DICE_SUPPORT) -void CloseModalSigninInBrowser(base::WeakPtr<Browser> browser) { +void CloseModalSigninInBrowser( + base::WeakPtr<Browser> browser, + ProfileCustomizationHandler::CustomizationResult result) { if (browser) browser->signin_view_controller()->CloseModalSignin(); }
diff --git a/chrome/browser/ui/webui/signin/profile_customization_handler.cc b/chrome/browser/ui/webui/signin/profile_customization_handler.cc index 989cd92..bc0ec9cb 100644 --- a/chrome/browser/ui/webui/signin/profile_customization_handler.cc +++ b/chrome/browser/ui/webui/signin/profile_customization_handler.cc
@@ -33,8 +33,8 @@ } ProfileCustomizationHandler::ProfileCustomizationHandler( - base::OnceClosure done_closure) - : done_closure_(std::move(done_closure)) {} + base::OnceCallback<void(CustomizationResult)> completion_callback) + : completion_callback_(std::move(completion_callback)) {} ProfileCustomizationHandler::~ProfileCustomizationHandler() = default; @@ -47,6 +47,9 @@ web_ui()->RegisterMessageCallback( "done", base::BindRepeating(&ProfileCustomizationHandler::HandleDone, base::Unretained(this))); + web_ui()->RegisterMessageCallback( + "skip", base::BindRepeating(&ProfileCustomizationHandler::HandleSkip, + base::Unretained(this))); } void ProfileCustomizationHandler::OnJavascriptAllowed() { @@ -101,8 +104,15 @@ GetProfileEntry()->SetLocalProfileName(profile_name, /*is_default_name=*/false); - if (done_closure_) - std::move(done_closure_).Run(); + if (completion_callback_) + std::move(completion_callback_).Run(CustomizationResult::kDone); +} + +void ProfileCustomizationHandler::HandleSkip(const base::Value::List& args) { + CHECK_EQ(0u, args.size()); + + if (completion_callback_) + std::move(completion_callback_).Run(CustomizationResult::kSkip); } void ProfileCustomizationHandler::UpdateProfileInfo(
diff --git a/chrome/browser/ui/webui/signin/profile_customization_handler.h b/chrome/browser/ui/webui/signin/profile_customization_handler.h index 2386414..82b30da 100644 --- a/chrome/browser/ui/webui/signin/profile_customization_handler.h +++ b/chrome/browser/ui/webui/signin/profile_customization_handler.h
@@ -18,7 +18,15 @@ class ProfileCustomizationHandler : public content::WebUIMessageHandler, public ProfileAttributesStorage::Observer { public: - explicit ProfileCustomizationHandler(base::OnceClosure done_closure); + enum class CustomizationResult { + // User clicked on the "Done" button. + kDone = 0, + // User clicked on the "Skip" button. + kSkip = 1, + }; + + explicit ProfileCustomizationHandler( + base::OnceCallback<void(CustomizationResult)> completion_callback); ~ProfileCustomizationHandler() override; ProfileCustomizationHandler(const ProfileCustomizationHandler&) = delete; @@ -44,6 +52,7 @@ // Handlers for messages from javascript. void HandleInitialized(const base::Value::List& args); void HandleDone(const base::Value::List& args); + void HandleSkip(const base::Value::List& args); // Sends an updated profile info (avatar and colors) to the WebUI. // `profile_path` is the path of the profile being updated, this function does @@ -61,8 +70,9 @@ ProfileAttributesStorage::Observer> observed_profile_{this}; - // Called when the "Done" button has been pressed. - base::OnceClosure done_closure_; + // Called when the "Done" or "Skip" button has been clicked. The callback + // normally closes native widget hosting Profile Customization webUI. + base::OnceCallback<void(CustomizationResult)> completion_callback_; }; #endif // CHROME_BROWSER_UI_WEBUI_SIGNIN_PROFILE_CUSTOMIZATION_HANDLER_H_
diff --git a/chrome/browser/ui/webui/signin/profile_customization_ui.cc b/chrome/browser/ui/webui/signin/profile_customization_ui.cc index 8fa13af..39687b2 100644 --- a/chrome/browser/ui/webui/signin/profile_customization_ui.cc +++ b/chrome/browser/ui/webui/signin/profile_customization_ui.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/ui/webui/signin/profile_customization_ui.h" +#include "base/callback_helpers.h" #include "base/feature_list.h" #include "base/strings/utf_string_conversions.h" #include "chrome/browser/browser_process.h" @@ -89,9 +90,11 @@ ProfileCustomizationUI::~ProfileCustomizationUI() = default; -void ProfileCustomizationUI::Initialize(base::OnceClosure done_closure) { - web_ui()->AddMessageHandler( - std::make_unique<ProfileCustomizationHandler>(std::move(done_closure))); +void ProfileCustomizationUI::Initialize( + base::OnceCallback<void(ProfileCustomizationHandler::CustomizationResult)> + completion_callback) { + web_ui()->AddMessageHandler(std::make_unique<ProfileCustomizationHandler>( + std::move(completion_callback))); } void ProfileCustomizationUI::BindInterface(
diff --git a/chrome/browser/ui/webui/signin/profile_customization_ui.h b/chrome/browser/ui/webui/signin/profile_customization_ui.h index 2d069bd4..026a71c 100644 --- a/chrome/browser/ui/webui/signin/profile_customization_ui.h +++ b/chrome/browser/ui/webui/signin/profile_customization_ui.h
@@ -6,6 +6,7 @@ #define CHROME_BROWSER_UI_WEBUI_SIGNIN_PROFILE_CUSTOMIZATION_UI_H_ #include "base/callback.h" +#include "chrome/browser/ui/webui/signin/profile_customization_handler.h" #include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/cpp/bindings/pending_remote.h" #include "mojo/public/cpp/bindings/receiver.h" @@ -33,7 +34,9 @@ ProfileCustomizationUI& operator=(const ProfileCustomizationUI&) = delete; // Initializes the ProfileCustomizationUI. - void Initialize(base::OnceClosure done_closure); + void Initialize( + base::OnceCallback<void(ProfileCustomizationHandler::CustomizationResult)> + completion_callback); // Instantiates the implementor of the // customize_themes::mojom::CustomizeThemesHandlerFactory mojo interface
diff --git a/chrome/browser/ui/webui/web_app_internals/web_app_internals_source.cc b/chrome/browser/ui/webui/web_app_internals/web_app_internals_source.cc index 2d94714..dbde99b 100644 --- a/chrome/browser/ui/webui/web_app_internals/web_app_internals_source.cc +++ b/chrome/browser/ui/webui/web_app_internals/web_app_internals_source.cc
@@ -268,7 +268,7 @@ // reference. if (!info.is_directory) { folder->Set(file_or_folder.AsUTF8Unsafe(), - base::StrCat({base::NumberToString(info.size / 1024), "kb"})); + base::StrCat({base::NumberToString(info.size), " bytes"})); return; }
diff --git a/chrome/browser/web_applications/BUILD.gn b/chrome/browser/web_applications/BUILD.gn index cd4064b..694ad48a 100644 --- a/chrome/browser/web_applications/BUILD.gn +++ b/chrome/browser/web_applications/BUILD.gn
@@ -12,6 +12,8 @@ "../ash/system_web_apps/system_web_app_background_task.h", "../ash/system_web_apps/system_web_app_manager.cc", "../ash/system_web_apps/system_web_app_manager.h", + "../ash/system_web_apps/system_web_app_manager_factory.cc", + "../ash/system_web_apps/system_web_app_manager_factory.h", "app_registrar_observer.h", "commands/callback_command.cc", "commands/callback_command.h",
diff --git a/chrome/browser/web_applications/system_web_apps/test/test_system_web_app_installation.cc b/chrome/browser/web_applications/system_web_apps/test/test_system_web_app_installation.cc index d97c012e..d9d00eb 100644 --- a/chrome/browser/web_applications/system_web_apps/test/test_system_web_app_installation.cc +++ b/chrome/browser/web_applications/system_web_apps/test/test_system_web_app_installation.cc
@@ -297,19 +297,29 @@ // startup. TestSystemWebAppInstallation is intended // to have the same lifecycle as the test, it won't be // destroyed before the test finishes. - base::Unretained(this), delegate_ptr)); + base::Unretained(this))); + + test_system_web_app_manager_creator_ = + std::make_unique<TestSystemWebAppManagerCreator>(base::BindRepeating( + &TestSystemWebAppInstallation::CreateSystemWebAppManager, + base::Unretained(this), delegate_ptr)); } TestSystemWebAppInstallation::TestSystemWebAppInstallation() { - fake_web_app_provider_creator_ = std::make_unique< - FakeWebAppProviderCreator>(base::BindRepeating( - &TestSystemWebAppInstallation::CreateWebAppProviderWithNoSystemWebApps, - // base::Unretained is safe here. This callback is called - // at TestingProfile::Init, which is at test startup. - // TestSystemWebAppInstallation is intended to have the - // same lifecycle as the test, it won't be destroyed before - // the test finishes. - base::Unretained(this))); + fake_web_app_provider_creator_ = std::make_unique<FakeWebAppProviderCreator>( + base::BindRepeating(&TestSystemWebAppInstallation::CreateWebAppProvider, + // base::Unretained is safe here. This callback is + // called at TestingProfile::Init, which is at test + // startup. TestSystemWebAppInstallation is intended + // to have the same lifecycle as the test, it won't be + // destroyed before the test finishes. + base::Unretained(this))); + + test_system_web_app_manager_creator_ = + std::make_unique<TestSystemWebAppManagerCreator>( + base::BindRepeating(&TestSystemWebAppInstallation:: + CreateSystemWebAppManagerWithNoSystemWebApps, + base::Unretained(this))); } TestSystemWebAppInstallation::~TestSystemWebAppInstallation() = default; @@ -769,17 +779,31 @@ } std::unique_ptr<KeyedService> -TestSystemWebAppInstallation::CreateWebAppProvider( +TestSystemWebAppInstallation::CreateWebAppProvider(Profile* profile) { + profile_ = profile; + + auto provider = std::make_unique<FakeWebAppProvider>(profile); + provider->Start(); + + return provider; +} + +std::unique_ptr<KeyedService> +TestSystemWebAppInstallation::CreateSystemWebAppManager( UnittestingSystemAppDelegate* delegate, Profile* profile) { - profile_ = profile; + // `CreateWebAppProvider` gets called first and assigns `profile_`. + DCHECK_EQ(profile_, profile); + if (GetWebUIType(delegate->GetInstallUrl()) == WebUIType::kChromeUntrusted) { AddTestURLDataSource(GetChromeUntrustedDataSourceNameFromInstallUrl( delegate->GetInstallUrl()), profile); } - auto provider = std::make_unique<FakeWebAppProvider>(profile); + WebAppProvider* provider = WebAppProvider::GetForLocalAppsUnchecked(profile); + DCHECK(provider); + auto system_web_app_manager = std::make_unique<ash::SystemWebAppManager>(profile); @@ -787,38 +811,36 @@ std::move(system_app_delegates_)); system_web_app_manager->SetUpdatePolicyForTesting(update_policy_); - provider->on_registry_ready().Post( - FROM_HERE, base::BindOnce(&ash::SystemWebAppManager::Start, - system_web_app_manager->GetWeakPtr())); - - provider->SetSystemWebAppManager(std::move(system_web_app_manager)); - provider->Start(); + system_web_app_manager->ConnectSubsystems(provider); + system_web_app_manager->ScheduleStart(); const url::Origin app_origin = url::Origin::Create(delegate->GetInstallUrl()); auto* allowlist = WebUIAllowlist::GetOrCreate(profile); for (const auto& permission : auto_granted_permissions_) allowlist->RegisterAutoGrantedPermission(app_origin, permission); - return provider; + return system_web_app_manager; } std::unique_ptr<KeyedService> -TestSystemWebAppInstallation::CreateWebAppProviderWithNoSystemWebApps( +TestSystemWebAppInstallation::CreateSystemWebAppManagerWithNoSystemWebApps( Profile* profile) { - profile_ = profile; - auto provider = std::make_unique<FakeWebAppProvider>(profile); + // `CreateWebAppProvider` gets called first and assigns `profile_`. + DCHECK_EQ(profile_, profile); + + WebAppProvider* provider = WebAppProvider::GetForLocalAppsUnchecked(profile); + DCHECK(provider); + auto system_web_app_manager = std::make_unique<ash::SystemWebAppManager>(profile); + system_web_app_manager->SetSystemAppsForTesting({}); system_web_app_manager->SetUpdatePolicyForTesting(update_policy_); - provider->on_registry_ready().Post( - FROM_HERE, base::BindOnce(&ash::SystemWebAppManager::Start, - system_web_app_manager->GetWeakPtr())); + system_web_app_manager->ConnectSubsystems(provider); + system_web_app_manager->ScheduleStart(); - provider->SetSystemWebAppManager(std::move(system_web_app_manager)); - provider->Start(); - return provider; + return system_web_app_manager; } void TestSystemWebAppInstallation::WaitForAppInstall() {
diff --git a/chrome/browser/web_applications/system_web_apps/test/test_system_web_app_installation.h b/chrome/browser/web_applications/system_web_apps/test/test_system_web_app_installation.h index 8cb7980b8..5d0b304 100644 --- a/chrome/browser/web_applications/system_web_apps/test/test_system_web_app_installation.h +++ b/chrome/browser/web_applications/system_web_apps/test/test_system_web_app_installation.h
@@ -10,6 +10,7 @@ #include "base/memory/raw_ptr.h" #include "chrome/browser/ash/system_web_apps/system_web_app_manager.h" #include "chrome/browser/ash/system_web_apps/types/system_web_app_delegate.h" +#include "chrome/browser/web_applications/system_web_apps/test/test_system_web_app_manager.h" #include "chrome/browser/web_applications/system_web_apps/test/test_system_web_app_web_ui_controller_factory.h" #include "chrome/browser/web_applications/test/fake_web_app_provider.h" #include "chrome/browser/web_applications/web_app_install_info.h" @@ -232,10 +233,12 @@ std::unique_ptr<UnittestingSystemAppDelegate> system_app_delegate); TestSystemWebAppInstallation(); - std::unique_ptr<KeyedService> CreateWebAppProvider( + std::unique_ptr<KeyedService> CreateWebAppProvider(Profile* profile); + std::unique_ptr<KeyedService> CreateSystemWebAppManager( UnittestingSystemAppDelegate* system_app_delegate, Profile* profile); - std::unique_ptr<KeyedService> CreateWebAppProviderWithNoSystemWebApps( + + std::unique_ptr<KeyedService> CreateSystemWebAppManagerWithNoSystemWebApps( Profile* profile); // Must be called in SetUp*App() methods, before WebAppProvider is created. @@ -244,7 +247,11 @@ raw_ptr<Profile> profile_; ash::SystemWebAppManager::UpdatePolicy update_policy_ = ash::SystemWebAppManager::UpdatePolicy::kAlwaysUpdate; + std::unique_ptr<FakeWebAppProviderCreator> fake_web_app_provider_creator_; + std::unique_ptr<TestSystemWebAppManagerCreator> + test_system_web_app_manager_creator_; + // nullopt if SetUpWithoutApps() was used. const absl::optional<ash::SystemWebAppType> type_; std::vector<std::unique_ptr<TestSystemWebAppWebUIControllerFactory>>
diff --git a/chrome/browser/web_applications/system_web_apps/test/test_system_web_app_manager.cc b/chrome/browser/web_applications/system_web_apps/test/test_system_web_app_manager.cc index f1ad60d5..f8cd939 100644 --- a/chrome/browser/web_applications/system_web_apps/test/test_system_web_app_manager.cc +++ b/chrome/browser/web_applications/system_web_apps/test/test_system_web_app_manager.cc
@@ -7,10 +7,42 @@ #include <memory> #include <string> #include <utility> + +#include "chrome/browser/ash/system_web_apps/system_web_app_manager_factory.h" #include "chrome/browser/ash/system_web_apps/types/system_web_app_delegate.h" +#include "chrome/browser/web_applications/test/fake_web_app_provider.h" +#include "chrome/browser/web_applications/web_app_utils.h" +#include "components/keyed_service/content/browser_context_dependency_manager.h" +#include "components/keyed_service/core/keyed_service.h" namespace web_app { +// static +std::unique_ptr<KeyedService> TestSystemWebAppManager::BuildDefault( + content::BrowserContext* context) { + Profile* profile = Profile::FromBrowserContext(context); + + WebAppProvider* provider = WebAppProvider::GetForLocalAppsUnchecked(profile); + DCHECK(provider); + + auto test_swa_manager = std::make_unique<TestSystemWebAppManager>(profile); + + test_swa_manager->ConnectSubsystems(provider); + + // We don't auto-install system web apps in `TestingProfile`. Tests must + // opt-in to call `ScheduleStart()` or `Start()` when they need. + + return test_swa_manager; +} + +// static +TestSystemWebAppManager* TestSystemWebAppManager::Get(Profile* profile) { + CHECK(profile->AsTestingProfile()); + auto* test_swa_manager = static_cast<TestSystemWebAppManager*>( + TestSystemWebAppManager::GetForLocalAppsUnchecked(profile)); + return test_swa_manager; +} + TestSystemWebAppManager::TestSystemWebAppManager(Profile* profile) : SystemWebAppManager(profile) { SetSystemAppsForTesting( @@ -33,4 +65,35 @@ return current_locale_; } +TestSystemWebAppManagerCreator::TestSystemWebAppManagerCreator( + CreateSystemWebAppManagerCallback callback) + : callback_(std::move(callback)) { + create_services_subscription_ = + BrowserContextDependencyManager::GetInstance() + ->RegisterCreateServicesCallbackForTesting( + base::BindRepeating(&TestSystemWebAppManagerCreator:: + OnWillCreateBrowserContextServices, + base::Unretained(this))); +} + +TestSystemWebAppManagerCreator::~TestSystemWebAppManagerCreator() = default; + +void TestSystemWebAppManagerCreator::OnWillCreateBrowserContextServices( + content::BrowserContext* context) { + ash::SystemWebAppManagerFactory::GetInstance()->SetTestingFactory( + context, base::BindRepeating( + &TestSystemWebAppManagerCreator::CreateSystemWebAppManager, + base::Unretained(this))); +} + +std::unique_ptr<KeyedService> +TestSystemWebAppManagerCreator::CreateSystemWebAppManager( + content::BrowserContext* context) { + Profile* profile = Profile::FromBrowserContext(context); + DCHECK(!ash::SystemWebAppManagerFactory::IsServiceCreatedForProfile(profile)); + if (!AreWebAppsEnabled(profile) || !callback_) + return nullptr; + return callback_.Run(profile); +} + } // namespace web_app
diff --git a/chrome/browser/web_applications/system_web_apps/test/test_system_web_app_manager.h b/chrome/browser/web_applications/system_web_apps/test/test_system_web_app_manager.h index 262912e..da31832 100644 --- a/chrome/browser/web_applications/system_web_apps/test/test_system_web_app_manager.h +++ b/chrome/browser/web_applications/system_web_apps/test/test_system_web_app_manager.h
@@ -8,16 +8,36 @@ #include <string> #include <vector> +#include "base/callback.h" +#include "base/callback_list.h" #include "base/version.h" #include "chrome/browser/ash/system_web_apps/system_web_app_manager.h" #include "url/gurl.h" +class KeyedService; class Profile; +namespace content { +class BrowserContext; +} + namespace web_app { +// This class is used in unit tests only, browser tests use real +// `SystemWebAppManager`. class TestSystemWebAppManager : public ash::SystemWebAppManager { public: + // Used by the TestingProfile in unit tests. + // Builds a stub `TestSystemWebAppManager` that needs to be manually started + // by calling `ScheduleStart()`. Use `TestSystemWebAppManager::Get()` to use + // testing methods. + static std::unique_ptr<KeyedService> BuildDefault( + content::BrowserContext* context); + + // Gets a TestSystemWebAppManager. Clients must call `ScheduleStart()` to make + // `on_apps_synchronized()` event ready. + static TestSystemWebAppManager* Get(Profile* profile); + explicit TestSystemWebAppManager(Profile* profile); TestSystemWebAppManager(const TestSystemWebAppManager&) = delete; TestSystemWebAppManager& operator=(const TestSystemWebAppManager&) = delete; @@ -42,6 +62,28 @@ std::string current_locale_; }; +// Used in tests to ensure that the SystemWebAppManager that is created on +// profile startup is the TestSystemWebAppManager. Hooks into the +// BrowserContextKeyedService initialization pipeline. +class TestSystemWebAppManagerCreator { + public: + using CreateSystemWebAppManagerCallback = + base::RepeatingCallback<std::unique_ptr<KeyedService>(Profile* profile)>; + + explicit TestSystemWebAppManagerCreator( + CreateSystemWebAppManagerCallback callback); + ~TestSystemWebAppManagerCreator(); + + private: + void OnWillCreateBrowserContextServices(content::BrowserContext* context); + std::unique_ptr<KeyedService> CreateSystemWebAppManager( + content::BrowserContext* context); + + CreateSystemWebAppManagerCallback callback_; + + base::CallbackListSubscription create_services_subscription_; +}; + } // namespace web_app #endif // CHROME_BROWSER_WEB_APPLICATIONS_SYSTEM_WEB_APPS_TEST_TEST_SYSTEM_WEB_APP_MANAGER_H_
diff --git a/chrome/browser/web_applications/test/fake_web_app_provider.cc b/chrome/browser/web_applications/test/fake_web_app_provider.cc index d860b61..eddf9fa0 100644 --- a/chrome/browser/web_applications/test/fake_web_app_provider.cc +++ b/chrome/browser/web_applications/test/fake_web_app_provider.cc
@@ -17,7 +17,6 @@ #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/policy/web_app_policy_manager.h" -#include "chrome/browser/web_applications/system_web_apps/test/test_system_web_app_manager.h" #include "chrome/browser/web_applications/test/fake_externally_managed_app_manager.h" #include "chrome/browser/web_applications/test/fake_os_integration_manager.h" #include "chrome/browser/web_applications/test/fake_web_app_database_factory.h" @@ -142,12 +141,6 @@ ui_manager_ = std::move(ui_manager); } -void FakeWebAppProvider::SetSystemWebAppManager( - std::unique_ptr<ash::SystemWebAppManager> system_web_app_manager) { - CheckNotStarted(); - system_web_app_manager_ = std::move(system_web_app_manager); -} - void FakeWebAppProvider::SetWebAppPolicyManager( std::unique_ptr<WebAppPolicyManager> web_app_policy_manager) { CheckNotStarted(); @@ -185,12 +178,6 @@ void FakeWebAppProvider::StartWithSubsystems() { CheckNotStarted(); SetRunSubsystemStartupTasks(true); - // Use a TestSystemWebAppManager to skip system web apps being - // auto-installed on |Start|. - // TODO(crbug.com/973324): This is set in `SetDefaultFakeSubsystems`. Remove - // it from here. - SetSystemWebAppManager( - std::make_unique<web_app::TestSystemWebAppManager>(profile_)); Start(); } @@ -225,11 +212,6 @@ SetWebAppPolicyManager(std::make_unique<WebAppPolicyManager>(profile_)); - // Use a TestSystemWebAppManager to skip system web apps being - // auto-installed on |Start|. - SetSystemWebAppManager( - std::make_unique<web_app::TestSystemWebAppManager>(profile_)); - SetCommandManager(std::make_unique<WebAppCommandManager>(profile_)); ON_CALL(processor(), IsTrackingMetadata())
diff --git a/chrome/browser/web_applications/test/fake_web_app_provider.h b/chrome/browser/web_applications/test/fake_web_app_provider.h index b899b3a11..e5f8f9f4 100644 --- a/chrome/browser/web_applications/test/fake_web_app_provider.h +++ b/chrome/browser/web_applications/test/fake_web_app_provider.h
@@ -8,7 +8,6 @@ #include <memory> #include "base/callback.h" -#include "base/callback_forward.h" #include "base/callback_list.h" #include "chrome/browser/web_applications/web_app_provider.h" #include "components/sync/test/model/mock_model_type_change_processor.h" @@ -17,10 +16,6 @@ class KeyedService; class Profile; -namespace ash { -class SystemWebAppManager; -} - namespace content { class BrowserContext; } @@ -83,8 +78,6 @@ std::unique_ptr<ExternallyManagedAppManager> externally_managed_app_manager); void SetWebAppUiManager(std::unique_ptr<WebAppUiManager> ui_manager); - void SetSystemWebAppManager( - std::unique_ptr<ash::SystemWebAppManager> system_web_app_manager); void SetWebAppPolicyManager( std::unique_ptr<WebAppPolicyManager> web_app_policy_manager); void SetCommandManager(std::unique_ptr<WebAppCommandManager> command_manager); @@ -126,12 +119,9 @@ // BrowserContextKeyedService initialization pipeline. class FakeWebAppProviderCreator { public: - using OnceCreateWebAppProviderCallback = - base::OnceCallback<std::unique_ptr<KeyedService>(Profile* profile)>; using CreateWebAppProviderCallback = base::RepeatingCallback<std::unique_ptr<KeyedService>(Profile* profile)>; - explicit FakeWebAppProviderCreator(OnceCreateWebAppProviderCallback callback); explicit FakeWebAppProviderCreator(CreateWebAppProviderCallback callback); ~FakeWebAppProviderCreator();
diff --git a/chrome/browser/web_applications/web_app_provider.cc b/chrome/browser/web_applications/web_app_provider.cc index 8bbb79d08..fbfe42e 100644 --- a/chrome/browser/web_applications/web_app_provider.cc +++ b/chrome/browser/web_applications/web_app_provider.cc
@@ -13,7 +13,6 @@ #include "base/run_loop.h" #include "build/build_config.h" #include "build/chromeos_buildflags.h" -#include "chrome/browser/ash/system_web_apps/system_web_app_manager.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/web_applications/daily_metrics_helper.h" #include "chrome/browser/web_applications/externally_installed_web_app_prefs.h" @@ -216,7 +215,6 @@ ui_manager_->Shutdown(); externally_managed_app_manager_->Shutdown(); manifest_update_manager_->Shutdown(); - system_web_app_manager_->Shutdown(); install_manager_->Shutdown(); icon_manager_->Shutdown(); install_finalizer_->Shutdown(); @@ -237,7 +235,6 @@ std::make_unique<ExternallyManagedAppManagerImpl>(profile); preinstalled_web_app_manager_ = std::make_unique<PreinstalledWebAppManager>(profile); - system_web_app_manager_ = std::make_unique<ash::SystemWebAppManager>(profile); web_app_policy_manager_ = std::make_unique<WebAppPolicyManager>(profile); database_factory_ = std::make_unique<WebAppDatabaseFactory>(profile); @@ -313,9 +310,6 @@ preinstalled_web_app_manager_->SetSubsystems( registrar_.get(), ui_manager_.get(), externally_managed_app_manager_.get()); - system_web_app_manager_->SetSubsystems( - externally_managed_app_manager_.get(), registrar_.get(), - sync_bridge_.get(), ui_manager_.get(), web_app_policy_manager_.get()); web_app_policy_manager_->SetSubsystems(externally_managed_app_manager_.get(), registrar_.get(), sync_bridge_.get(), os_integration_manager_.get()); @@ -328,13 +322,6 @@ command_manager_->SetSubsystems(install_manager_.get()); connected_ = true; - - // TODO(crbug.com/1321984): Extract this code to SystemWebAppManager - // KeyedService. - manifest_update_manager_->SetSystemWebAppDelegateMap( - &system_web_app_manager_->system_app_delegates()); - web_app_policy_manager_->SetSystemWebAppDelegateMap( - &system_web_app_manager_->system_app_delegates()); } void WebAppProvider::StartSyncBridge() { @@ -376,7 +363,6 @@ ExternallyInstalledWebAppPrefs::RegisterProfilePrefs(registry); PreinstalledWebAppManager::RegisterProfilePrefs(registry); WebAppPolicyManager::RegisterProfilePrefs(registry); - ash::SystemWebAppManager::RegisterProfilePrefs(registry); WebAppPrefsUtilsRegisterProfilePrefs(registry); IsolationPrefsUtilsRegisterProfilePrefs(registry); RegisterInstallBounceMetricProfilePrefs(registry);
diff --git a/chrome/browser/web_applications/web_app_provider.h b/chrome/browser/web_applications/web_app_provider.h index 48fdb956..08055e3 100644 --- a/chrome/browser/web_applications/web_app_provider.h +++ b/chrome/browser/web_applications/web_app_provider.h
@@ -18,10 +18,6 @@ class Profile; -namespace ash { -class SystemWebAppManager; -} - namespace content { class WebContents; } @@ -148,10 +144,6 @@ } protected: - // TODO(crbug.com/1321984): Delete system_web_app_manager_. - friend class ash::SystemWebAppManager; - friend class WebAppProviderFactory; - virtual void StartImpl(); void CreateSubsystems(Profile* profile); @@ -179,9 +171,6 @@ std::unique_ptr<WebAppInstallFinalizer> install_finalizer_; std::unique_ptr<ManifestUpdateManager> manifest_update_manager_; std::unique_ptr<ExternallyManagedAppManager> externally_managed_app_manager_; - // TODO(crbug.com/1321984): Extract system web app manager as - // chrome/browser/ash/ keyed service. - std::unique_ptr<ash::SystemWebAppManager> system_web_app_manager_; std::unique_ptr<WebAppAudioFocusIdMap> audio_focus_id_map_; std::unique_ptr<WebAppInstallManager> install_manager_; std::unique_ptr<WebAppPolicyManager> web_app_policy_manager_;
diff --git a/chrome/browser/web_applications/web_app_provider_factory.cc b/chrome/browser/web_applications/web_app_provider_factory.cc index d7c6293..6876e61 100644 --- a/chrome/browser/web_applications/web_app_provider_factory.cc +++ b/chrome/browser/web_applications/web_app_provider_factory.cc
@@ -4,7 +4,6 @@ #include "chrome/browser/web_applications/web_app_provider_factory.h" -#include "chrome/browser/ash/system_web_apps/system_web_app_manager.h" #include "chrome/browser/content_settings/host_content_settings_map_factory.h" #include "chrome/browser/metrics/ukm_background_recorder_service.h" #include "chrome/browser/profiles/profile.h" @@ -53,13 +52,6 @@ WebAppProvider* provider = new WebAppProvider(profile); provider->Start(); - // TODO(crbug.com/1321984): Make SWAM a KeyedService and move this scheduling - // to that new service factory. - provider->on_registry_ready().Post( - FROM_HERE, - base::BindOnce(&ash::SystemWebAppManager::Start, - provider->system_web_app_manager_->GetWeakPtr())); - return provider; }
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt index d080325..4e2296a2 100644 --- a/chrome/build/linux.pgo.txt +++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@ -chrome-linux-main-1655229557-36aeb1dcde852e0e6daabaedec9aed25e8446d58.profdata +chrome-linux-main-1655271799-e052a880a182ec4f533846fb5fa76276479ad24b.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt index 78bb747..42b42fb0 100644 --- a/chrome/build/mac.pgo.txt +++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@ -chrome-mac-main-1655250914-1f025f2d0cf31dca0d1885c0e412e79c8f096d4f.profdata +chrome-mac-main-1655271799-3dbce1d5b32c25a17124fc1c88b26cc010397167.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt index f04ed15..e719a47 100644 --- a/chrome/build/win32.pgo.txt +++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@ -chrome-win32-main-1655229557-066d5add5fce3d3ed8e49b23efab1500633c1555.profdata +chrome-win32-main-1655271799-afc5146a664cfc20dfe535291a0926e4788db342.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt index 4d54d983..b9d106a 100644 --- a/chrome/build/win64.pgo.txt +++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@ -chrome-win64-main-1655250914-706926b27021a324e0e16e0d619fb284315f3b44.profdata +chrome-win64-main-1655283589-6861ba398f596394a34c3f5d7c9d94d8f4106210.profdata
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc index 39dd67f..c3d5bd5c 100644 --- a/chrome/common/chrome_switches.cc +++ b/chrome/common/chrome_switches.cc
@@ -590,6 +590,10 @@ const char kWebRtcRemoteEventLogUploadNoSuppression[] = "webrtc-event-log-upload-no-suppression"; +// Override WebRTC IP handling policy to mimic the behavior when WebRTC IP +// handling policy is specified in Preferences. +const char kWebRtcIPHandlingPolicy[] = "webrtc-ip-handling-policy"; + // Specify the initial window position: --window-position=x,y const char kWindowPosition[] = "window-position";
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h index 12c9b02..42d445af 100644 --- a/chrome/common/chrome_switches.h +++ b/chrome/common/chrome_switches.h
@@ -178,6 +178,7 @@ extern const char kWebRtcRemoteEventLogProactivePruningDelta[]; extern const char kWebRtcRemoteEventLogUploadDelayMs[]; extern const char kWebRtcRemoteEventLogUploadNoSuppression[]; +extern const char kWebRtcIPHandlingPolicy[]; extern const char kWindowPosition[]; extern const char kWindowSize[]; extern const char kWindowWorkspace[];
diff --git a/chrome/common/extensions/api/file_manager_private.idl b/chrome/common/extensions/api/file_manager_private.idl index 84fac49..49eb994 100644 --- a/chrome/common/extensions/api/file_manager_private.idl +++ b/chrome/common/extensions/api/file_manager_private.idl
@@ -365,6 +365,15 @@ zip }; +enum RecentDateBucket { + today, + yesterday, + earlier_this_week, + earlier_this_month, + earlier_this_year, + older +}; + // These three fields together uniquely identify a task. dictionary FileTaskDescriptor { DOMString appId; @@ -410,6 +419,9 @@ // Timestamp of entry update time by me, in milliseconds past the epoch. double? modificationByMeTime; + // Date bucket calculated by |modificationTime| or |modificationByMeTime|. + RecentDateBucket? recentDateBucket; + // URL to the Drive thumbnail image for this file. DOMString? thumbnailUrl; @@ -982,6 +994,17 @@ // The name of the last error that happened. DOMString errorName; + + // The files affected by the IOTask. Currently only returned for TrashIOTask. + [instanceOf=Entry] object[]? outputs; +}; + +dictionary DlpMetadata { + // The source URL of the file, if it's been downloaded. + DOMString sourceUrl; + + // True if there is any DLP policy on the file, false otherwise. + boolean isDlpRestricted; }; // A Guest OS that supports guest->host file sharing. This definition should @@ -1043,9 +1066,10 @@ callback GetDisallowedTransfersCallback = void([instanceOf=Entry] object[] disallowedEntries); -// |restrictedFiles| A list of files with any Data Leak Prevention restriction. -callback GetFilesRestrictedByDlpCallback = - void([instanceOf=Entry] object[] restrictedFiles); +// |dlpMetadata| A list of DlpMetadata containing DLP information about +// the entries. +callback GetDlpMetadataCallback = + void(DlpMetadata[] dlpMetadata); // |copyId| ID of the copy task. Can be used to identify the progress, and to // cancel the task. @@ -1328,13 +1352,14 @@ [instanceOf=DirectoryEntry] object destinationEntry, GetDisallowedTransfersCallback callback); - // Returns the list of files that have any Data Leak Prevention restriction rule set. + // Returns the list of DlpMetadata containing DLP information + // about the entries. // |entries| List of the source entries to be checked. // |callback| Result callback. [nocompile] - static void getFilesRestrictedByDlp( + static void getDlpMetadata( [instanceOf=Entry] object[] entries, - GetFilesRestrictedByDlpCallback callback); + GetDlpMetadataCallback callback); // Starts to copy an entry. If the source is a directory, the copy is done // recursively.
diff --git a/chrome/common/extensions/api/file_manager_private_internal.idl b/chrome/common/extensions/api/file_manager_private_internal.idl index ca236f0..7ead75b 100644 --- a/chrome/common/extensions/api/file_manager_private_internal.idl +++ b/chrome/common/extensions/api/file_manager_private_internal.idl
@@ -36,8 +36,8 @@ callback GetUrlCallback = void(DOMString url); callback GetDisallowedTransfersCallback = void(EntryDescription[] entries); - callback GetFilesRestrictedByDlpCallback = - void(EntryDescription[] entries); + callback GetDlpMetadataCallback = + void(fileManagerPrivate.DlpMetadata[] entries); callback StartCopyCallback = void(long copyId); callback IOTaskIdCallback = void(long taskId); callback ZipSelectionCallback = void(long zipId, double totalBytes); @@ -98,8 +98,8 @@ static void getDisallowedTransfers(DOMString[] entries, DOMString destinationEntry, GetDisallowedTransfersCallback callback); - static void getFilesRestrictedByDlp(DOMString[] entries, - GetFilesRestrictedByDlpCallback callback); + static void getDlpMetadata(DOMString[] entries, + GetDlpMetadataCallback callback); static void startCopy(DOMString url, DOMString parentUrl, DOMString newName,
diff --git a/chrome/renderer/resources/extensions/file_manager_private_custom_bindings.js b/chrome/renderer/resources/extensions/file_manager_private_custom_bindings.js index 2bc4603..24f8f72 100644 --- a/chrome/renderer/resources/extensions/file_manager_private_custom_bindings.js +++ b/chrome/renderer/resources/extensions/file_manager_private_custom_bindings.js
@@ -225,9 +225,9 @@ }); apiFunctions.setHandleRequest( - 'getFilesRestrictedByDlp', function(entries, callback) { + 'getDlpMetadata', function(entries, callback) { var sourceUrls = entries.map(getEntryURL); - fileManagerPrivateInternal.getFilesRestrictedByDlp( + fileManagerPrivateInternal.getDlpMetadata( sourceUrls, callback); }); @@ -405,3 +405,15 @@ } dispatch(args); }); + +bindingUtil.registerEventArgumentMassager( + 'fileManagerPrivate.onIOTaskProgressStatus', function(args, dispatch) { + // Convert outputs arguments into real Entry objects if they exist. + const outputs = args[0].outputs; + if (outputs) { + for (let i = 0; i < outputs.length; i++) { + outputs[i] = GetExternalFileEntry(outputs[i]); + } + } + dispatch(args); + });
diff --git a/chrome/services/sharing/nearby/platform/webrtc.cc b/chrome/services/sharing/nearby/platform/webrtc.cc index 21d054f9..cc1753d 100644 --- a/chrome/services/sharing/nearby/platform/webrtc.cc +++ b/chrome/services/sharing/nearby/platform/webrtc.cc
@@ -19,7 +19,7 @@ #include "third_party/nearby/src/internal/platform/logging.h" #include "third_party/webrtc/api/jsep.h" #include "third_party/webrtc/api/peer_connection_interface.h" -#include "third_party/webrtc_overrides/task_queue_factory.h" +#include "third_party/webrtc_overrides/metronome_task_queue_factory.h" #include "unicode/locid.h" namespace location { @@ -415,7 +415,8 @@ DCHECK(rtc_worker_thread_); webrtc::PeerConnectionFactoryDependencies factory_dependencies; - factory_dependencies.task_queue_factory = CreateWebRtcTaskQueueFactory(); + factory_dependencies.task_queue_factory = + CreateWebRtcMetronomeTaskQueueFactory(); factory_dependencies.network_thread = rtc_network_thread_; factory_dependencies.worker_thread = rtc_worker_thread_; factory_dependencies.signaling_thread = rtc_signaling_thread_;
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 0442ad7..a18e842 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -6858,6 +6858,8 @@ "//components/send_tab_to_self:test_support", "//components/services/app_service:unit_tests", "//components/services/app_service/public/cpp:icon_loader_test_support", + "//components/services/app_service/public/cpp:preferred_app", + "//components/services/app_service/public/cpp:preferred_apps", "//components/services/app_service/public/cpp:publisher", "//components/services/app_service/public/cpp:test_support", "//components/services/app_service/public/cpp:unit_tests",
diff --git a/chrome/test/base/test_chrome_web_ui_controller_factory.cc b/chrome/test/base/test_chrome_web_ui_controller_factory.cc index 2c72f8a..0827243e 100644 --- a/chrome/test/base/test_chrome_web_ui_controller_factory.cc +++ b/chrome/test/base/test_chrome_web_ui_controller_factory.cc
@@ -71,6 +71,8 @@ std::make_unique<TestDataSource>("webui")); content::WebUIDataSource* source = webui::CreateWebUITestDataSource(); + if (provider) + provider->DataSourceOverrides(source); content::WebUIDataSource::Add(profile, source); return controller;
diff --git a/chrome/test/base/test_chrome_web_ui_controller_factory.h b/chrome/test/base/test_chrome_web_ui_controller_factory.h index f5b6ab9..25b654458 100644 --- a/chrome/test/base/test_chrome_web_ui_controller_factory.h +++ b/chrome/test/base/test_chrome_web_ui_controller_factory.h
@@ -11,6 +11,7 @@ #include "chrome/browser/ui/webui/chrome_web_ui_controller_factory.h" #include "content/public/browser/web_ui.h" +#include "content/public/browser/web_ui_data_source.h" // A test implementation of ChromeWebUIControllerFactory that provides a // registry to override CreateWebUIControllerForURL() by host. @@ -25,6 +26,10 @@ content::WebUI* web_ui, const GURL& url) = 0; + // Override this method to customize `source` for the newly created WebUI + // controller. + virtual void DataSourceOverrides(content::WebUIDataSource* source) {} + protected: virtual ~WebUIProvider(); };
diff --git a/chrome/test/base/testing_profile.cc b/chrome/test/base/testing_profile.cc index 9531e5c..c30a0e8 100644 --- a/chrome/test/base/testing_profile.cc +++ b/chrome/test/base/testing_profile.cc
@@ -108,10 +108,12 @@ #include "testing/gmock/include/gmock/gmock.h" #if BUILDFLAG(ENABLE_EXTENSIONS) +#include "chrome/browser/ash/system_web_apps/system_web_app_manager_factory.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/extension_special_storage_policy.h" #include "chrome/browser/extensions/extension_system_factory.h" #include "chrome/browser/extensions/test_extension_system.h" +#include "chrome/browser/web_applications/system_web_apps/test/test_system_web_app_manager.h" #include "chrome/browser/web_applications/test/fake_web_app_provider.h" #include "chrome/browser/web_applications/web_app_provider_factory.h" #include "components/guest_view/browser/guest_view_manager.h" @@ -413,6 +415,9 @@ web_app::WebAppProviderFactory::GetInstance()->SetTestingFactory( this, base::BindRepeating(&web_app::FakeWebAppProvider::BuildDefault)); + ash::SystemWebAppManagerFactory::GetInstance()->SetTestingFactory( + this, + base::BindRepeating(&web_app::TestSystemWebAppManager::BuildDefault)); #endif // Prefs for incognito profiles are set in CreateIncognitoPrefService().
diff --git a/chrome/test/data/webrtc/region_capture_embedded.html b/chrome/test/data/webrtc/region_capture_embedded.html index 03591155..3f1cdce1 100644 --- a/chrome/test/data/webrtc/region_capture_embedded.html +++ b/chrome/test/data/webrtc/region_capture_embedded.html
@@ -19,17 +19,11 @@ } </script> </head> - <body onload="onLoad();"> + <body onload="reportEmbeddingSuccess();"> <div id="div"> <!-- This DIV is just a convenient target for cropTargetFromElement. --> - <p id="p_id">0</p> + <h1>Region Capture Test - Page 1 (Embedded)</h1> </div> - <iframe id="mailman_frame" hidden></iframe> - <script> - function onLoad() { - animate(document.getElementById('p_id')); - reportEmbeddingSuccess(); - } - </script> + <iframe id="mailman_frame"></iframe> </body> </html>
diff --git a/chrome/test/data/webrtc/region_capture_helpers.js b/chrome/test/data/webrtc/region_capture_helpers.js index 2ccdcd1..4e888f69 100644 --- a/chrome/test/data/webrtc/region_capture_helpers.js +++ b/chrome/test/data/webrtc/region_capture_helpers.js
@@ -65,12 +65,6 @@ } } -function animate(element) { - const animationCallback = function() { - element.innerHTML = parseInt(element.innerHTML) + 1; - }; - setInterval(animationCallback, 20); -} ///////////////////////////////////////// // Main actions from C++ test fixture. //
diff --git a/chrome/test/data/webrtc/region_capture_main.html b/chrome/test/data/webrtc/region_capture_main.html index 50b7b6bc3..e521ac3 100644 --- a/chrome/test/data/webrtc/region_capture_main.html +++ b/chrome/test/data/webrtc/region_capture_main.html
@@ -54,18 +54,13 @@ } </script> </head> - <body onload="onLoad();"> + <body> <div id="div"> <!-- This DIV is just a convenient target for cropTargetFromElement. --> - <p id="p_id">0</p> + <h1>Region Capture Test - Page 1 (Main)</h1> + <br/> </div> - <br /> <iframe id="embedded_frame" allow="display-capture *"></iframe> - <iframe id="mailman_frame" hidden></iframe> - <script> - function onLoad() { - animate(document.getElementById('p_id')); - } - </script> + <iframe id="mailman_frame"></iframe> </body> </html>
diff --git a/chrome/test/data/webrtc/region_capture_other_embedded.html b/chrome/test/data/webrtc/region_capture_other_embedded.html index ae0f488..3c1e6f4 100644 --- a/chrome/test/data/webrtc/region_capture_other_embedded.html +++ b/chrome/test/data/webrtc/region_capture_other_embedded.html
@@ -14,17 +14,11 @@ } </script> </head> - <body onload="onLoad();"> + <body onload="reportEmbeddingSuccess();"> <div id="div"> <!-- This DIV is just a convenient target for cropTargetFromElement. --> - <p id="p_id">0</p> + <h1>Region Capture Test - Page 2 (Embedded)</h1> </div> - <iframe id="mailman_frame" hidden></iframe> - <script> - function onLoad() { - animate(document.getElementById('p_id')); - reportEmbeddingSuccess(); - } - </script> + <iframe id="mailman_frame"></iframe> </body> </html>
diff --git a/chrome/test/data/webrtc/region_capture_other_main.html b/chrome/test/data/webrtc/region_capture_other_main.html index 0b69455..8ad30d5e 100644 --- a/chrome/test/data/webrtc/region_capture_other_main.html +++ b/chrome/test/data/webrtc/region_capture_other_main.html
@@ -10,18 +10,13 @@ setRole("top-level"); </script> </head> - <body onload="onLoad();"> + <body> <div id="div"> <!-- This DIV is just a convenient target for cropTargetFromElement. --> - <p id="p_id">0</p> - <br /> + <h1>Region Capture Test - Page 2 (Main)</h1> + <br/> <iframe id="embedded_frame" allow="display-capture *"></iframe> </div> - <iframe id="mailman_frame" hidden></iframe> - <script> - function onLoad() { - animate(document.getElementById('p_id')); - } - </script> + <iframe id="mailman_frame"></iframe> </body> </html>
diff --git a/chrome/test/data/webui/BUILD.gn b/chrome/test/data/webui/BUILD.gn index 00129822..466d0147 100644 --- a/chrome/test/data/webui/BUILD.gn +++ b/chrome/test/data/webui/BUILD.gn
@@ -359,6 +359,7 @@ } grit("resources") { + testonly = true defines = chrome_grit_defines # These arguments are needed since the grd is generated at build time. @@ -376,6 +377,7 @@ } generate_grd("build_chai_grdp") { + testonly = true grd_prefix = "webui_generated_test" out_grd = "$target_gen_dir/chai_resources.grdp" input_files_base_dir = rebase_path("//third_party/chaijs", "//") @@ -383,6 +385,7 @@ } generate_grd("build_web_ui_test_mojo_grdp") { + testonly = true grd_prefix = "webui_generated_test" out_grd = "$target_gen_dir/web_ui_test_mojo_resources.grdp" input_files_base_dir = rebase_path(target_gen_dir, root_build_dir) @@ -391,6 +394,7 @@ } generate_grd("build_grd") { + testonly = true grd_prefix = "webui_generated_test" output_files_base_dir = "test/data/grit" out_grd = "$target_gen_dir/resources.grd" @@ -500,9 +504,16 @@ } if (is_chromeos_ash) { - deps += [ "chromeos/personalization_app:build_grdp" ] - grdp_files += - [ "$target_gen_dir/chromeos/personalization_app/resources.grdp" ] + deps += [ + "chromeos/personalization_app:build_grdp", + "//ui/file_manager:build_tests_gen_grdp", + "//ui/file_manager:build_tests_grdp", + ] + grdp_files += [ + "$target_gen_dir/chromeos/personalization_app/resources.grdp", + "$root_gen_dir/ui/file_manager/tests_resources.grdp", + "$root_gen_dir/ui/file_manager/tests_gen_resources.grdp", + ] } manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
diff --git a/chrome/test/data/webui/chromeos/os_feedback_ui/confirmation_page_test.js b/chrome/test/data/webui/chromeos/os_feedback_ui/confirmation_page_test.js index 651a90fd..0a0d8440 100644 --- a/chrome/test/data/webui/chromeos/os_feedback_ui/confirmation_page_test.js +++ b/chrome/test/data/webui/chromeos/os_feedback_ui/confirmation_page_test.js
@@ -117,6 +117,7 @@ getElement(diagnosticsLink, '#startIcon').icon); assertEquals( 'Diagnostics app', getElementContent(diagnosticsLink, '#label')); + assertTrue(page.i18nExists('diagnosticsAppLabel')); assertEquals( 'Run tests and troubleshooting for hardware issues', getElementContent(diagnosticsLink, '#subLabel'));
diff --git a/chrome/test/data/webui/chromeos/os_feedback_ui/share_data_page_test.js b/chrome/test/data/webui/chromeos/os_feedback_ui/share_data_page_test.js index f298064..d36ba6f 100644 --- a/chrome/test/data/webui/chromeos/os_feedback_ui/share_data_page_test.js +++ b/chrome/test/data/webui/chromeos/os_feedback_ui/share_data_page_test.js
@@ -108,6 +108,7 @@ // Screenshot elements. assertTrue(!!getElement('#screenshotCheckbox')); assertEquals('Screenshot', getElementContent('#screenshotCheckLabel')); + assertTrue(page.i18nExists('attachScreenshotLabel')); assertTrue(!!getElement('#screenshotImage')); // Add file attachment element.
diff --git a/chrome/test/data/webui/settings/privacy_sandbox_test.ts b/chrome/test/data/webui/settings/privacy_sandbox_test.ts index 0be4dfc..1bd0b37e 100644 --- a/chrome/test/data/webui/settings/privacy_sandbox_test.ts +++ b/chrome/test/data/webui/settings/privacy_sandbox_test.ts
@@ -267,7 +267,7 @@ function assertMainViewVisible() { assertEquals( - page.privacySandboxSettingsView_, PrivacySandboxSettingsView.MAIN); + page.privacySandboxSettingsView, PrivacySandboxSettingsView.MAIN); const dialogWrapper = page.shadowRoot!.querySelector<CrDialogElement>('#dialogWrapper'); assertFalse(!!dialogWrapper); @@ -275,7 +275,7 @@ function assertLearnMoreDialogVisible() { assertEquals( - page.privacySandboxSettingsView_, + page.privacySandboxSettingsView, PrivacySandboxSettingsView.LEARN_MORE_DIALOG); const dialogWrapper = page.shadowRoot!.querySelector<CrDialogElement>('#dialogWrapper'); @@ -289,7 +289,7 @@ function assertAdPersonalizationDialogVisible() { assertEquals( - page.privacySandboxSettingsView_, + page.privacySandboxSettingsView, PrivacySandboxSettingsView.AD_PERSONALIZATION_DIALOG); const dialogWrapper = page.shadowRoot!.querySelector<CrDialogElement>('#dialogWrapper'); @@ -310,7 +310,7 @@ function assertAdPersonalizationRemovedDialogVisible() { assertEquals( - page.privacySandboxSettingsView_, + page.privacySandboxSettingsView, PrivacySandboxSettingsView.AD_PERSONALIZATION_REMOVED_DIALOG); const dialogWrapper = page.shadowRoot!.querySelector<CrDialogElement>('#dialogWrapper'); @@ -331,7 +331,7 @@ function assertAdMeasurementDialogVisible() { assertEquals( - page.privacySandboxSettingsView_, + page.privacySandboxSettingsView, PrivacySandboxSettingsView.AD_MEASUREMENT_DIALOG); const dialogWrapper = page.shadowRoot!.querySelector<CrDialogElement>('#dialogWrapper'); @@ -345,7 +345,7 @@ function assertSpamAndFraudDialogVisible() { assertEquals( - page.privacySandboxSettingsView_, + page.privacySandboxSettingsView, PrivacySandboxSettingsView.SPAM_AND_FRAUD_DIALOG); const dialogWrapper = page.shadowRoot!.querySelector<CrDialogElement>('#dialogWrapper');
diff --git a/chrome/test/data/webui/signin/profile_customization_test.ts b/chrome/test/data/webui/signin/profile_customization_test.ts index 18d72e6..6c938bea 100644 --- a/chrome/test/data/webui/signin/profile_customization_test.ts +++ b/chrome/test/data/webui/signin/profile_customization_test.ts
@@ -6,9 +6,9 @@ import {ProfileCustomizationAppElement} from 'chrome://profile-customization/profile_customization_app.js'; import {ProfileCustomizationBrowserProxyImpl} from 'chrome://profile-customization/profile_customization_browser_proxy.js'; +import {CrButtonElement} from 'chrome://resources/cr_elements/cr_button/cr_button.m.js'; import {webUIListenerCallback} from 'chrome://resources/js/cr.m.js'; import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js'; - import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js'; import {isChildVisible} from 'chrome://webui-test/test_util.js'; @@ -126,9 +126,20 @@ }); // Checks that the Skip button is present when the page is displayed in a - // dialog in Sync Promo + // dialog test('HasSkipButton', function() { assertEquals(inDialogDesign, isChildVisible(app, '#skipButton')); }); + + // Checks that clicking the Skip button triggers the correct browser proxy + // method. + if (inDialogDesign) { + test('ClickSkip', function() { + const skipButton = + app.shadowRoot!.querySelector<CrButtonElement>('#skipButton')!; + skipButton.click(); + return browserProxy.whenCalled('skip'); + }); + } }); });
diff --git a/chrome/test/data/webui/signin/test_profile_customization_browser_proxy.ts b/chrome/test/data/webui/signin/test_profile_customization_browser_proxy.ts index cc125a2..5738ab4 100644 --- a/chrome/test/data/webui/signin/test_profile_customization_browser_proxy.ts +++ b/chrome/test/data/webui/signin/test_profile_customization_browser_proxy.ts
@@ -10,7 +10,7 @@ private profileInfo_: ProfileInfo; constructor() { - super(['done', 'initialized']); + super(['done', 'initialized', 'skip']); this.profileInfo_ = { backgroundColor: '', @@ -32,4 +32,8 @@ done(profileName: string) { this.methodCalled('done', profileName); } + + skip() { + this.methodCalled('skip'); + } }
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM index ae0de0b..3e05b16 100644 --- a/chromeos/CHROMEOS_LKGM +++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@ -14906.0.0 \ No newline at end of file +14916.0.0 \ No newline at end of file
diff --git a/chromeos/ash/services/federated/public/cpp/fake_service_connection.cc b/chromeos/ash/services/federated/public/cpp/fake_service_connection.cc index 1adac6f..8fb049570 100644 --- a/chromeos/ash/services/federated/public/cpp/fake_service_connection.cc +++ b/chromeos/ash/services/federated/public/cpp/fake_service_connection.cc
@@ -4,27 +4,30 @@ #include "chromeos/ash/services/federated/public/cpp/fake_service_connection.h" -namespace chromeos { +namespace ash { namespace federated { FakeServiceConnectionImpl::FakeServiceConnectionImpl() = default; FakeServiceConnectionImpl::~FakeServiceConnectionImpl() = default; void FakeServiceConnectionImpl::BindReceiver( - mojo::PendingReceiver<mojom::FederatedService> receiver) { + mojo::PendingReceiver<chromeos::federated::mojom::FederatedService> + receiver) { Clone(std::move(receiver)); } void FakeServiceConnectionImpl::Clone( - mojo::PendingReceiver<mojom::FederatedService> receiver) { + mojo::PendingReceiver<chromeos::federated::mojom::FederatedService> + receiver) { receivers_.Add(this, std::move(receiver)); } -void FakeServiceConnectionImpl::ReportExample(const std::string& client_name, - mojom::ExamplePtr example) { +void FakeServiceConnectionImpl::ReportExample( + const std::string& client_name, + chromeos::federated::mojom::ExamplePtr example) { LOG(INFO) << "In FakeServiceConnectionImpl::ReportExample, does nothing"; return; } } // namespace federated -} // namespace chromeos +} // namespace ash
diff --git a/chromeos/ash/services/federated/public/cpp/fake_service_connection.h b/chromeos/ash/services/federated/public/cpp/fake_service_connection.h index caf2d936..4066bf91 100644 --- a/chromeos/ash/services/federated/public/cpp/fake_service_connection.h +++ b/chromeos/ash/services/federated/public/cpp/fake_service_connection.h
@@ -13,14 +13,15 @@ #include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/cpp/bindings/receiver_set.h" -namespace chromeos { +namespace ash { namespace federated { -// Fake implementation of chromeos::federated::ServiceConnection. +// Fake implementation of ash::federated::ServiceConnection. // Handles BindReceiver by binding the receiver to itself. // For use with ServiceConnection::UseFakeServiceConnectionForTesting(). -class FakeServiceConnectionImpl : public ServiceConnection, - public mojom::FederatedService { +class FakeServiceConnectionImpl + : public ServiceConnection, + public chromeos::federated::mojom::FederatedService { public: FakeServiceConnectionImpl(); FakeServiceConnectionImpl(const FakeServiceConnectionImpl&) = delete; @@ -30,18 +31,20 @@ // ServiceConnection: void BindReceiver( - mojo::PendingReceiver<mojom::FederatedService> receiver) override; + mojo::PendingReceiver<chromeos::federated::mojom::FederatedService> + receiver) override; // mojom::FederatedService: - void Clone(mojo::PendingReceiver<mojom::FederatedService> receiver) override; + void Clone(mojo::PendingReceiver<chromeos::federated::mojom::FederatedService> + receiver) override; void ReportExample(const std::string& client_name, - mojom::ExamplePtr example) override; + chromeos::federated::mojom::ExamplePtr example) override; private: - mojo::ReceiverSet<mojom::FederatedService> receivers_; + mojo::ReceiverSet<chromeos::federated::mojom::FederatedService> receivers_; }; } // namespace federated -} // namespace chromeos +} // namespace ash #endif // CHROMEOS_ASH_SERVICES_FEDERATED_PUBLIC_CPP_FAKE_SERVICE_CONNECTION_H_
diff --git a/chromeos/ash/services/federated/public/cpp/federated_example_util.cc b/chromeos/ash/services/federated/public/cpp/federated_example_util.cc index 3eaae3efb0d..b3355c5 100644 --- a/chromeos/ash/services/federated/public/cpp/federated_example_util.cc +++ b/chromeos/ash/services/federated/public/cpp/federated_example_util.cc
@@ -4,20 +4,26 @@ #include "chromeos/ash/services/federated/public/cpp/federated_example_util.h" -namespace chromeos { +namespace ash { namespace federated { -mojom::ValueListPtr CreateInt64List(const std::vector<int64_t>& values) { - return mojom::ValueList::NewInt64List(mojom::Int64List::New(values)); +chromeos::federated::mojom::ValueListPtr CreateInt64List( + const std::vector<int64_t>& values) { + return chromeos::federated::mojom::ValueList::NewInt64List( + chromeos::federated::mojom::Int64List::New(values)); } -mojom::ValueListPtr CreateFloatList(const std::vector<double>& values) { - return mojom::ValueList::NewFloatList(mojom::FloatList::New(values)); +chromeos::federated::mojom::ValueListPtr CreateFloatList( + const std::vector<double>& values) { + return chromeos::federated::mojom::ValueList::NewFloatList( + chromeos::federated::mojom::FloatList::New(values)); } -mojom::ValueListPtr CreateStringList(const std::vector<std::string>& values) { - return mojom::ValueList::NewStringList(mojom::StringList::New(values)); +chromeos::federated::mojom::ValueListPtr CreateStringList( + const std::vector<std::string>& values) { + return chromeos::federated::mojom::ValueList::NewStringList( + chromeos::federated::mojom::StringList::New(values)); } } // namespace federated -} // namespace chromeos +} // namespace ash
diff --git a/chromeos/ash/services/federated/public/cpp/federated_example_util.h b/chromeos/ash/services/federated/public/cpp/federated_example_util.h index 7437dc2..b22fc7a 100644 --- a/chromeos/ash/services/federated/public/cpp/federated_example_util.h +++ b/chromeos/ash/services/federated/public/cpp/federated_example_util.h
@@ -10,15 +10,18 @@ #include "chromeos/ash/services/federated/public/mojom/example.mojom.h" -namespace chromeos { +namespace ash { namespace federated { // Helper functions for creating different ValueList. -mojom::ValueListPtr CreateInt64List(const std::vector<int64_t>& values); -mojom::ValueListPtr CreateFloatList(const std::vector<double>& values); -mojom::ValueListPtr CreateStringList(const std::vector<std::string>& values); +chromeos::federated::mojom::ValueListPtr CreateInt64List( + const std::vector<int64_t>& values); +chromeos::federated::mojom::ValueListPtr CreateFloatList( + const std::vector<double>& values); +chromeos::federated::mojom::ValueListPtr CreateStringList( + const std::vector<std::string>& values); } // namespace federated -} // namespace chromeos +} // namespace ash #endif // CHROMEOS_ASH_SERVICES_FEDERATED_PUBLIC_CPP_FEDERATED_EXAMPLE_UTIL_H_
diff --git a/chromeos/ash/services/federated/public/cpp/service_connection.cc b/chromeos/ash/services/federated/public/cpp/service_connection.cc index 6e334ea4..2f58667 100644 --- a/chromeos/ash/services/federated/public/cpp/service_connection.cc +++ b/chromeos/ash/services/federated/public/cpp/service_connection.cc
@@ -14,7 +14,7 @@ #include "mojo/public/cpp/system/invitation.h" #include "third_party/cros_system_api/dbus/service_constants.h" -namespace chromeos { +namespace ash { namespace federated { namespace { @@ -31,7 +31,8 @@ // ServiceConnection: void BindReceiver( - mojo::PendingReceiver<mojom::FederatedService> receiver) override; + mojo::PendingReceiver<chromeos::federated::mojom::FederatedService> + receiver) override; private: // Binds the top level interface |federated_service_| to an @@ -46,7 +47,7 @@ // Response callback for FederatedClient::BootstrapMojoConnection. void OnBootstrapMojoConnectionResponse(bool success); - mojo::Remote<mojom::FederatedService> federated_service_; + mojo::Remote<chromeos::federated::mojom::FederatedService> federated_service_; SEQUENCE_CHECKER(sequence_checker_); }; @@ -56,7 +57,8 @@ } void ServiceConnectionImpl::BindReceiver( - mojo::PendingReceiver<mojom::FederatedService> receiver) { + mojo::PendingReceiver<chromeos::federated::mojom::FederatedService> + receiver) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); BindFederatedServiceIfNeeded(); federated_service_->Clone(std::move(receiver)); @@ -81,8 +83,9 @@ // Bind our end of |pipe| to our mojo::Remote<FederatedService>. The daemon // should bind its end to a FederatedService implementation. - federated_service_.Bind(mojo::PendingRemote<mojom::FederatedService>( - std::move(pipe), 0u /* version */)); + federated_service_.Bind( + mojo::PendingRemote<chromeos::federated::mojom::FederatedService>( + std::move(pipe), 0u /* version */)); federated_service_.set_disconnect_handler(base::BindOnce( &ServiceConnectionImpl::OnMojoDisconnect, base::Unretained(this))); @@ -131,4 +134,4 @@ } } // namespace federated -} // namespace chromeos +} // namespace ash
diff --git a/chromeos/ash/services/federated/public/cpp/service_connection.h b/chromeos/ash/services/federated/public/cpp/service_connection.h index 122fbdfa1..1f27bef 100644 --- a/chromeos/ash/services/federated/public/cpp/service_connection.h +++ b/chromeos/ash/services/federated/public/cpp/service_connection.h
@@ -8,13 +8,13 @@ #include "chromeos/ash/services/federated/public/mojom/federated_service.mojom.h" #include "mojo/public/cpp/bindings/pending_receiver.h" -namespace chromeos { +namespace ash { namespace federated { // Encapsulates a connection to the Chrome OS Federated Service daemon via its // Mojo interface. Usage: // mojo::Remote<FederatedService> federated_service; -// chromeos::federated::ServiceConnection::GetInstance()->BindReceiver( +// ash::federated::ServiceConnection::GetInstance()->BindReceiver( // federated_service.BindNewPipeAndPassReceiver()); // if (federated_service) { // chromeos::federated::mojom::ExamplePtr example = ...; @@ -31,7 +31,8 @@ // Binds the receiver to the implementation in the Federated Service daemon. virtual void BindReceiver( - mojo::PendingReceiver<mojom::FederatedService> receiver) = 0; + mojo::PendingReceiver<chromeos::federated::mojom::FederatedService> + receiver) = 0; protected: ServiceConnection() = default; @@ -54,6 +55,6 @@ }; } // namespace federated -} // namespace chromeos +} // namespace ash #endif // CHROMEOS_ASH_SERVICES_FEDERATED_PUBLIC_CPP_SERVICE_CONNECTION_H_
diff --git a/chromeos/ash/services/federated/public/cpp/service_connection_unittest.cc b/chromeos/ash/services/federated/public/cpp/service_connection_unittest.cc index cd67e459..6dacd08 100644 --- a/chromeos/ash/services/federated/public/cpp/service_connection_unittest.cc +++ b/chromeos/ash/services/federated/public/cpp/service_connection_unittest.cc
@@ -16,7 +16,7 @@ #include "mojo/core/embedder/scoped_ipc_support.h" #include "testing/gtest/include/gtest/gtest.h" -namespace chromeos { +namespace ash { namespace federated { namespace { @@ -58,8 +58,8 @@ // Tests that BindReceiver runs OK (no crash) in a basic Mojo environment. TEST_F(FederatedServiceConnectionTest, ReportExample) { - mojo::Remote<mojom::FederatedService> federated_service; - chromeos::federated::ServiceConnection::GetInstance()->BindReceiver( + mojo::Remote<chromeos::federated::mojom::FederatedService> federated_service; + ServiceConnection::GetInstance()->BindReceiver( federated_service.BindNewPipeAndPassReceiver()); } @@ -70,8 +70,8 @@ ScopedFakeServiceConnectionForTest scoped_fake_for_test( &fake_service_connection); - mojo::Remote<mojom::FederatedService> federated_service; - chromeos::federated::ServiceConnection::GetInstance()->BindReceiver( + mojo::Remote<chromeos::federated::mojom::FederatedService> federated_service; + ServiceConnection::GetInstance()->BindReceiver( federated_service.BindNewPipeAndPassReceiver()); EXPECT_TRUE(federated_service.is_bound()); EXPECT_TRUE(federated_service.is_connected()); @@ -82,4 +82,4 @@ } // namespace } // namespace federated -} // namespace chromeos +} // namespace ash
diff --git a/chromeos/chromeos_strings.grd b/chromeos/chromeos_strings.grd index 0b95496..bb3e9dd9 100644 --- a/chromeos/chromeos_strings.grd +++ b/chromeos/chromeos_strings.grd
@@ -3413,10 +3413,16 @@ <message name="IDS_FEEDBACK_TOOL_SHARE_DIAGNOSTIC_DATA_LABEL" desc="Label showing the share diagnostic data."> Share diagnostic data </message> + <message name="IDS_FEEDBACK_TOOL_SCREENSHOT_LABEL" desc="Label for the screenshot field"> + Screenshot + </message> <!-- Confirmation Page --> <message name="IDS_FEEDBACK_TOOL_PAGE_TITLE_AFTER_SENT" desc="Label showing a thank you message as the title of the confirmation page after a report has been sent."> Thanks for your feedback </message> + <message name="IDS_FEEDBACK_TOOL_RESOURCES_DIAGNOSTICS_APP_LABEL" desc="Label of the diagnostics app"> + Diagnostics app + </message> <!-- End of Feedback Tool --> </messages> </release>
diff --git a/chromeos/chromeos_strings_grd/IDS_FEEDBACK_TOOL_RESOURCES_DIAGNOSTICS_APP_LABEL.png.sha1 b/chromeos/chromeos_strings_grd/IDS_FEEDBACK_TOOL_RESOURCES_DIAGNOSTICS_APP_LABEL.png.sha1 new file mode 100644 index 0000000..4f607c0 --- /dev/null +++ b/chromeos/chromeos_strings_grd/IDS_FEEDBACK_TOOL_RESOURCES_DIAGNOSTICS_APP_LABEL.png.sha1
@@ -0,0 +1 @@ +1a29394e35efa33c04ab03a3e42de689305d0ef2 \ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_FEEDBACK_TOOL_SCREENSHOT_LABEL.png.sha1 b/chromeos/chromeos_strings_grd/IDS_FEEDBACK_TOOL_SCREENSHOT_LABEL.png.sha1 new file mode 100644 index 0000000..e0278c0 --- /dev/null +++ b/chromeos/chromeos_strings_grd/IDS_FEEDBACK_TOOL_SCREENSHOT_LABEL.png.sha1
@@ -0,0 +1 @@ +956296e35b4f3c6c8c023b03684fabeba4e929f2 \ No newline at end of file
diff --git a/chromeos/crosapi/mojom/networking_private.mojom b/chromeos/crosapi/mojom/networking_private.mojom index 631ee57a..209b34d 100644 --- a/chromeos/crosapi/mojom/networking_private.mojom +++ b/chromeos/crosapi/mojom/networking_private.mojom
@@ -82,6 +82,10 @@ [MinVersion=2] OnPortalDetectionCompleted@3(string networkGuid, CaptivePortalStatus status); + + // Fired when any certificate list has changed. + [MinVersion=3] + OnCertificateListsChanged@4(); }; // This interface mirrors the NetworkingPrivateDelegate from Lacros to Ash to
diff --git a/components/autofill/content/renderer/form_autofill_util.cc b/components/autofill/content/renderer/form_autofill_util.cc index 4e9c8d3d..1b5cbac 100644 --- a/components/autofill/content/renderer/form_autofill_util.cc +++ b/components/autofill/content/renderer/form_autofill_util.cc
@@ -253,34 +253,37 @@ return std::u16string(); // Ignore elements known not to contain inferable labels. + bool skip_node = false; if (node.IsElementNode()) { const WebElement element = node.To<WebElement>(); - if (IsOptionElement(element) || IsScriptElement(element) || - IsNoScriptElement(element) || + if (IsOptionElement(element) || + (element.HasHTMLTagName("div") && base::Contains(divs_to_skip, node)) || (element.IsFormControlElement() && IsAutofillableElement(element.To<WebFormControlElement>()))) { return std::u16string(); } - - if (element.HasHTMLTagName("div") && base::Contains(divs_to_skip, node)) - return std::u16string(); + skip_node = IsScriptElement(element) || IsNoScriptElement(element); } - // Extract the text exactly at this node. - std::u16string node_text = node.NodeValue().Utf16(); + std::u16string node_text; - // Recursively compute the children's text. - // Preserve inter-element whitespace separation. - std::u16string child_text = - FindChildTextInner(node.FirstChild(), depth - 1, divs_to_skip); - bool add_space = node.IsTextNode() && node_text.empty(); - node_text = CombineAndCollapseWhitespace(node_text, child_text, add_space); + if (!skip_node) { + // Extract the text exactly at this node. + node_text = node.NodeValue().Utf16(); + + // Recursively compute the children's text. + // Preserve inter-element whitespace separation. + std::u16string child_text = + FindChildTextInner(node.FirstChild(), depth - 1, divs_to_skip); + bool add_space = node.IsTextNode() && node_text.empty(); + node_text = CombineAndCollapseWhitespace(node_text, child_text, add_space); + } // Recursively compute the siblings' text. // Again, preserve inter-element whitespace separation. std::u16string sibling_text = FindChildTextInner(node.NextSibling(), depth - 1, divs_to_skip); - add_space = node.IsTextNode() && node_text.empty(); + bool add_space = node.IsTextNode() && node_text.empty(); node_text = CombineAndCollapseWhitespace(node_text, sibling_text, add_space); return node_text; @@ -358,8 +361,13 @@ // A text node's value will be empty if it is for a line break. bool add_space = sibling.IsTextNode() && value.empty(); inferred_label_source = FormFieldData::LabelSource::kCombined; - inferred_label = - CombineAndCollapseWhitespace(value, inferred_label, add_space); + if (forward) { + inferred_label = + CombineAndCollapseWhitespace(inferred_label, value, add_space); + } else { + inferred_label = + CombineAndCollapseWhitespace(value, inferred_label, add_space); + } continue; } @@ -649,8 +657,14 @@ // e.g. <div>Some Text<span><input ...></span></div> // e.g. <div>Some Text</div><div><input ...></div> // -// Because this is already traversing the <div> structure, if it finds a <label> -// sibling along the way, infer from that <label>. +// Contrary to the other InferLabelFrom* functions, this functions walks up +// the DOM tree from the original input, instead of down from the surrounding +// tag. While doing so, if a <label> or text node sibling are found along the +// way, a label is inferred from them directly. For example, <div>First +// name<div><input></div>Last name<div><input></div></div> infers "First name" +// and "Last name" for the two inputs, respectively, by picking up the text +// nodes on the way to the surrounding div. Without doing so, the label of both +// inputs becomes "First nameLast name". std::u16string InferLabelFromDivTable(const WebFormControlElement& element) { WebNode node = element.ParentNode(); bool looking_for_parent = true; @@ -679,11 +693,21 @@ } looking_for_parent = false; - } else if (!looking_for_parent && HasTagName(node, *kLabel)) { - WebLabelElement label_element = node.To<WebLabelElement>(); - if (label_element.CorrespondingControl().IsNull()) + } else if (!looking_for_parent) { + // Infer a label from text nodes and unassigned <label> siblings. + if (HasTagName(node, *kLabel) && + node.To<WebLabelElement>().CorrespondingControl().IsNull()) { inferred_label = FindChildText(node); - } else if (looking_for_parent && IsTraversableContainerElement(node)) { + } else if (node.IsTextNode()) { + // TODO(crbug.com/796918): Ideally `FindChildText()` should be used + // here as well. But because the function doesn't trim it's return + // value on every code path, the `NodeValue()` is explicitly extracted + // here. Trimming is necessary to skip indentation. + inferred_label = node.NodeValue().Utf16(); + base::TrimWhitespace(inferred_label, base::TrimPositions::TRIM_ALL, + &inferred_label); + } + } else if (IsTraversableContainerElement(node)) { // If the element is in a non-div container, its label most likely is too. break; }
diff --git a/components/autofill/content/renderer/form_autofill_util_browsertest.cc b/components/autofill/content/renderer/form_autofill_util_browsertest.cc index 6c2874f..62445ea 100644 --- a/components/autofill/content/renderer/form_autofill_util_browsertest.cc +++ b/components/autofill/content/renderer/form_autofill_util_browsertest.cc
@@ -127,7 +127,12 @@ "</div></div></div></div></div></div></div></div></div></div></div></" "div>", u"child0child1child2child3child4"}, - }; + {"Skip script tags", + "<div id='target'><script>alert('hello');</script>label</div>", + u"label"}, + {"Script tag whitespacing", + "<div id='target'>Auto<script>alert('hello');</script>fill</div>", + u"Autofill"}}; for (auto test_case : test_cases) { SCOPED_TRACE(test_case.description); LoadHTML(test_case.html); @@ -188,20 +193,18 @@ <div><input id=target></div> </div>)", u"label"}, - // TODO(crbug.com/796918): Should be label {"DIV table test 4", R"( <div> <div>should be skipped<input></div> label <div><input id=target></div> </div>)", - u""}, - // TODO(crbug.com/796918): Should be label + u"label"}, {"DIV table test 5", "<div>" "<div>label<div><input id='target'/></div>behind</div>" "</div>", - u"labelbehind"}, + u"label"}, {"DIV table test 6", R"( <div> label @@ -211,6 +214,8 @@ // TODO(crbug.com/796918): Should be "label" or "label-". This happens // because "-" is inferred, but discarded because `!IsLabelValid()`. u""}, + {"Infer from next sibling", + "<input id='target' type='checkbox'>hello <b>world</b>", u"hello world"}, }; for (auto test_case : test_cases) { SCOPED_TRACE(test_case.description); @@ -249,7 +254,11 @@ FormFieldData::LabelSource::kAriaLabel}, {"<input id='target' value='label'/>", FormFieldData::LabelSource::kValue}, + // In the next test, the text node is picked up on the way up the DOM-tree + // by the div extraction logic. {"<li>label<div><input id='target'/></div></li>", + FormFieldData::LabelSource::kDivTable}, + {"<li><span>label</span><div><input id='target'/></div></li>", FormFieldData::LabelSource::kLiTag}, {"<table><tr><td>label</td><td><input id='target'/></td></tr></table>", FormFieldData::LabelSource::kTdTag},
diff --git a/components/autofill/core/browser/BUILD.gn b/components/autofill/core/browser/BUILD.gn index 41504cf..37d2480 100644 --- a/components/autofill/core/browser/BUILD.gn +++ b/components/autofill/core/browser/BUILD.gn
@@ -421,13 +421,6 @@ sources += get_target_outputs(":regex_patterns_inl_h") - if (is_win) { - sources += [ - "autofill_ie_toolbar_import_win.cc", - "autofill_ie_toolbar_import_win.h", - ] - } - if (is_ios) { sources += [ "autofill_save_update_address_profile_delegate_ios.cc", @@ -876,10 +869,6 @@ "webdata/web_data_service_unittest.cc", ] - if (is_win) { - sources += [ "autofill_ie_toolbar_import_win_unittest.cc" ] - } - if (is_ios) { sources += [ "autofill_save_update_address_profile_delegate_ios_unittest.cc" ]
diff --git a/components/autofill/core/browser/autofill_ie_toolbar_import_win.cc b/components/autofill/core/browser/autofill_ie_toolbar_import_win.cc deleted file mode 100644 index bf3af43c9..0000000 --- a/components/autofill/core/browser/autofill_ie_toolbar_import_win.cc +++ /dev/null
@@ -1,306 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/autofill/core/browser/autofill_ie_toolbar_import_win.h" - -#include <stddef.h> -#include <stdint.h> -#include <map> -#include <string> -#include <vector> - -#include "base/check.h" -#include "base/compiler_specific.h" -#include "base/memory/raw_ptr.h" -#include "base/win/registry.h" -#include "components/autofill/core/browser/crypto/rc4_decryptor.h" -#include "components/autofill/core/browser/data_model/autofill_profile.h" -#include "components/autofill/core/browser/data_model/credit_card.h" -#include "components/autofill/core/browser/data_model/form_group.h" -#include "components/autofill/core/browser/data_model/phone_number.h" -#include "components/autofill/core/browser/field_types.h" -#include "components/autofill/core/browser/geo/autofill_country.h" -#include "components/autofill/core/browser/geo/phone_number_i18n.h" -#include "components/autofill/core/browser/personal_data_manager.h" -#include "components/autofill/core/browser/personal_data_manager_observer.h" -#include "components/os_crypt/os_crypt.h" - -using base::win::RegKey; - -namespace autofill { - -// Forward declaration. This function is not in unnamed namespace as it -// is referenced in the unittest. -bool ImportCurrentUserProfiles(const std::string& app_locale, - std::vector<AutofillProfile>* profiles, - std::vector<CreditCard>* credit_cards); -namespace { - -const wchar_t* const kProfileKey = - L"Software\\Google\\Google Toolbar\\4.0\\Autofill\\Profiles"; -const wchar_t* const kCreditCardKey = - L"Software\\Google\\Google Toolbar\\4.0\\Autofill\\Credit Cards"; -const wchar_t* const kPasswordHashValue = L"password_hash"; -const wchar_t* const kSaltValue = L"salt"; - -// This string is stored along with saved addresses and credit cards in the -// WebDB, and hence should not be modified, so that it remains consistent over -// time. -const char kIEToolbarImportOrigin[] = "Imported from Internet Explorer"; - -// This is RC4 decryption for Toolbar credit card data. This is necessary -// because it is not standard, so Crypto API cannot be used. -std::wstring DecryptCCNumber(const std::wstring& data) { - const wchar_t* kEmptyKey = - L"\x3605\xCEE5\xCE49\x44F7\xCF4E\xF6CC\x604B\xFCBE\xC70A\x08FD"; - const size_t kMacLen = 10; - - if (data.length() <= kMacLen) - return std::wstring(); - - RC4Decryptor rc4_algorithm(kEmptyKey); - return rc4_algorithm.Run(data.substr(kMacLen)); -} - -bool IsEmptySalt(std::wstring const& salt) { - // Empty salt in IE Toolbar is \x1\x2...\x14 - if (salt.length() != 20) - return false; - for (size_t i = 0; i < salt.length(); ++i) { - if (salt[i] != i + 1) - return false; - } - return true; -} - -std::wstring ReadAndDecryptValue(const RegKey& key, const wchar_t* value_name) { - DWORD data_type = REG_BINARY; - DWORD data_size = 0; - LONG result = key.ReadValue(value_name, nullptr, &data_size, &data_type); - if ((result != ERROR_SUCCESS) || !data_size || data_type != REG_BINARY) - return std::wstring(); - std::string data; - data.resize(data_size); - result = key.ReadValue(value_name, &(data[0]), &data_size, &data_type); - if (result == ERROR_SUCCESS) { - std::string out_data; - if (OSCrypt::DecryptString(data, &out_data)) { - // The actual data is in UTF16 already. - if (!(out_data.size() & 1) && (out_data.size() > 2) && - !out_data[out_data.size() - 1] && !out_data[out_data.size() - 2]) { - return reinterpret_cast<const wchar_t*>(out_data.c_str()); - } - } - } - return std::wstring(); -} - -struct { - ServerFieldType field_type; - const wchar_t *reg_value_name; -} profile_reg_values[] = { - {NAME_FIRST, L"name_first"}, - {NAME_MIDDLE, L"name_middle"}, - {NAME_LAST, L"name_last"}, - {NAME_SUFFIX, L"name_suffix"}, - {EMAIL_ADDRESS, L"email"}, - {COMPANY_NAME, L"company_name"}, - {PHONE_HOME_NUMBER, L"phone_home_number"}, - {PHONE_HOME_CITY_CODE, L"phone_home_city_code"}, - {PHONE_HOME_COUNTRY_CODE, L"phone_home_country_code"}, - {ADDRESS_HOME_LINE1, L"address_home_line1"}, - {ADDRESS_HOME_LINE2, L"address_home_line2"}, - {ADDRESS_HOME_CITY, L"address_home_city"}, - {ADDRESS_HOME_STATE, L"address_home_state"}, - {ADDRESS_HOME_ZIP, L"address_home_zip"}, - {ADDRESS_HOME_COUNTRY, L"address_home_country"}, - {ADDRESS_BILLING_LINE1, L"address_billing_line1"}, - {ADDRESS_BILLING_LINE2, L"address_billing_line2"}, - {ADDRESS_BILLING_CITY, L"address_billing_city"}, - {ADDRESS_BILLING_STATE, L"address_billing_state"}, - {ADDRESS_BILLING_ZIP, L"address_billing_zip"}, - {ADDRESS_BILLING_COUNTRY, L"address_billing_country"}, - {CREDIT_CARD_NAME_FULL, L"credit_card_name_full"}, - {CREDIT_CARD_NUMBER, L"credit_card_number"}, - {CREDIT_CARD_EXP_MONTH, L"credit_card_exp_month"}, - {CREDIT_CARD_EXP_4_DIGIT_YEAR, L"credit_card_exp_4_digit_year"}, - {CREDIT_CARD_TYPE, L"credit_card_type"}, - // We do not import verification code. -}; - -typedef std::map<std::wstring, ServerFieldType> RegToFieldMap; - -// Imports address or credit card data from the given registry |key| into the -// given |form_group|, with the help of |reg_to_field|. When importing address -// data, writes the phone data into |phone|; otherwise, |phone| should be null. -// Returns true if any fields were set, false otherwise. -bool ImportSingleFormGroup(const RegKey& key, - const RegToFieldMap& reg_to_field, - const std::string& app_locale, - FormGroup* form_group, - PhoneNumber::PhoneCombineHelper* phone) { - if (!key.Valid()) - return false; - - bool has_non_empty_fields = false; - - for (uint32_t i = 0; i < key.GetValueCount(); ++i) { - std::wstring value_name; - if (key.GetValueNameAt(i, &value_name) != ERROR_SUCCESS) - continue; - - RegToFieldMap::const_iterator it = reg_to_field.find(value_name); - if (it == reg_to_field.end()) - continue; // This field is not imported. - - std::wstring field_value = ReadAndDecryptValue(key, value_name.c_str()); - if (!field_value.empty()) { - if (it->second == CREDIT_CARD_NUMBER) - field_value = DecryptCCNumber(field_value); - - // Phone numbers are stored piece-by-piece, and then reconstructed from - // the pieces. The rest of the fields are set "as is". - if (!phone || !phone->SetInfo(AutofillType(it->second), - base::WideToUTF16(field_value))) { - has_non_empty_fields = true; - form_group->SetInfo(AutofillType(it->second), - base::WideToUTF16(field_value), app_locale); - } - } - } - - return has_non_empty_fields; -} - -// Imports address data from the given registry |key| into the given |profile|, -// with the help of |reg_to_field|. Returns true if any fields were set, false -// otherwise. -bool ImportSingleProfile(const std::string& app_locale, - const RegKey& key, - const RegToFieldMap& reg_to_field, - AutofillProfile* profile) { - PhoneNumber::PhoneCombineHelper phone; - bool has_non_empty_fields = - ImportSingleFormGroup(key, reg_to_field, app_locale, profile, &phone); - - // Now re-construct the phones if needed. - std::u16string constructed_number; - if (phone.ParseNumber(*profile, app_locale, &constructed_number)) { - has_non_empty_fields = true; - profile->SetRawInfo(PHONE_HOME_WHOLE_NUMBER, constructed_number); - } - - return has_non_empty_fields; -} - -// Imports profiles from the IE toolbar and stores them. Asynchronous -// if PersonalDataManager has not been loaded yet. Deletes itself on completion. -class AutofillImporter : public PersonalDataManagerObserver { - public: - explicit AutofillImporter(PersonalDataManager* personal_data_manager) - : personal_data_manager_(personal_data_manager) { - personal_data_manager_->AddObserver(this); - } - - bool ImportProfiles() { - if (!ImportCurrentUserProfiles(personal_data_manager_->app_locale(), - &profiles_, - &credit_cards_)) { - delete this; - return false; - } - if (personal_data_manager_->IsDataLoaded()) - OnPersonalDataChanged(); - return true; - } - - // PersonalDataManagerObserver: - void OnPersonalDataChanged() override { - for (const AutofillProfile& it : profiles_) - personal_data_manager_->AddProfile(it); - for (const CreditCard& it : credit_cards_) - personal_data_manager_->AddCreditCard(it); - delete this; - } - - private: - ~AutofillImporter() override { personal_data_manager_->RemoveObserver(this); } - - raw_ptr<PersonalDataManager> personal_data_manager_; - std::vector<AutofillProfile> profiles_; - std::vector<CreditCard> credit_cards_; -}; - -} // namespace - -// Imports Autofill profiles and credit cards from IE Toolbar if present and not -// password protected. Returns true if data is successfully retrieved. False if -// there is no data, data is password protected or error occurred. -bool ImportCurrentUserProfiles(const std::string& app_locale, - std::vector<AutofillProfile>* profiles, - std::vector<CreditCard>* credit_cards) { - DCHECK(profiles); - DCHECK(credit_cards); - - // Create a map of possible fields for a quick access. - RegToFieldMap reg_to_field; - for (const auto& profile_reg_value : profile_reg_values) { - reg_to_field[std::wstring(profile_reg_value.reg_value_name)] = - profile_reg_value.field_type; - } - - base::win::RegistryKeyIterator iterator_profiles(HKEY_CURRENT_USER, - kProfileKey); - for (; iterator_profiles.Valid(); ++iterator_profiles) { - std::wstring key_name(kProfileKey); - key_name.append(L"\\"); - key_name.append(iterator_profiles.Name()); - RegKey key(HKEY_CURRENT_USER, key_name.c_str(), KEY_READ); - AutofillProfile profile; - profile.set_origin(kIEToolbarImportOrigin); - if (ImportSingleProfile(app_locale, key, reg_to_field, &profile)) { - // Combine phones into whole phone #. - profiles->push_back(profile); - } - } - std::wstring password_hash; - std::wstring salt; - RegKey cc_key(HKEY_CURRENT_USER, kCreditCardKey, KEY_READ); - if (cc_key.Valid()) { - password_hash = ReadAndDecryptValue(cc_key, kPasswordHashValue); - salt = ReadAndDecryptValue(cc_key, kSaltValue); - } - - // We import CC profiles only if they are not password protected. - if (password_hash.empty() && IsEmptySalt(salt)) { - base::win::RegistryKeyIterator iterator_cc(HKEY_CURRENT_USER, - kCreditCardKey); - for (; iterator_cc.Valid(); ++iterator_cc) { - std::wstring key_name(kCreditCardKey); - key_name.append(L"\\"); - key_name.append(iterator_cc.Name()); - RegKey key(HKEY_CURRENT_USER, key_name.c_str(), KEY_READ); - CreditCard credit_card; - credit_card.set_origin(kIEToolbarImportOrigin); - if (ImportSingleFormGroup(key, reg_to_field, app_locale, &credit_card, - nullptr)) { - std::u16string cc_number = credit_card.GetRawInfo(CREDIT_CARD_NUMBER); - if (!cc_number.empty()) - credit_cards->push_back(credit_card); - } - } - } - return (profiles->size() + credit_cards->size()) > 0; -} - -bool ImportAutofillDataWin(PersonalDataManager* pdm) { - // In incognito mode we do not have PDM - and we should not import anything. - if (!pdm) - return false; - AutofillImporter* importer = new AutofillImporter(pdm); - // importer will self delete. - return importer->ImportProfiles(); -} - -} // namespace autofill
diff --git a/components/autofill/core/browser/autofill_ie_toolbar_import_win.h b/components/autofill/core/browser/autofill_ie_toolbar_import_win.h deleted file mode 100644 index 830aac25..0000000 --- a/components/autofill/core/browser/autofill_ie_toolbar_import_win.h +++ /dev/null
@@ -1,24 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_IE_TOOLBAR_IMPORT_WIN_H_ -#define COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_IE_TOOLBAR_IMPORT_WIN_H_ - -namespace autofill { - -// This importer is here and not in chrome/browser/importer/toolbar_importer.cc -// because of the following: -// 1. The data is not saved in profile, but rather in registry, thus it is -// accessed without going through toolbar front end. -// 2. This applies to IE (thus Windows) toolbar only. -// 3. The functionality relevant only to and completely encapsulated in the -// autofill. -// 4. This is completely automated as opposed to Importers, which are explicit. -class PersonalDataManager; - -bool ImportAutofillDataWin(PersonalDataManager* pdm); - -} // namespace autofill - -#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_IE_TOOLBAR_IMPORT_WIN_H_
diff --git a/components/autofill/core/browser/autofill_ie_toolbar_import_win_unittest.cc b/components/autofill/core/browser/autofill_ie_toolbar_import_win_unittest.cc deleted file mode 100644 index 22051ec..0000000 --- a/components/autofill/core/browser/autofill_ie_toolbar_import_win_unittest.cc +++ /dev/null
@@ -1,231 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/autofill/core/browser/autofill_ie_toolbar_import_win.h" - -#include <stddef.h> -#include <windows.h> - -#include <string> - -#include "base/strings/utf_string_conversions.h" -#include "base/win/registry.h" -#include "components/autofill/core/browser/data_model/autofill_profile.h" -#include "components/autofill/core/browser/data_model/credit_card.h" -#include "components/autofill/core/browser/field_types.h" -#include "components/os_crypt/os_crypt.h" -#include "components/os_crypt/os_crypt_mocker.h" -#include "testing/gtest/include/gtest/gtest.h" - -using base::win::RegKey; - -namespace autofill { - -// Defined in autofill_ie_toolbar_import_win.cc. Not exposed in the header file. -bool ImportCurrentUserProfiles(const std::string& app_locale, - std::vector<AutofillProfile>* profiles, - std::vector<CreditCard>* credit_cards); - -namespace { - -const wchar_t kUnitTestRegistrySubKey[] = L"SOFTWARE\\Chromium Unit Tests"; -const wchar_t kUnitTestUserOverrideSubKey[] = - L"SOFTWARE\\Chromium Unit Tests\\HKCU Override"; - -const wchar_t kProfileKey[] = - L"Software\\Google\\Google Toolbar\\4.0\\Autofill\\Profiles"; -const wchar_t kCreditCardKey[] = - L"Software\\Google\\Google Toolbar\\4.0\\Autofill\\Credit Cards"; -const wchar_t kPasswordHashValue[] = L"password_hash"; -const wchar_t kSaltValue[] = L"salt"; - -struct ValueDescription { - wchar_t const* const value_name; - wchar_t const* const value; -}; - -ValueDescription profile1[] = { - { L"name_first", L"John" }, - { L"name_middle", L"Herman" }, - { L"name_last", L"Doe" }, - { L"email", L"jdoe@test.com" }, - { L"company_name", L"Testcompany" }, - { L"phone_home_number", L"555-5555" }, - { L"phone_home_city_code", L"650" }, - { L"phone_home_country_code", L"1" }, -}; - -ValueDescription profile2[] = { - { L"name_first", L"Jane" }, - { L"name_last", L"Doe" }, - { L"email", L"janedoe@test.com" }, - { L"company_name", L"Testcompany" }, -}; - -ValueDescription credit_card[] = { - {L"credit_card_name_full", L"Tommy Gun"}, - // "4111111111111111" encrypted: - {L"credit_card_number", - L"\xE53F\x19AB\xC1BF\xC9EB\xECCC\x9BDA\x8515" - L"\xE14D\x6852\x80A8\x50A3\x4375\xFD9F\x1E07" - L"\x790E\x7336\xB773\xAF33\x93EA\xB846\xEC89" - L"\x265C\xD0E6\x4E23\xB75F\x7983"}, - {L"credit_card_exp_month", L"11"}, - {L"credit_card_exp_4_digit_year", L"2011"}, -}; - -ValueDescription empty_salt = { - kSaltValue, - L"\x1\x2\x3\x4\x5\x6\x7\x8\x9\xA\xB\xC\xD\xE\xF\x10\x11\x12\x13\x14" -}; - -ValueDescription empty_password = { - kPasswordHashValue, L"" -}; - -ValueDescription protected_salt = { - kSaltValue, L"\x4854\xB906\x9C7C\x50A6\x4376\xFD9D\x1E02" -}; - -ValueDescription protected_password = { - kPasswordHashValue, L"\x18B7\xE586\x459B\x7457\xA066\x3842\x71DA" -}; - -void EncryptAndWrite(RegKey* key, const ValueDescription* value) { - std::string data; - size_t data_size = (lstrlen(value->value) + 1) * sizeof(wchar_t); - data.resize(data_size); - memcpy(&data[0], value->value, data_size); - - std::string encrypted_data; - OSCrypt::EncryptString(data, &encrypted_data); - EXPECT_EQ(ERROR_SUCCESS, key->WriteValue(value->value_name, - &encrypted_data[0], encrypted_data.size(), REG_BINARY)); -} - -void CreateSubkey(RegKey* key, wchar_t const* subkey_name, - const ValueDescription* values, size_t values_size) { - RegKey subkey; - subkey.Create(key->Handle(), subkey_name, KEY_ALL_ACCESS); - EXPECT_TRUE(subkey.Valid()); - for (size_t i = 0; i < values_size; ++i) - EncryptAndWrite(&subkey, values + i); -} - -} // namespace - -class AutofillIeToolbarImportTest : public testing::Test { - public: - AutofillIeToolbarImportTest(); - - AutofillIeToolbarImportTest(const AutofillIeToolbarImportTest&) = delete; - AutofillIeToolbarImportTest& operator=(const AutofillIeToolbarImportTest&) = - delete; - - // testing::Test method overrides: - void SetUp() override; - void TearDown() override; - - private: - RegKey temp_hkcu_hive_key_; -}; - -AutofillIeToolbarImportTest::AutofillIeToolbarImportTest() { -} - -void AutofillIeToolbarImportTest::SetUp() { - OSCryptMocker::SetUp(); - temp_hkcu_hive_key_.Create(HKEY_CURRENT_USER, - kUnitTestUserOverrideSubKey, - KEY_ALL_ACCESS); - EXPECT_TRUE(temp_hkcu_hive_key_.Valid()); - EXPECT_EQ(ERROR_SUCCESS, RegOverridePredefKey(HKEY_CURRENT_USER, - temp_hkcu_hive_key_.Handle())); -} - -void AutofillIeToolbarImportTest::TearDown() { - EXPECT_EQ(ERROR_SUCCESS, RegOverridePredefKey(HKEY_CURRENT_USER, nullptr)); - temp_hkcu_hive_key_.Close(); - RegKey key(HKEY_CURRENT_USER, kUnitTestRegistrySubKey, KEY_ALL_ACCESS); - key.DeleteKey(L""); - OSCryptMocker::TearDown(); -} - -TEST_F(AutofillIeToolbarImportTest, TestAutofillImport) { - RegKey profile_key; - profile_key.Create(HKEY_CURRENT_USER, kProfileKey, KEY_ALL_ACCESS); - EXPECT_TRUE(profile_key.Valid()); - - CreateSubkey(&profile_key, L"0", profile1, std::size(profile1)); - CreateSubkey(&profile_key, L"1", profile2, std::size(profile2)); - - RegKey cc_key; - cc_key.Create(HKEY_CURRENT_USER, kCreditCardKey, KEY_ALL_ACCESS); - EXPECT_TRUE(cc_key.Valid()); - CreateSubkey(&cc_key, L"0", credit_card, std::size(credit_card)); - EncryptAndWrite(&cc_key, &empty_password); - EncryptAndWrite(&cc_key, &empty_salt); - - profile_key.Close(); - cc_key.Close(); - - std::vector<AutofillProfile> profiles; - std::vector<CreditCard> credit_cards; - EXPECT_TRUE(ImportCurrentUserProfiles("en-US", &profiles, &credit_cards)); - ASSERT_EQ(2U, profiles.size()); - // The profiles are read in reverse order. - EXPECT_EQ(base::WideToUTF16(profile1[0].value), - profiles[1].GetRawInfo(NAME_FIRST)); - EXPECT_EQ(base::WideToUTF16(profile1[1].value), - profiles[1].GetRawInfo(NAME_MIDDLE)); - EXPECT_EQ(base::WideToUTF16(profile1[2].value), - profiles[1].GetRawInfo(NAME_LAST)); - EXPECT_EQ(base::WideToUTF16(profile1[3].value), - profiles[1].GetRawInfo(EMAIL_ADDRESS)); - EXPECT_EQ(base::WideToUTF16(profile1[4].value), - profiles[1].GetRawInfo(COMPANY_NAME)); - EXPECT_EQ(base::WideToUTF16(profile1[7].value), - profiles[1].GetInfo(AutofillType(PHONE_HOME_COUNTRY_CODE), "US")); - EXPECT_EQ(base::WideToUTF16(profile1[6].value), - profiles[1].GetInfo(AutofillType(PHONE_HOME_CITY_CODE), "US")); - EXPECT_EQ(u"5555555", - profiles[1].GetInfo(AutofillType(PHONE_HOME_NUMBER), "US")); - EXPECT_EQ(u"1 650-555-5555", profiles[1].GetRawInfo(PHONE_HOME_WHOLE_NUMBER)); - - EXPECT_EQ(base::WideToUTF16(profile2[0].value), - profiles[0].GetRawInfo(NAME_FIRST)); - EXPECT_EQ(base::WideToUTF16(profile2[1].value), - profiles[0].GetRawInfo(NAME_LAST)); - EXPECT_EQ(base::WideToUTF16(profile2[2].value), - profiles[0].GetRawInfo(EMAIL_ADDRESS)); - EXPECT_EQ(base::WideToUTF16(profile2[3].value), - profiles[0].GetRawInfo(COMPANY_NAME)); - - ASSERT_EQ(1U, credit_cards.size()); - EXPECT_EQ(base::WideToUTF16(credit_card[0].value), - credit_cards[0].GetRawInfo(CREDIT_CARD_NAME_FULL)); - EXPECT_EQ(u"4111111111111111", - credit_cards[0].GetRawInfo(CREDIT_CARD_NUMBER)); - EXPECT_EQ(base::WideToUTF16(credit_card[2].value), - credit_cards[0].GetRawInfo(CREDIT_CARD_EXP_MONTH)); - EXPECT_EQ(base::WideToUTF16(credit_card[3].value), - credit_cards[0].GetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR)); - - // Mock password encrypted cc. - cc_key.Open(HKEY_CURRENT_USER, kCreditCardKey, KEY_ALL_ACCESS); - EXPECT_TRUE(cc_key.Valid()); - EncryptAndWrite(&cc_key, &protected_password); - EncryptAndWrite(&cc_key, &protected_salt); - cc_key.Close(); - - profiles.clear(); - credit_cards.clear(); - EXPECT_TRUE(ImportCurrentUserProfiles("en-US", &profiles, &credit_cards)); - // Profiles are not protected. - EXPECT_EQ(2U, profiles.size()); - // Credit cards are. - EXPECT_EQ(0U, credit_cards.size()); -} - -} // namespace autofill
diff --git a/components/autofill/core/browser/crypto/rc4_decryptor.h b/components/autofill/core/browser/crypto/rc4_decryptor.h deleted file mode 100644 index 4598274..0000000 --- a/components/autofill/core/browser/crypto/rc4_decryptor.h +++ /dev/null
@@ -1,112 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_CRYPTO_RC4_DECRYPTOR_H_ -#define COMPONENTS_AUTOFILL_CORE_BROWSER_CRYPTO_RC4_DECRYPTOR_H_ - -#include <stdint.h> -#include <string.h> - -#include <memory> -#include <string> - -namespace autofill { - -// This is modified RC4 decryption used for import of Toolbar autofill data -// only. The difference from the Crypto Api implementation is twofold: -// First, it uses a non-standard key size (160 bit), not supported by Microsoft -// (it supports only 40 and 128 bit for RC4). Second, it codes 128 words with -// value 0x0020 at the beginning of the code to enhance security. -// -// This class used in -// components/autofill/core/browser/autofill_ie_toolbar_import_win.cc. -// -// This class should not be used anywhere else!!! -class RC4Decryptor { - public: - explicit RC4Decryptor(wchar_t const* password) { - PrepareKey(reinterpret_cast<const uint8_t*>(password), - wcslen(password) * sizeof(wchar_t)); - std::wstring data; - // First 128 bytes should be spaces. - data.resize(128, L' '); - Run(data.c_str()); - } - - // Run the algorithm - std::wstring Run(const std::wstring& data) { - int data_size = data.length() * sizeof(wchar_t); - - std::unique_ptr<wchar_t[]> buffer(new wchar_t[data.length() + 1]); - memset(buffer.get(), 0, (data.length() + 1) * sizeof(wchar_t)); - memcpy(buffer.get(), data.c_str(), data_size); - - RunInternal(reinterpret_cast<uint8_t*>(buffer.get()), data_size); - - std::wstring result(buffer.get()); - - // Clear the memory - memset(buffer.get(), 0, data_size); - return result; - } - - private: - static const int kKeyDataSize = 256; - struct Rc4Key { - uint8_t state[kKeyDataSize]; - uint8_t x; - uint8_t y; - }; - - void SwapByte(uint8_t* byte1, uint8_t* byte2) { - uint8_t temp = *byte1; - *byte1 = *byte2; - *byte2 = temp; - } - - void PrepareKey(const uint8_t* key_data, int key_data_len) { - uint8_t index1 = 0; - uint8_t index2 = 0; - uint8_t* state; - short counter; - - state = &key_.state[0]; - for (counter = 0; counter < kKeyDataSize; ++counter) - state[counter] = static_cast<uint8_t>(counter); - - key_.x = key_.y = 0; - - for (counter = 0; counter < kKeyDataSize; counter++) { - index2 = (key_data[index1] + state[counter] + index2) % kKeyDataSize; - SwapByte(&state[counter], &state[index2]); - index1 = (index1 + 1) % key_data_len; - } - } - - void RunInternal(uint8_t* buffer, int buffer_len) { - uint8_t x, y; - uint8_t xor_index = 0; - uint8_t* state; - int counter; - - x = key_.x; - y = key_.y; - state = &key_.state[0]; - for (counter = 0; counter < buffer_len; ++counter) { - x = (x + 1) % kKeyDataSize; - y = (state[x] + y) % kKeyDataSize; - SwapByte(&state[x], &state[y]); - xor_index = (state[x] + state[y]) % kKeyDataSize; - buffer[counter] ^= state[xor_index]; - } - key_.x = x; - key_.y = y; - } - - Rc4Key key_; -}; - -} // namespace autofill - -#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_CRYPTO_RC4_DECRYPTOR_H_
diff --git a/components/autofill/ios/form_util/resources/fill.js b/components/autofill/ios/form_util/resources/fill.js index 5c0b8f9..e71e7590 100644 --- a/components/autofill/ios/form_util/resources/fill.js +++ b/components/autofill/ios/form_util/resources/fill.js
@@ -1025,9 +1025,9 @@ } // Ignore elements known not to contain inferable labels. + let skipNode = false; if (node.nodeType === Node.ELEMENT_NODE) { - if (node.tagName === 'OPTION' || node.tagName === 'SCRIPT' || - node.tagName === 'NOSCRIPT') { + if (node.tagName === 'OPTION') { return ''; } if (__gCrWeb.form.isFormControlElement(/** @type {Element} */ (node))) { @@ -1036,6 +1036,7 @@ return ''; } } + skipNode = node.tagName === 'SCRIPT' || node.tagName === 'NOSCRIPT'; } if (node.tagName === 'DIV') { @@ -1047,30 +1048,33 @@ } // Extract the text exactly at this node. - let nodeText = __gCrWeb.fill.nodeValue(node); - if (node.nodeType === Node.TEXT_NODE && !nodeText) { - // In the C++ version, this text node would have been stripped completely. - // Just pass the buck. - return __gCrWeb.fill.findChildTextInner( - node.nextSibling, depth, divsToSkip); - } + let nodeText = ''; + if (!skipNode) { + nodeText = __gCrWeb.fill.nodeValue(node); + if (node.nodeType === Node.TEXT_NODE && !nodeText) { + // In the C++ version, this text node would have been stripped completely. + // Just pass the buck. + return __gCrWeb.fill.findChildTextInner( + node.nextSibling, depth, divsToSkip); + } - // Recursively compute the children's text. - // Preserve inter-element whitespace separation. - const childText = - __gCrWeb.fill.findChildTextInner(node.firstChild, depth - 1, divsToSkip); - let addSpace = node.nodeType === Node.TEXT_NODE && !nodeText; - // Emulate apparently incorrect Chromium behavior tracked in - // https://crbug.com/239819. - addSpace = false; - nodeText = - __gCrWeb.fill.combineAndCollapseWhitespace(nodeText, childText, addSpace); + // Recursively compute the children's text. + // Preserve inter-element whitespace separation. + const childText = __gCrWeb.fill.findChildTextInner( + node.firstChild, depth - 1, divsToSkip); + let addSpace = node.nodeType === Node.TEXT_NODE && !nodeText; + // Emulate apparently incorrect Chromium behavior tracked in + // https://crbug.com/239819. + addSpace = false; + nodeText = __gCrWeb.fill.combineAndCollapseWhitespace( + nodeText, childText, addSpace); + } // Recursively compute the siblings' text. // Again, preserve inter-element whitespace separation. const siblingText = __gCrWeb.fill.findChildTextInner(node.nextSibling, depth - 1, divsToSkip); - addSpace = node.nodeType === Node.TEXT_NODE && !nodeText; + let addSpace = node.nodeType === Node.TEXT_NODE && !nodeText; // Emulate apparently incorrect Chromium behavior tracked in // https://crbug.com/239819. addSpace = false; @@ -1174,8 +1178,13 @@ const value = __gCrWeb.fill.findChildText(sibling); // A text node's value will be empty if it is for a line break. const addSpace = nodeType === Node.TEXT_NODE && value.length === 0; - inferredLabel = __gCrWeb.fill.combineAndCollapseWhitespace( - value, inferredLabel, addSpace); + if (forward) { + inferredLabel = __gCrWeb.fill.combineAndCollapseWhitespace( + inferredLabel, value, addSpace); + } else { + inferredLabel = __gCrWeb.fill.combineAndCollapseWhitespace( + value, inferredLabel, addSpace); + } continue; } @@ -1575,8 +1584,14 @@ * e.g. <div>Some Text<span><input ...></span></div> * e.g. <div>Some Text</div><div><input ...></div> * - * Because this is already traversing the <div> structure, if it finds a <label> - * sibling along the way, infer from that <label>. + * Contrary to the other InferLabelFrom* functions, this functions walks up + * the DOM tree from the original input, instead of down from the surrounding + * tag. While doing so, if a <label> or text node sibling are found along the + * way, a label is inferred from them directly. For example, <div>First + * name<div><input></div>Last name<div><input></div></div> infers "First name" + * and "Last name" for the two inputs, respectively, by picking up the text + * nodes on the way to the surrounding div. Without doing so, the label of both + * inputs becomes "First nameLast name". * * It is based on the logic in * string16 InferLabelFromDivTable(const WebFormControlElement& element) @@ -1623,12 +1638,14 @@ } lookingForParent = false; - } else if (!lookingForParent && __gCrWeb.fill.hasTagName(node, 'label')) { - if (!node.control) { + } else if (!lookingForParent) { + // Infer a label from text nodes and unassigned <label> siblings. + if (__gCrWeb.fill.hasTagName(node, 'label') && !node.control) { inferredLabel = __gCrWeb.fill.findChildText(node); + } else if (node.nodeType === Node.TEXT_NODE) { + inferredLabel = __gCrWeb.fill.nodeValue(node).trim(); } - } else if ( - lookingForParent && __gCrWeb.fill.isTraversableContainerElement(node)) { + } else if (__gCrWeb.fill.isTraversableContainerElement(node)) { // If the element is in a non-div container, its label most likely is too. break; }
diff --git a/components/exo/wayland/clients/client_base.cc b/components/exo/wayland/clients/client_base.cc index 430f0b8..50f1a59f 100644 --- a/components/exo/wayland/clients/client_base.cc +++ b/components/exo/wayland/clients/client_base.cc
@@ -556,9 +556,8 @@ ui::OzonePlatform::InitParams ozone_params; ozone_params.single_process = true; ui::OzonePlatform::InitializeForGPU(ozone_params); - gl::GLDisplayEGL* display = static_cast<gl::GLDisplayEGL*>( - gl::init::InitializeGLOneOff(/*system_device_id=*/0)); - DCHECK(display); + bool gl_initialized = gl::init::InitializeGLOneOff(/*system_device_id=*/0); + DCHECK(gl_initialized); gl_surface_ = gl::init::CreateOffscreenGLSurface(gfx::Size()); gl_context_ = gl::init::CreateGLContext(nullptr, // share_group @@ -567,11 +566,14 @@ make_current_ = std::make_unique<ui::ScopedMakeCurrent>(gl_context_.get(), gl_surface_.get()); - if (display->ext->b_EGL_EXT_image_flush_external || - display->ext->b_EGL_ARM_implicit_external_sync) { + if (gl::GLSurfaceEGL::GetGLDisplayEGL()->HasEGLExtension( + "EGL_EXT_image_flush_external") || + gl::GLSurfaceEGL::GetGLDisplayEGL()->HasEGLExtension( + "EGL_ARM_implicit_external_sync")) { egl_sync_type_ = EGL_SYNC_FENCE_KHR; } - if (display->ext->b_EGL_ANDROID_native_fence_sync) { + if (gl::GLSurfaceEGL::GetGLDisplayEGL()->HasEGLExtension( + "EGL_ANDROID_native_fence_sync")) { egl_sync_type_ = EGL_SYNC_NATIVE_FENCE_ANDROID; }
diff --git a/components/security_interstitials/content/cert_logger.proto b/components/security_interstitials/content/cert_logger.proto index 7b58b5b..750f7a8 100644 --- a/components/security_interstitials/content/cert_logger.proto +++ b/components/security_interstitials/content/cert_logger.proto
@@ -304,6 +304,7 @@ MAC_TRUST_IMPL_DOMAIN_CACHE = 1; MAC_TRUST_IMPL_SIMPLE = 2; MAC_TRUST_IMPL_MRU_CACHE = 3; + MAC_TRUST_IMPL_DOMAIN_CACHE_FULL_CERTS = 4; }; optional MacTrustImplType mac_trust_impl = 13;
diff --git a/components/security_interstitials/content/certificate_error_report.cc b/components/security_interstitials/content/certificate_error_report.cc index fa95730..d73084a3 100644 --- a/components/security_interstitials/content/certificate_error_report.cc +++ b/components/security_interstitials/content/certificate_error_report.cc
@@ -151,20 +151,20 @@ chrome_browser_ssl::TrialVerificationInfo::MacTrustImplType TrustImplTypeFromMojom( cert_verifier::mojom::CertVerifierDebugInfo::MacTrustImplType input) { + using mojom_MacTrustImplType = + cert_verifier::mojom::CertVerifierDebugInfo::MacTrustImplType; + using chrome_browser_ssl::TrialVerificationInfo; switch (input) { - case cert_verifier::mojom::CertVerifierDebugInfo::MacTrustImplType:: - kUnknown: - return chrome_browser_ssl::TrialVerificationInfo::MAC_TRUST_IMPL_UNKNOWN; - case cert_verifier::mojom::CertVerifierDebugInfo::MacTrustImplType:: - kDomainCache: - return chrome_browser_ssl::TrialVerificationInfo:: - MAC_TRUST_IMPL_DOMAIN_CACHE; - case cert_verifier::mojom::CertVerifierDebugInfo::MacTrustImplType::kSimple: - return chrome_browser_ssl::TrialVerificationInfo::MAC_TRUST_IMPL_SIMPLE; - case cert_verifier::mojom::CertVerifierDebugInfo::MacTrustImplType:: - kLruCache: - return chrome_browser_ssl::TrialVerificationInfo:: - MAC_TRUST_IMPL_MRU_CACHE; + case mojom_MacTrustImplType::kUnknown: + return TrialVerificationInfo::MAC_TRUST_IMPL_UNKNOWN; + case mojom_MacTrustImplType::kDomainCache: + return TrialVerificationInfo::MAC_TRUST_IMPL_DOMAIN_CACHE; + case mojom_MacTrustImplType::kSimple: + return TrialVerificationInfo::MAC_TRUST_IMPL_SIMPLE; + case mojom_MacTrustImplType::kLruCache: + return TrialVerificationInfo::MAC_TRUST_IMPL_MRU_CACHE; + case mojom_MacTrustImplType::kDomainCacheFullCerts: + return TrialVerificationInfo::MAC_TRUST_IMPL_DOMAIN_CACHE_FULL_CERTS; } } #endif // BUILDFLAG(IS_APPLE)
diff --git a/components/services/app_service/public/cpp/icon_types.cc b/components/services/app_service/public/cpp/icon_types.cc index 6d0bf3e..84155785 100644 --- a/components/services/app_service/public/cpp/icon_types.cc +++ b/components/services/app_service/public/cpp/icon_types.cc
@@ -76,78 +76,4 @@ } } -apps::mojom::IconValuePtr ConvertIconValueToMojomIconValue( - IconValuePtr icon_value) { - apps::mojom::IconValuePtr iv = apps::mojom::IconValue::New(); - if (!icon_value || icon_value->icon_type == IconType::kUnknown) { - return iv; - } - - iv->icon_type = ConvertIconTypeToMojomIconType(icon_value->icon_type); - iv->is_placeholder_icon = icon_value->is_placeholder_icon; - - switch (icon_value->icon_type) { - case IconType::kUnknown: - break; - case IconType::kCompressed: - iv->compressed = std::move(icon_value->compressed); - break; - case IconType::kUncompressed: - case IconType::kStandard: - iv->uncompressed = icon_value->uncompressed; - break; - } - - return iv; -} - -IconValuePtr ConvertMojomIconValueToIconValue( - apps::mojom::IconValuePtr mojom_icon_value) { - auto iv = std::make_unique<IconValue>(); - if (!mojom_icon_value) { - return iv; - } - - iv->icon_type = ConvertMojomIconTypeToIconType(mojom_icon_value->icon_type); - iv->is_placeholder_icon = mojom_icon_value->is_placeholder_icon; - - switch (mojom_icon_value->icon_type) { - case mojom::IconType::kUnknown: - break; - case mojom::IconType::kCompressed: - DCHECK(mojom_icon_value->compressed.has_value()); - iv->compressed = std::move(mojom_icon_value->compressed.value()); - break; - case mojom::IconType::kUncompressed: - case mojom::IconType::kStandard: - iv->uncompressed = mojom_icon_value->uncompressed; - break; - } - - return iv; -} - -base::OnceCallback<void(IconValuePtr)> IconValueToMojomIconValueCallback( - base::OnceCallback<void(apps::mojom::IconValuePtr)> callback) { - return base::BindOnce( - [](base::OnceCallback<void(apps::mojom::IconValuePtr)> inner_callback, - IconValuePtr icon_value) { - std::move(inner_callback) - .Run(ConvertIconValueToMojomIconValue(std::move(icon_value))); - }, - std::move(callback)); -} - -base::OnceCallback<void(apps::mojom::IconValuePtr)> -MojomIconValueToIconValueCallback( - base::OnceCallback<void(IconValuePtr)> callback) { - return base::BindOnce( - [](base::OnceCallback<void(IconValuePtr)> inner_callback, - apps::mojom::IconValuePtr icon_value) { - std::move(inner_callback) - .Run(ConvertMojomIconValueToIconValue(std::move(icon_value))); - }, - std::move(callback)); -} - } // namespace apps
diff --git a/components/services/app_service/public/cpp/icon_types.h b/components/services/app_service/public/cpp/icon_types.h index 136028b..64bdd086 100644 --- a/components/services/app_service/public/cpp/icon_types.h +++ b/components/services/app_service/public/cpp/icon_types.h
@@ -121,23 +121,6 @@ COMPONENT_EXPORT(ICON_TYPES) IconType ConvertMojomIconTypeToIconType(apps::mojom::IconType mojom_icon_type); -COMPONENT_EXPORT(ICON_TYPES) -apps::mojom::IconValuePtr ConvertIconValueToMojomIconValue( - IconValuePtr icon_value); - -COMPONENT_EXPORT(ICON_TYPES) -IconValuePtr ConvertMojomIconValueToIconValue( - apps::mojom::IconValuePtr mojom_icon_value); - -COMPONENT_EXPORT(ICON_TYPES) -base::OnceCallback<void(IconValuePtr)> IconValueToMojomIconValueCallback( - base::OnceCallback<void(apps::mojom::IconValuePtr)> callback); - -COMPONENT_EXPORT(ICON_TYPES) -base::OnceCallback<void(apps::mojom::IconValuePtr)> -MojomIconValueToIconValueCallback( - base::OnceCallback<void(IconValuePtr)> callback); - } // namespace apps #endif // COMPONENTS_SERVICES_APP_SERVICE_PUBLIC_CPP_ICON_TYPES_H_
diff --git a/components/services/app_service/public/mojom/types.mojom b/components/services/app_service/public/mojom/types.mojom index 7783e70..c59aa337 100644 --- a/components/services/app_service/public/mojom/types.mojom +++ b/components/services/app_service/public/mojom/types.mojom
@@ -249,13 +249,6 @@ kStandard, }; -struct IconValue { - IconType icon_type; - gfx.mojom.ImageSkia? uncompressed; - array<uint8>? compressed; - bool is_placeholder_icon; -}; - // Enumeration of possible app launch sources. // This should be kept in sync with metadata/apps/histograms.xml, and // LaunchSource in enums.xml.
diff --git a/components/services/screen_ai/proto/chrome_screen_ai.proto b/components/services/screen_ai/proto/chrome_screen_ai.proto index 4467ccb..2017ee7a 100644 --- a/components/services/screen_ai/proto/chrome_screen_ai.proto +++ b/components/services/screen_ai/proto/chrome_screen_ai.proto
@@ -239,10 +239,6 @@ Type enum_type = 1; string string_type = 2; } - - // A confidence score in the range of [0, 1], indicating how confident the - // model is of the given type prediction. Closer to 1 means more confident. - float confidence = 3; } PredictedType predicted_type = 1; @@ -265,10 +261,10 @@ } enum Direction { - LEFT_TO_RIGHT = 0; - RIGHT_TO_LEFT = 1; - UNSPECIFIED = 2; - TOP_TO_BOTTOM = 3; + DIRECTION_UNSPECIFIED = 0; + DIRECTION_LEFT_TO_RIGHT = 1; + DIRECTION_RIGHT_TO_LEFT = 2; + DIRECTION_TOP_TO_BOTTOM = 3; } // Text line with associated bounding box. @@ -283,26 +279,22 @@ // Text line in UTF8 format. string utf8_string = 3; - // Confidence as computed by the OCR engine. - float confidence = 4; - // Language guess for the line. The format is the ISO 639-1 two-letter // language code if that is defined (e.g. "en"), or else the ISO 639-2 // three-letter code if that is defined, or else a Google-specific code. - string language = 5; + string language = 4; // ID of the text block that this line belongs to. - int32 block_id = 6; + int32 block_id = 5; // Index within the block that this line belongs to. - int32 order_within_block = 7; + int32 order_within_block = 6; - // The direction of the script contained in the line. Directed by the enum - // Direction defined above. - int32 direction = 8; + // The direction of the script contained in the line. + Direction direction = 7; // Content type for this line. - ContentType content_type = 9; + ContentType content_type = 8; } // Word with associated bounding box. @@ -318,52 +310,42 @@ // Word string in UTF8 format. string utf8_string = 3; - // Confidence as computed by the OCR engine. - float confidence = 4; - // True if the word passes the internal beamsearch dictionary check. - bool dictionary_word = 5; + bool dictionary_word = 4; // Language guess for the word. The format is the ISO 639-1 two-letter // language code if that is defined (e.g. "en"), or else the ISO 639-2 // three-letter code if that is defined, or else a Google-specific code. - string language = 6; + string language = 5; // This word is separated from next word by space. - bool has_space_after = 7; + bool has_space_after = 6; // If true, foreground and background colors successfully detected. - bool estimate_color_success = 8; + bool estimate_color_success = 7; // Estimated grayscale value of foreground. - int32 foreground_gray_value = 9; + int32 foreground_gray_value = 8; // Estimated grayscale value of background. - int32 background_gray_value = 10; + int32 background_gray_value = 9; // Estimated RGB of foreground. Extracting RGB channels from this // integer is best done using the leptonica helper extractRGBValues(). - int32 foreground_rgb_value = 11; + int32 foreground_rgb_value = 10; // Estimated RGB of background. Extracting RGB channels from this // integer is best done using the leptonica helper extractRGBValues(). - int32 background_rgb_value = 12; + int32 background_rgb_value = 11; - // The direction of the script contained in the word. Directed by the enum - // Direction defined above. - int32 direction = 13; + // The direction of the script contained in the word. + Direction direction = 12; // Content type for this word. - ContentType content_type = 14; - - // If content_type == HANDWRITTEN, confidence on this word being handwritten. - float handwriting_confidence = 15; + ContentType content_type = 13; // Detected orientation of the text. - Orientation orientation = 16; - - // Confidence of langid language identification. - float language_confidence = 17; + Orientation orientation = 14; } // Symbol with associated bounding box. @@ -400,8 +382,6 @@ CONTENT_TYPE_HANDWRITTEN_FORMULA = 7; // Signature or intitals. CONTENT_TYPE_SIGNATURE = 8; - - CONTENT_TYPE_UNKNOWN = 100; } message VisualAnnotation {
diff --git a/components/services/screen_ai/proto/proto_convertor.cc b/components/services/screen_ai/proto/proto_convertor.cc index ba27b51..0e4fc82 100644 --- a/components/services/screen_ai/proto/proto_convertor.cc +++ b/components/services/screen_ai/proto/proto_convertor.cc
@@ -17,6 +17,9 @@ #include "base/check_op.h" #include "base/notreached.h" +#include "base/numerics/checked_math.h" +#include "base/numerics/clamped_math.h" +#include "base/ranges/ranges.h" #include "components/services/screen_ai/proto/chrome_screen_ai.pb.h" #include "components/services/screen_ai/proto/dimension.pb.h" #include "components/services/screen_ai/proto/view_hierarchy.pb.h" @@ -30,13 +33,9 @@ #include "ui/gfx/geometry/rect_f.h" #include "ui/gfx/geometry/transform.h" -namespace { +namespace ranges = base::ranges; -// The minimum confidence level that a Screen AI annotation should have to be -// accepted. -// TODO(https://crbug.com/1278249): Add experiment or heuristics to better -// adjust this threshold. -constexpr float kScreenAIMinConfidenceThreshold = 0.1f; +namespace { // Returns the next valid ID that can be used for identifying `AXNode`s in the // accessibility tree. @@ -45,6 +44,23 @@ return next_node_id++; } +bool HaveIdenticalFormattingStyle(const chrome_screen_ai::WordBox& word_1, + const chrome_screen_ai::WordBox& word_2) { + if (word_1.language() != word_2.language()) + return false; + if (word_1.estimate_color_success() && word_2.estimate_color_success()) { + if (word_1.foreground_rgb_value() != word_2.foreground_rgb_value()) + return false; + if (word_1.background_rgb_value() != word_2.background_rgb_value()) + return false; + } + if (word_1.direction() != word_2.direction()) + return false; + if (word_1.content_type() != word_2.content_type()) + return false; + return true; +} + // Returns whether the provided `predicted_type` is: // A) set, and // B) has a confidence that is above our acceptance threshold. @@ -52,15 +68,6 @@ const chrome_screen_ai::UIComponent::PredictedType& predicted_type, ui::AXNodeData& out_data) { DCHECK_EQ(out_data.role, ax::mojom::Role::kUnknown); - if (predicted_type.confidence() < 0.0f || - predicted_type.confidence() > 1.0f) { - NOTREACHED() - << "Unrecognized chrome_screen_ai::PredictedType::confidence value: " - << predicted_type.confidence(); - return false; // Confidence is out of bounds. - } - if (predicted_type.confidence() < kScreenAIMinConfidenceThreshold) - return false; switch (predicted_type.type_of_case()) { case chrome_screen_ai::UIComponent::PredictedType::kEnumType: // TODO(https://crbug.com/1278249): We do not actually need an enum. All @@ -88,9 +95,7 @@ out_data.relative_bounds.bounds = gfx::RectF(bounding_box.x(), bounding_box.y(), bounding_box.width(), bounding_box.height()); - // A negative width or height will result in an empty rect. - if (out_data.relative_bounds.bounds.IsEmpty()) - return; + DCHECK(!out_data.relative_bounds.bounds.IsEmpty()); if (container_id != ui::kInvalidAXNodeID) out_data.relative_bounds.offset_container_id = container_id; if (bounding_box.angle()) { @@ -101,25 +106,21 @@ void SerializeDirection(const chrome_screen_ai::Direction& direction, ui::AXNodeData& out_data) { - if (!chrome_screen_ai::Direction_IsValid(direction)) { - NOTREACHED() << "Unrecognized chrome_screen_ai::Direction value: " - << direction; - return; - } + DCHECK(chrome_screen_ai::Direction_IsValid(direction)); switch (direction) { - case chrome_screen_ai::Direction::UNSPECIFIED: + case chrome_screen_ai::DIRECTION_UNSPECIFIED: // We assume that LEFT_TO_RIGHT is the default direction. - case chrome_screen_ai::Direction::LEFT_TO_RIGHT: + case chrome_screen_ai::DIRECTION_LEFT_TO_RIGHT: out_data.AddIntAttribute( ax::mojom::IntAttribute::kTextDirection, static_cast<int32_t>(ax::mojom::WritingDirection::kLtr)); break; - case chrome_screen_ai::Direction::RIGHT_TO_LEFT: + case chrome_screen_ai::DIRECTION_RIGHT_TO_LEFT: out_data.AddIntAttribute( ax::mojom::IntAttribute::kTextDirection, static_cast<int32_t>(ax::mojom::WritingDirection::kRtl)); break; - case chrome_screen_ai::Direction::TOP_TO_BOTTOM: + case chrome_screen_ai::DIRECTION_TOP_TO_BOTTOM: out_data.AddIntAttribute( ax::mojom::IntAttribute::kTextDirection, static_cast<int32_t>(ax::mojom::WritingDirection::kTtb)); @@ -138,11 +139,7 @@ void SerializeContentType(const chrome_screen_ai::ContentType& content_type, ui::AXNodeData& out_data) { - if (!chrome_screen_ai::ContentType_IsValid(content_type)) { - NOTREACHED() << "Unrecognized chrome_screen_ai::ContentType value: " - << content_type; - return; - } + DCHECK(chrome_screen_ai::ContentType_IsValid(content_type)); switch (content_type) { case chrome_screen_ai::CONTENT_TYPE_PRINTED_TEXT: case chrome_screen_ai::CONTENT_TYPE_HANDWRITTEN_TEXT: @@ -175,13 +172,6 @@ // the user that this is a signature, e.g. via ARIA Annotations. out_data.role = ax::mojom::Role::kStaticText; break; - case chrome_screen_ai::CONTENT_TYPE_UNKNOWN: - // This should be "Role::kPresentational" but it has been erroniously - // removed from the codebase. - // TODO(nektar): Add presentational role back to avoid confusion with the - // meaning of kNone vs. kUnknown. - out_data.role = ax::mojom::Role::kNone; // Presentational. - break; case google::protobuf::kint32min: case google::protobuf::kint32max: // Ordinarily, a default case should have been added to permit future @@ -195,43 +185,145 @@ } void SerializeWordBox(const chrome_screen_ai::WordBox& word_box, - const size_t index, - ui::AXNodeData& parent_node, - std::vector<ui::AXNodeData>& node_data) { - DCHECK_LT(index, node_data.size()); - DCHECK_NE(parent_node.id, ui::kInvalidAXNodeID); - ui::AXNodeData& word_box_node = node_data[index]; - DCHECK_EQ(word_box_node.role, ax::mojom::Role::kUnknown); - if (word_box.confidence() < 0.0f || word_box.confidence() > 1.0f) { - NOTREACHED() << "Unrecognized chrome_screen_ai::WordBox::confidence value: " - << word_box.confidence(); - return; // Confidence is out of bounds. - } - if (word_box.confidence() < kScreenAIMinConfidenceThreshold) - return; - word_box_node.role = ax::mojom::Role::kInlineTextBox; - word_box_node.id = GetNextNodeID(); - SerializeBoundingBox(word_box.bounding_box(), parent_node.id, word_box_node); - // Since the role is `kInlineTextBox`, NameFrom would automatically and - // correctly be set to `ax::mojom::NameFrom::kContents`. + ui::AXNodeData& inline_text_box) { + DCHECK_NE(inline_text_box.id, ui::kInvalidAXNodeID); + // TODO(nektar): What if the angles of orientation are different, would the + // following DCHECK unnecessarily? Do we need to apply the related transform, + // or is the fact that the transform is the same between line and word boxes + // results in no difference? + DCHECK(inline_text_box.relative_bounds.bounds.Contains(gfx::RectF( + word_box.bounding_box().x(), word_box.bounding_box().y(), + word_box.bounding_box().width(), word_box.bounding_box().height()))); + + std::vector<int32_t> character_offsets; + // TODO(nektar): Handle writing directions other than LEFT_TO_RIGHT. + int32_t line_offset = + base::ClampRound(inline_text_box.relative_bounds.bounds.x()); + ranges::transform(word_box.symbols(), std::back_inserter(character_offsets), + [line_offset](const chrome_screen_ai::SymbolBox& symbol) { + return symbol.bounding_box().x() - line_offset; + }); + + std::string inner_text = + inline_text_box.GetStringAttribute(ax::mojom::StringAttribute::kName); + inner_text += word_box.utf8_string(); + size_t word_length = word_box.utf8_string().length(); if (word_box.has_space_after()) { - word_box_node.SetName(word_box.utf8_string() + " "); - } else { - word_box_node.SetName(word_box.utf8_string()); + inner_text += " "; + ++word_length; } - // TODO(nektar): DCHECK that line box's text is equal to the concatenation of - // the text found in all contained word boxes. - // TODO(nektar): Set character bounding box information. + inline_text_box.SetName(inner_text); + + std::vector<int32_t> word_starts = inline_text_box.GetIntListAttribute( + ax::mojom::IntListAttribute::kWordStarts); + std::vector<int32_t> word_ends = inline_text_box.GetIntListAttribute( + ax::mojom::IntListAttribute::kWordEnds); + int32_t new_word_start = 0; + int32_t new_word_end = base::checked_cast<int32_t>(word_length); + if (!word_ends.empty()) { + new_word_start += word_ends[word_ends.size() - 1]; + new_word_end += new_word_start; + } + word_starts.push_back(new_word_start); + word_ends.push_back(new_word_end); + inline_text_box.AddIntListAttribute(ax::mojom::IntListAttribute::kWordStarts, + word_starts); + inline_text_box.AddIntListAttribute(ax::mojom::IntListAttribute::kWordEnds, + word_ends); + DCHECK_LE(new_word_start, new_word_end); + DCHECK_LE( + new_word_end, + base::checked_cast<int32_t>( + inline_text_box.GetStringAttribute(ax::mojom::StringAttribute::kName) + .length())); + + if (!word_box.language().empty()) { + DCHECK_EQ(inline_text_box.GetStringAttribute( + ax ::mojom::StringAttribute::kLanguage), + word_box.language()) + << "A `WordBox` has a different language than its enclosing `LineBox`."; + } + if (word_box.estimate_color_success()) { - word_box_node.AddIntAttribute(ax::mojom::IntAttribute::kBackgroundColor, - word_box.background_rgb_value()); - word_box_node.AddIntAttribute(ax::mojom::IntAttribute::kColor, - word_box.foreground_rgb_value()); + if (!inline_text_box.HasIntAttribute( + ax::mojom::IntAttribute::kBackgroundColor)) { + inline_text_box.AddIntAttribute(ax::mojom::IntAttribute::kBackgroundColor, + word_box.background_rgb_value()); + } else { + DCHECK_EQ(inline_text_box.GetIntAttribute( + ax::mojom::IntAttribute::kBackgroundColor), + word_box.background_rgb_value()) + << "A `WordBox` has a different background color than its enclosing " + "`LineBox`."; + } + if (!inline_text_box.HasIntAttribute(ax::mojom::IntAttribute::kColor)) { + inline_text_box.AddIntAttribute(ax::mojom::IntAttribute::kColor, + word_box.foreground_rgb_value()); + } else { + DCHECK_EQ( + inline_text_box.GetIntAttribute(ax::mojom::IntAttribute::kColor), + word_box.foreground_rgb_value()) + << "A `WordBox` has a different foreground color than its enclosing " + "`LineBox`."; + } } - SerializeDirection( - static_cast<chrome_screen_ai::Direction>(word_box.direction()), - word_box_node); - parent_node.child_ids.push_back(word_box_node.id); + SerializeDirection(word_box.direction(), inline_text_box); +} + +// Creates an inline text box for every style span in the provided +// `static_text_node`, starting from `start_from_word_index` in the node's +// `word_boxes`. Returns the number of inline text box nodes that have been +// initialized in `node_data`. +size_t SerializeWordBoxes(const google::protobuf::RepeatedPtrField< + chrome_screen_ai::WordBox>& word_boxes, + const int start_from_word_index, + const size_t node_index, + ui::AXNodeData& static_text_node, + std::vector<ui::AXNodeData>& node_data) { + if (word_boxes.empty()) + return 0u; + DCHECK_LT(start_from_word_index, word_boxes.size()); + DCHECK_LT(node_index, node_data.size()); + DCHECK_NE(static_text_node.id, ui::kInvalidAXNodeID); + ui::AXNodeData& inline_text_box_node = node_data[node_index]; + DCHECK_EQ(inline_text_box_node.role, ax::mojom::Role::kUnknown); + inline_text_box_node.role = ax::mojom::Role::kInlineTextBox; + inline_text_box_node.id = GetNextNodeID(); + // TODO(nektar): Find the union of the bounding boxes in this formatting + // context and set it as the bounding box of `inline_text_box_node`. + inline_text_box_node.relative_bounds.bounds = + static_text_node.relative_bounds.bounds; + + std::string language; + if (static_text_node.GetStringAttribute(ax::mojom::StringAttribute::kLanguage, + &language)) { + // TODO(nektar): Only set language if different from parent node (i.e. the + // static text node), in order to minimize memory usage. + inline_text_box_node.AddStringAttribute( + ax::mojom::StringAttribute::kLanguage, language); + } + static_text_node.child_ids.push_back(inline_text_box_node.id); + + const auto formatting_context_start = + std::cbegin(word_boxes) + start_from_word_index; + const auto formatting_context_end = + ranges::find_if_not(formatting_context_start, ranges::end(word_boxes), + [formatting_context_start](const auto& word_box) { + return HaveIdenticalFormattingStyle( + *formatting_context_start, word_box); + }); + for (auto word_iter = formatting_context_start; + word_iter != formatting_context_end; ++word_iter) { + SerializeWordBox(*word_iter, inline_text_box_node); + } + if (formatting_context_end != std::cend(word_boxes)) { + return 1u + + SerializeWordBoxes( + word_boxes, + std::distance(std::cbegin(word_boxes), formatting_context_end), + (node_index + 1u), static_text_node, node_data); + } + return 1u; } void SerializeUIComponent(const chrome_screen_ai::UIComponent& ui_component, @@ -249,42 +341,39 @@ parent_node.child_ids.push_back(current_node.id); } -void SerializeLineBox(const chrome_screen_ai::LineBox& line_box, - const size_t index, - ui::AXNodeData& parent_node, - std::vector<ui::AXNodeData>& node_data) { +// Returns the number of accessibility nodes that have been initialized in +// `node_data`. A single `line_box` may turn into a number of inline text boxes +// depending on how many formatting contexts it contains. If `line_box` is of a +// non-textual nature, only one node will be initialized. +size_t SerializeLineBox(const chrome_screen_ai::LineBox& line_box, + const size_t index, + ui::AXNodeData& parent_node, + std::vector<ui::AXNodeData>& node_data) { DCHECK_LT(index, node_data.size()); DCHECK_NE(parent_node.id, ui::kInvalidAXNodeID); ui::AXNodeData& line_box_node = node_data[index]; DCHECK_EQ(line_box_node.role, ax::mojom::Role::kUnknown); - if (line_box.confidence() < 0.0f || line_box.confidence() > 1.0f) { - NOTREACHED() << "Unrecognized chrome_screen_ai::LineBox::confidence value: " - << line_box.confidence(); - return; // Confidence is out of bounds. - } - if (line_box.confidence() < kScreenAIMinConfidenceThreshold) - return; + SerializeContentType(line_box.content_type(), line_box_node); line_box_node.id = GetNextNodeID(); - if (ui::IsText(line_box_node.role)) { - size_t word_node_index = index + 1u; - for (const auto& word : line_box.words()) - SerializeWordBox(word, word_node_index++, line_box_node, node_data); - } SerializeBoundingBox(line_box.bounding_box(), parent_node.id, line_box_node); - // Since the role is `kStaticText`, NameFrom would automatically and correctly - // be set to `ax::mojom::NameFrom::kContents`. + // `ax::mojom::NameFrom` should be set to the correct value based on the + // role. line_box_node.SetName(line_box.utf8_string()); if (!line_box.language().empty()) { - // TODO(nektar): Only set language if different from parent node to - // minimize memory usage. + // TODO(nektar): Only set language if different from parent node (i.e. the + // page node), in order to minimize memory usage. line_box_node.AddStringAttribute(ax::mojom::StringAttribute::kLanguage, line_box.language()); } - SerializeDirection( - static_cast<chrome_screen_ai::Direction>(line_box.direction()), - line_box_node); + SerializeDirection(line_box.direction(), line_box_node); parent_node.child_ids.push_back(line_box_node.id); + + if (!ui::IsText(line_box_node.role)) + return 1u; + return 1u + SerializeWordBoxes(line_box.words(), + /* start_from_word_index */ 0, (index + 1u), + line_box_node, node_data); } // Adds the subtree of |nodes[node_index_to_add]| to |nodes_order| with @@ -319,26 +408,39 @@ // TODO(https://crbug.com/1278249): Create an AXTreeSource and create the // update using AXTreeSerializer. - // Each `UIComponent` and `LineBox` will take up one node in the accessibility + // Each `UIComponent`, `LineBox`, as well as every `WordBox` that results in a + // different formatting context, will take up one node in the accessibility // tree, resulting in hundreds of nodes, making it inefficient to push_back // one node at a time. We pre-allocate the needed nodes making node creation // an O(n) operation. - const size_t word_count = std::accumulate( - std::begin(visual_annotation.lines()), - std::end(visual_annotation.lines()), 0u, - [](const size_t& count, const chrome_screen_ai::LineBox& line_box) { - return count + line_box.words().size(); - }); + size_t formatting_context_count = 0u; + for (const chrome_screen_ai::LineBox& line : visual_annotation.lines()) { + // By design, and same as in Blink, every line creates a separate formatting + // context regardless as to whether the format styles are identical with + // previous lines or not. + ++formatting_context_count; + DCHECK(!line.words().empty()) + << "Empty lines should have been pruned in the Screen AI library."; + for (auto iter = std::cbegin(line.words()); + std::next(iter) != std::cend(line.words()); ++iter) { + if (!HaveIdenticalFormattingStyle(*iter, *std::next(iter))) + ++formatting_context_count; + } + } - // Each unique `chrome_screen_ai::LineBox::block_id` creates a new - // paragraph, each paragraph is placed in its correct reading order, - // and each paragraph has a sorted set of line boxes. Line boxes are sorted - // using their `chrome_screen_ai::LineBox::order_within_block` member and they - // are identified by their index in the container of line boxes. Use std::map - // to sort both paragraphs and lines, both operations having an O(n * log(n)) - // complexity. + // Each unique `chrome_screen_ai::LineBox::block_id` signifies a different + // block of text, and so it creates a new static text node in the + // accessibility tree. Each block has a sorted set of line boxes, everyone of + // which is turned into one or more inline text box nodes in the accessibility + // tree. Line boxes are sorted using their + // `chrome_screen_ai::LineBox::order_within_block` member and are identified + // by their index in the container of line boxes. Use std::map to sort both + // text blocks and the line boxes that belong to each one, both operations + // having an O(n * log(n)) complexity. + // TODO(accessibility): Create separate paragraphs based on the blocks' + // spacing. // TODO(accessibility): Determine reading order based on visual positioning of - // paragraphs, not on their block IDs. + // text blocks, not on the order of their block IDs. std::map<int32_t, std::map<int32_t, int>> blocks_to_lines_map; for (int i = 0; i < visual_annotation.lines_size(); ++i) { const chrome_screen_ai::LineBox& line = visual_annotation.lines(i); @@ -354,8 +456,8 @@ std::vector<ui::AXNodeData> nodes( rootnodes_count + visual_annotation.ui_component().size() + - blocks_to_lines_map.size() + visual_annotation.lines().size() + - word_count); + visual_annotation.lines().size() + formatting_context_count); + size_t index = 0u; if (!visual_annotation.ui_component().empty()) { @@ -380,24 +482,26 @@ block_to_lines_pair.second) { const chrome_screen_ai::LineBox& line_box = visual_annotation.lines(line_sequence_number_to_index_pair.second); - SerializeLineBox(line_box, index++, page_node, nodes); - index += line_box.words().size(); + // Every line with a textual accessibility role should turn into one or + // more inline text boxes, each one representing a formatting context. + // If the line is not of a textual role, only one node is initialized + // having a more specific role such as `ax::mojom::Role::kImage`. + index += SerializeLineBox(line_box, index, page_node, nodes); } } } // Filter out invalid / unrecognized / unused nodes from the update. update.nodes.resize(nodes.size()); - auto end_node_iter = - std::copy_if(std::begin(nodes), std::end(nodes), std::begin(update.nodes), - [](const ui::AXNodeData& node_data) { - return node_data.role != ax::mojom::Role::kUnknown && - node_data.id != ui::kInvalidAXNodeID; - }); + const auto end_node_iter = ranges::copy_if( + nodes, ranges::begin(update.nodes), [](const ui::AXNodeData& node_data) { + return node_data.role != ax::mojom::Role::kUnknown && + node_data.id != ui::kInvalidAXNodeID; + }); update.nodes.resize(std::distance(std::begin(update.nodes), end_node_iter)); // TODO(https://crbug.com/1278249): Add UMA metrics to record the number of - // annotations, item types, confidence levels, etc. + // annotations, item types, etc. return update; }
diff --git a/components/services/screen_ai/proto/proto_convertor_unittest.cc b/components/services/screen_ai/proto/proto_convertor_unittest.cc index d9eba124..a7eb8fff 100644 --- a/components/services/screen_ai/proto/proto_convertor_unittest.cc +++ b/components/services/screen_ai/proto/proto_convertor_unittest.cc
@@ -62,7 +62,6 @@ chrome_screen_ai::UIComponent::PredictedType* type_0 = component_0->mutable_predicted_type(); type_0->set_enum_type(chrome_screen_ai::UIComponent::BUTTON); - type_0->set_confidence(0.8f); chrome_screen_ai::Rect* box_0 = component_0->mutable_bounding_box(); box_0->set_x(0); box_0->set_y(1); @@ -73,26 +72,12 @@ chrome_screen_ai::UIComponent* component_1 = annotation.add_ui_component(); chrome_screen_ai::UIComponent::PredictedType* type_1 = component_1->mutable_predicted_type(); - type_1->set_string_type("Presentational"); - // If the confidence is low, this component together with all its fields - // should be ignored. - type_1->set_confidence(0.05f); + type_1->set_string_type("Signature"); chrome_screen_ai::Rect* box_1 = component_1->mutable_bounding_box(); - box_1->set_x(0); - box_1->set_y(0); - box_1->set_width(5); - box_1->set_height(5); - - chrome_screen_ai::UIComponent* component_2 = annotation.add_ui_component(); - chrome_screen_ai::UIComponent::PredictedType* type_2 = - component_2->mutable_predicted_type(); - type_2->set_string_type("Signature"); - type_2->set_confidence(0.6f); - chrome_screen_ai::Rect* box_2 = component_2->mutable_bounding_box(); // `x`, `y`, and `angle` should be defaulted to 0 since they are singular // proto3 fields, not proto2. - box_2->set_width(5); - box_2->set_height(5); + box_1->set_width(5); + box_1->set_height(5); } { @@ -116,7 +101,7 @@ { chrome_screen_ai::LineBox* line_0 = annotation.add_lines(); - line_0->set_direction(chrome_screen_ai::Direction::RIGHT_TO_LEFT); + line_0->set_direction(chrome_screen_ai::DIRECTION_RIGHT_TO_LEFT); chrome_screen_ai::WordBox* word_0_0 = line_0->add_words(); chrome_screen_ai::Rect* box_0_0 = word_0_0->mutable_bounding_box(); @@ -125,12 +110,12 @@ box_0_0->set_width(250); box_0_0->set_height(20); word_0_0->set_utf8_string("Hello"); + word_0_0->set_language("en"); word_0_0->set_has_space_after(true); - word_0_0->set_confidence(0.9f); word_0_0->set_estimate_color_success(true); word_0_0->set_background_rgb_value(50000); word_0_0->set_foreground_rgb_value(25000); - word_0_0->set_direction(chrome_screen_ai::Direction::RIGHT_TO_LEFT); + word_0_0->set_direction(chrome_screen_ai::DIRECTION_RIGHT_TO_LEFT); chrome_screen_ai::WordBox* word_0_1 = line_0->add_words(); chrome_screen_ai::Rect* box_0_1 = word_0_1->mutable_bounding_box(); @@ -139,12 +124,12 @@ box_0_1->set_width(250); box_0_1->set_height(20); word_0_1->set_utf8_string("world"); + word_0_1->set_language("en"); // `word_0_1.has_space_after()` should be defaulted to false. - word_0_1->set_confidence(0.9f); word_0_1->set_estimate_color_success(true); word_0_1->set_background_rgb_value(50000); word_0_1->set_foreground_rgb_value(25000); - word_0_1->set_direction(chrome_screen_ai::Direction::RIGHT_TO_LEFT); + word_0_1->set_direction(chrome_screen_ai::DIRECTION_RIGHT_TO_LEFT); chrome_screen_ai::Rect* box_0 = line_0->mutable_bounding_box(); box_0->set_x(100); @@ -152,28 +137,9 @@ box_0->set_width(500); box_0->set_height(20); line_0->set_utf8_string("Hello world"); - line_0->set_confidence(0.9f); line_0->set_language("en"); - line_0->set_block_id(2); + line_0->set_block_id(1); line_0->set_order_within_block(1); - - chrome_screen_ai::LineBox* line_1 = annotation.add_lines(); - line_1->set_confidence(0.0f); - // Language, and the line as a whole, should be ignored since the - // confidence is zero. - line_1->set_language("en"); - line_1->set_block_id(1); - line_1->set_order_within_block(0); - - chrome_screen_ai::LineBox* line_2 = annotation.add_lines(); - line_2->set_confidence(0.7f); - chrome_screen_ai::Rect* box_2 = line_2->mutable_bounding_box(); - // No bounding box should be created in the AXTree because the height is -5. - box_2->set_width(5); - box_2->set_height(-5); - line_2->set_block_id(2); - line_2->set_order_within_block(0); - line_2->set_direction(chrome_screen_ai::Direction::UNSPECIFIED); } { @@ -193,18 +159,13 @@ " id=6 genericContainer offset_container_id=4 (0, 0)-(5, 5) " "role_description=Signature\n" "id=7 region (0, 0)-(800, 900) is_page_breaking_object=true " - "child_ids=8,9\n" - " id=8 staticText (0, 0)-(5, 0) name_from=contents text_direction=ltr " - "name=\n" - " id=9 staticText offset_container_id=7 (100, 100)-(500, 20) " + "child_ids=8\n" + " id=8 staticText offset_container_id=7 (100, 100)-(500, 20) " "name_from=contents text_direction=rtl name=Hello world language=en " - "child_ids=10,11\n" - " id=10 inlineTextBox offset_container_id=9 (100, 100)-(250, 20) " - "name_from=contents background_color=&C350 color=&61A8 " - "text_direction=rtl name=Hello \n" - " id=11 inlineTextBox offset_container_id=9 (350, 100)-(250, 20) " - "name_from=contents background_color=&C350 color=&61A8 " - "text_direction=rtl name=world\n"); + "child_ids=9\n" + " id=9 inlineTextBox (100, 100)-(500, 20) name_from=contents " + "background_color=&C350 color=&61A8 text_direction=rtl language=en " + "name=Hello world word_starts=0,6 word_ends=6,11\n"); EXPECT_EQ(expected_update, update.ToString()); } }
diff --git a/components/test/data/autofill/heuristics/output/022_checkout_crutchfield.com.out b/components/test/data/autofill/heuristics/output/022_checkout_crutchfield.com.out index 2fba472..acd2b0e 100644 --- a/components/test/data/autofill/heuristics/output/022_checkout_crutchfield.com.out +++ b/components/test/data/autofill/heuristics/output/022_checkout_crutchfield.com.out
@@ -10,7 +10,7 @@ EMAIL_ADDRESS | ctl00$ctl00$MainContentPlaceHolder$MainContentPlaceHolder$email2 | Email | | ctl00$ctl00$MainContentPlaceHolder$MainContentPlaceHolder$firstname_1-default UNKNOWN_TYPE | ctl00$ctl00$MainContentPlaceHolder$MainContentPlaceHolder$chbox2 | Send me exclusive offers, deals and expert reviews. | on | ctl00$ctl00$MainContentPlaceHolder$MainContentPlaceHolder$firstname_1-default UNKNOWN_TYPE | ctl00$ctl00$MainContentPlaceHolder$MainContentPlaceHolder$same | Same as billing address. | same | ctl00$ctl00$MainContentPlaceHolder$MainContentPlaceHolder$firstname_1-default -UNKNOWN_TYPE | ctl00$ctl00$MainContentPlaceHolder$MainContentPlaceHolder$giftOrder | Prices will not appear on invoice. This order is a gift. | gift | ctl00$ctl00$MainContentPlaceHolder$MainContentPlaceHolder$firstname_1-default +UNKNOWN_TYPE | ctl00$ctl00$MainContentPlaceHolder$MainContentPlaceHolder$giftOrder | This order is a gift. Prices will not appear on invoice. | gift | ctl00$ctl00$MainContentPlaceHolder$MainContentPlaceHolder$firstname_1-default NAME_FIRST | ctl00$ctl00$MainContentPlaceHolder$MainContentPlaceHolder$shippingFirstname | First Name | | ctl00$ctl00$MainContentPlaceHolder$MainContentPlaceHolder$shippingFirstname_2-default NAME_MIDDLE_INITIAL | ctl00$ctl00$MainContentPlaceHolder$MainContentPlaceHolder$shippingMi | M.I. | | ctl00$ctl00$MainContentPlaceHolder$MainContentPlaceHolder$shippingFirstname_2-default NAME_LAST | ctl00$ctl00$MainContentPlaceHolder$MainContentPlaceHolder$shippingLastname | Last Name | | ctl00$ctl00$MainContentPlaceHolder$MainContentPlaceHolder$shippingFirstname_2-default
diff --git a/components/test/data/autofill/heuristics/output/034_checkout_overstock.com.out b/components/test/data/autofill/heuristics/output/034_checkout_overstock.com.out index 9953e27..2c4557a 100644 --- a/components/test/data/autofill/heuristics/output/034_checkout_overstock.com.out +++ b/components/test/data/autofill/heuristics/output/034_checkout_overstock.com.out
@@ -25,7 +25,7 @@ UNKNOWN_TYPE | CC | PayPal | PayPal | ShippingFirstName_2-default UNKNOWN_TYPE | CC | bml | bml | ShippingFirstName_2-default UNKNOWN_TYPE | UsePromoCode | Use Promo Code | on | ShippingFirstName_2-default -MERCHANT_PROMO_CODE | PromoCode | See Terms | | ShippingFirstName_2-default +MERCHANT_PROMO_CODE | PromoCode | Use Promo Code | | ShippingFirstName_2-default UNKNOWN_TYPE | UseGiftCards | Use Gift Card | on | ShippingFirstName_2-default UNKNOWN_TYPE | GiftCardNumber0 | Gift Card 1: | | ShippingFirstName_2-default UNKNOWN_TYPE | PINNumber0 | PIN: | | ShippingFirstName_2-default
diff --git a/components/test/data/autofill/heuristics/output/037_checkout_qvc.com.out b/components/test/data/autofill/heuristics/output/037_checkout_qvc.com.out index 519e7d0..d1cd8df 100644 --- a/components/test/data/autofill/heuristics/output/037_checkout_qvc.com.out +++ b/components/test/data/autofill/heuristics/output/037_checkout_qvc.com.out
@@ -26,4 +26,4 @@ ADDRESS_HOME_ZIP | ShiptoZipCode | * Postal Code: | | ShiptoAddress1_2-default ADDRESS_HOME_COUNTRY | ShiptoCountry | * Country: | US | ShiptoAddress1_2-default UNKNOWN_TYPE | ShiptoRadiobutton | This order only | ThisOrderOnly | ShiptoAddress1_2-default -UNKNOWN_TYPE | ShiptoRadiobutton | (Permanent Ship-To)**All future orders | PermanentShipto | ShiptoAddress1_2-default +UNKNOWN_TYPE | ShiptoRadiobutton | All future orders (Permanent Ship-To)** | PermanentShipto | ShiptoAddress1_2-default
diff --git a/components/test/data/autofill/heuristics/output/094_checkout_staples.com.out b/components/test/data/autofill/heuristics/output/094_checkout_staples.com.out index a1f83c7..b6c1d2c6 100644 --- a/components/test/data/autofill/heuristics/output/094_checkout_staples.com.out +++ b/components/test/data/autofill/heuristics/output/094_checkout_staples.com.out
@@ -1,5 +1,5 @@ UNKNOWN_TYPE | emailAddress | * Indicates a required field | | emailAddress_1-default -UNKNOWN_TYPE | emailPreference | , I would like to receive emails about special money-saving offers from Staples. Yes | emailYes | emailAddress_1-default +UNKNOWN_TYPE | emailPreference | Yes, I would like to receive emails about special money-saving offers from Staples. | emailYes | emailAddress_1-default NAME_FIRST | sFirstName | First Name * | | sFirstName_1-default NAME_LAST | sLastName | Last Name * | | sFirstName_1-default COMPANY_NAME | sCompany | Company Name (optional) | | sFirstName_1-default
diff --git a/components/test/data/autofill/heuristics/output/109_checkout_m_nordstroms.com.out b/components/test/data/autofill/heuristics/output/109_checkout_m_nordstroms.com.out index 96b7dd4..cea2e63 100644 --- a/components/test/data/autofill/heuristics/output/109_checkout_m_nordstroms.com.out +++ b/components/test/data/autofill/heuristics/output/109_checkout_m_nordstroms.com.out
@@ -38,4 +38,4 @@ ADDRESS_HOME_COUNTRY | | Country | 0 | _1-default EMAIL_ADDRESS | | E-mail Information Information | | _1-default PHONE_HOME_WHOLE_NUMBER | | Phone Information Information | | _1-default -UNKNOWN_TYPE | | Send me e-mail updates about the latest trends, products and promotions online and in store. Yes! | on | _1-default +UNKNOWN_TYPE | | Yes! Send me e-mail updates about the latest trends, products and promotions online and in store. | on | _1-default
diff --git a/components/test/data/autofill/heuristics/output/149_checkout_qvc.com_non_hidden.out b/components/test/data/autofill/heuristics/output/149_checkout_qvc.com_non_hidden.out index ac5a6cd5..d1cd8df 100644 --- a/components/test/data/autofill/heuristics/output/149_checkout_qvc.com_non_hidden.out +++ b/components/test/data/autofill/heuristics/output/149_checkout_qvc.com_non_hidden.out
@@ -26,4 +26,4 @@ ADDRESS_HOME_ZIP | ShiptoZipCode | * Postal Code: | | ShiptoAddress1_2-default ADDRESS_HOME_COUNTRY | ShiptoCountry | * Country: | US | ShiptoAddress1_2-default UNKNOWN_TYPE | ShiptoRadiobutton | This order only | ThisOrderOnly | ShiptoAddress1_2-default -UNKNOWN_TYPE | ShiptoRadiobutton | (Permanent Ship-To)** All future orders | PermanentShipto | ShiptoAddress1_2-default +UNKNOWN_TYPE | ShiptoRadiobutton | All future orders (Permanent Ship-To)** | PermanentShipto | ShiptoAddress1_2-default
diff --git a/components/viz/service/display_embedder/compositor_gpu_thread.cc b/components/viz/service/display_embedder/compositor_gpu_thread.cc index e3a72cb..06e2cb2 100644 --- a/components/viz/service/display_embedder/compositor_gpu_thread.cc +++ b/components/viz/service/display_embedder/compositor_gpu_thread.cc
@@ -20,7 +20,6 @@ #include "gpu/ipc/common/gpu_client_ids.h" #include "gpu/ipc/service/gpu_channel_manager.h" #include "gpu/vulkan/buildflags.h" -#include "ui/gl/gl_bindings.h" #include "ui/gl/gl_context.h" #include "ui/gl/gl_surface_egl.h" #include "ui/gl/init/gl_factory.h" @@ -49,7 +48,7 @@ // that instead of enabling/disabling DrDc based on the extension. if (gl::GetGLImplementation() == gl::kGLImplementationEGLANGLE) DCHECK(gl::GLSurfaceEGL::GetGLDisplayEGL() - ->ext->b_EGL_ANGLE_context_virtualization); + ->IsANGLEContextVirtualizationSupported()); #endif scoped_refptr<VulkanContextProvider> vulkan_context_provider;
diff --git a/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc b/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc index 411603d4..443b418 100644 --- a/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc +++ b/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc
@@ -854,6 +854,7 @@ metadata.page_scale_factor = frame_metadata.page_scale_factor; metadata.root_scroll_offset_x = frame_metadata.root_scroll_offset.x(); metadata.root_scroll_offset_y = frame_metadata.root_scroll_offset.y(); + metadata.source_size = source_size; if (frame_metadata.top_controls_visible_height.has_value()) { last_top_controls_visible_height_ = *frame_metadata.top_controls_visible_height; @@ -976,6 +977,7 @@ metadata.region_capture_rect = scale_factor ? ScaleToEnclosingRect(capture_region, 1.0f / scale_factor) : capture_region; + metadata.source_size = capture_region.size(); } // Note that this is done unconditionally, as a new crop version may indicate // that the stream has been successfully uncropped.
diff --git a/content/app/content_main_runner_impl_browsertest.cc b/content/app/content_main_runner_impl_browsertest.cc new file mode 100644 index 0000000..1356879 --- /dev/null +++ b/content/app/content_main_runner_impl_browsertest.cc
@@ -0,0 +1,249 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <memory> +#include <ostream> +#include <string> +#include <tuple> +#include <utility> +#include <vector> + +#include "base/command_line.h" +#include "base/feature_list.h" +#include "base/task/thread_pool/thread_pool_instance.h" +#include "base/test/scoped_field_trial_list_resetter.h" +#include "build/buildflag.h" +#include "content/browser/startup_helper.h" +#include "content/public/app/content_main_delegate.h" +#include "content/public/browser/content_browser_client.h" +#include "content/public/common/content_switches.h" +#include "content/public/gpu/content_gpu_client.h" +#include "content/public/renderer/content_renderer_client.h" +#include "content/public/test/browser_test.h" +#include "content/public/test/content_browser_test.h" +#include "content/public/utility/content_utility_client.h" +#include "sandbox/policy/switches.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/abseil-cpp/absl/types/variant.h" + +namespace variations { +class VariationsIdsProvider; +}; + +namespace content { + +class ContentClient; + +namespace { + +using ::testing::_; +using ::testing::AtMost; +using ::testing::ByMove; +using ::testing::DoAll; +using ::testing::Invoke; +using ::testing::Return; +using ::testing::SetArgPointee; +using InvokedIn = ContentMainDelegate::InvokedIn; + +#if BUILDFLAG(IS_ANDROID) +// TODO(joenotcharles): Find out why this test crashes on Android, which uses +// custom startup code in BrowserTestBase::SetUp instead of calling ContentMain. +#error This test is not supported on Android. +#endif + +// Mocks only the cross-platform methods of ContentMainDelegate. +class MockContentMainDelegate : public ContentMainDelegate { + public: + MOCK_METHOD(bool, BasicStartupComplete, (int*), (override)); + MOCK_METHOD(void, PreSandboxStartup, (), (override)); + MOCK_METHOD(void, SandboxInitialized, (const std::string&), (override)); + MOCK_METHOD((absl::variant<int, MainFunctionParams>), + RunProcess, + (const std::string&, MainFunctionParams), + (override)); + MOCK_METHOD(void, ProcessExiting, (const std::string&), (override)); + MOCK_METHOD(int, TerminateForFatalInitializationError, (), (override)); + MOCK_METHOD(bool, ShouldLockSchemeRegistry, (), (override)); + MOCK_METHOD(void, PreBrowserMain, (), (override)); + MOCK_METHOD(bool, ShouldCreateFeatureList, (InvokedIn), (override)); + MOCK_METHOD(variations::VariationsIdsProvider*, + CreateVariationsIdsProvider, + (), + (override)); + MOCK_METHOD(void, PostEarlyInitialization, (InvokedIn), (override)); + MOCK_METHOD(ContentClient*, CreateContentClient, (), (override)); + MOCK_METHOD(ContentBrowserClient*, + CreateContentBrowserClient, + (), + (override)); + MOCK_METHOD(ContentGpuClient*, CreateContentGpuClient, (), (override)); + MOCK_METHOD(ContentRendererClient*, + CreateContentRendererClient, + (), + (override)); + MOCK_METHOD(ContentUtilityClient*, + CreateContentUtilityClient, + (), + (override)); +}; + +// Parameters to control the expectations for MockContentMainDelegate. Each test +// case uses a different set of parameters, since the expectations need to be +// installed before SetUp() is called. +struct MockExpectations { + bool exit_after_basic_startup = false; + bool content_main_should_create_feature_list = true; +}; + +std::ostream& operator<<(std::ostream& os, const MockExpectations& m) { + return os << "exit_after_basic_startup:" << m.exit_after_basic_startup + << ",content_main_should_create_feature_list:" + << m.content_main_should_create_feature_list; +} + +// Tests that methods of ContentMainDelegate are called in the expected order. +// The string parameter is the process name (empty for the browser process). +class ContentMainRunnerImplBrowserTest + : public ContentBrowserTest, + public ::testing::WithParamInterface< + std::tuple<std::string, MockExpectations>> { + protected: + ContentMainRunnerImplBrowserTest() { + std::string process_type; + std::tie(process_type, mock_expectations_) = GetParam(); + + // Start without a feature list so the startup sequence can create one. + // `scoped_field_trial_list_resetter_` will do the same for the field trial + // list. + original_feature_list_ = base::FeatureList::ClearInstanceForTesting(); + + const bool is_browser_process = process_type.empty(); + if (!is_browser_process) { + // Fool ContentMain() into thinking this is a different process type. + base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); + command_line->AppendSwitchASCII(switches::kProcessType, process_type); + command_line->AppendSwitch(sandbox::policy::switches::kNoSandbox); + } + const InvokedIn invoked_in = is_browser_process + ? InvokedIn::kBrowserProcessUnderTest + : InvokedIn::kChildProcess; + + // These methods may or may not be called, depending on configuration. + EXPECT_CALL(mock_delegate_, ShouldLockSchemeRegistry()).Times(AtMost(1)); + EXPECT_CALL(mock_delegate_, CreateVariationsIdsProvider()).Times(AtMost(1)); + // CreateContentClient() is only called if GetContentClient() returns null. + EXPECT_CALL(mock_delegate_, CreateContentClient()).Times(AtMost(1)); + + // Expect the following entry points to be called, in order. + // + // BrowserTestBase::SetUp() calls ContentMain(), which instantiates a + // ContentMainRunnerImpl, which calls the entry points in + // ContentMainDelegate. So test expectations must be installed before + // calling the inherited SetUp(). + ::testing::InSequence s; + EXPECT_CALL(mock_delegate_, BasicStartupComplete(_)) + .WillOnce(DoAll( + // Set the exit code. + SetArgPointee<0>(0), + // Set the return value. + Return(mock_expectations_.exit_after_basic_startup))); + if (mock_expectations_.exit_after_basic_startup) { + // Expect no more calls. + return; + } + + if (is_browser_process) { + EXPECT_CALL(mock_delegate_, CreateContentBrowserClient()) + .WillOnce(Return(&content_browser_client_)); + } else if (process_type == switches::kGpuProcess) { + EXPECT_CALL(mock_delegate_, CreateContentGpuClient()) + .WillOnce(Return(&content_gpu_client_)); + } else if (process_type == switches::kRendererProcess) { + EXPECT_CALL(mock_delegate_, CreateContentRendererClient()) + .WillOnce(Return(&content_renderer_client_)); + } else { + EXPECT_CALL(mock_delegate_, CreateContentUtilityClient()) + .WillOnce(Return(&content_utility_client_)); + } + EXPECT_CALL(mock_delegate_, PreSandboxStartup()); + EXPECT_CALL(mock_delegate_, SandboxInitialized(process_type)); + EXPECT_CALL(mock_delegate_, ShouldCreateFeatureList(invoked_in)) + .WillOnce( + Return(mock_expectations_.content_main_should_create_feature_list)); + // PreBrowserMain is only called in the browser process. + EXPECT_CALL(mock_delegate_, PreBrowserMain()) + .Times(is_browser_process ? 1 : 0); + EXPECT_CALL(mock_delegate_, PostEarlyInitialization(invoked_in)) + .WillOnce(Invoke( + this, &ContentMainRunnerImplBrowserTest::PostEarlyInitialization)); + EXPECT_CALL(mock_delegate_, RunProcess(process_type, _)) + .WillOnce(Return(ByMove(0))); + EXPECT_CALL(mock_delegate_, ProcessExiting(process_type)); + } + + ~ContentMainRunnerImplBrowserTest() override { + // Restore the original feature list for other tests. Any temporary + // FeatureList created during the test (by ContentMainRunnerImpl or + // PostEarlyInitialization, depending on the value of the + // `content_main_should_create_feature_list` parameter) must be removed + // first. + base::FeatureList::ClearInstanceForTesting(); + base::FeatureList::RestoreInstanceForTesting( + std::move(original_feature_list_)); + } + + ContentMainDelegate* GetCustomContentMainDelegate() override { + return &mock_delegate_; + } + + void PostEarlyInitialization() { + ASSERT_TRUE(base::ThreadPoolInstance::Get()); + if (mock_expectations_.content_main_should_create_feature_list) { + ASSERT_TRUE(base::FeatureList::GetInstance()); + } else { + ASSERT_FALSE(base::FeatureList::GetInstance()); + + // ContentMainRunnerImpl will try to use the feature list after + // PostEarlyInitialization, so we need to create one. + field_trials_ = SetUpFieldTrialsAndFeatureList(); + } + } + + ::testing::StrictMock<MockContentMainDelegate> mock_delegate_; + MockExpectations mock_expectations_; + + // Stubs to return from CreateContent*Client mocks. These will be deleted at + // the end of the test to satisfy the leak checker. + ContentBrowserClient content_browser_client_; + ContentGpuClient content_gpu_client_; + ContentRendererClient content_renderer_client_; + ContentUtilityClient content_utility_client_; + + // Ensure that the test can create its own `field_trials_`. + base::test::ScopedFieldTrialListResetter scoped_field_trial_list_resetter_; + std::unique_ptr<base::FeatureList> original_feature_list_; + std::unique_ptr<base::FieldTrialList> field_trials_; +}; + +INSTANTIATE_TEST_SUITE_P( + All, + ContentMainRunnerImplBrowserTest, + ::testing::Combine( + ::testing::Values("", + switches::kGpuProcess, + switches::kRendererProcess, + switches::kUtilityProcess), + ::testing::Values(MockExpectations{}, + MockExpectations{ + .content_main_should_create_feature_list = false}, + MockExpectations{.exit_after_basic_startup = true}))); + +IN_PROC_BROWSER_TEST_P(ContentMainRunnerImplBrowserTest, StartupSequence) { + // All of the work is done in the test suite constructor and SetUp(). +} + +} // namespace + +} // namespace content
diff --git a/content/browser/media/capture/web_contents_frame_tracker.cc b/content/browser/media/capture/web_contents_frame_tracker.cc index 10048ba..b2db5b20 100644 --- a/content/browser/media/capture/web_contents_frame_tracker.cc +++ b/content/browser/media/capture/web_contents_frame_tracker.cc
@@ -23,6 +23,7 @@ #include "content/public/browser/web_contents_media_capture_id.h" #include "content/public/browser/web_contents_observer.h" #include "media/base/media_switches.h" +#include "media/base/video_util.h" #include "media/capture/video_capture_types.h" #include "ui/base/layout.h" #include "ui/gfx/geometry/dip_util.h" @@ -149,6 +150,9 @@ void WebContentsFrameTracker::SetCapturedContentSize( const gfx::Size& content_size) { + // For efficiency, this function should only be called when the captured + // content size changes. The caller is responsible for enforcing that. + DVLOG(3) << __func__ << ": content_size=" << content_size.ToString(); if (base::FeatureList::IsEnabled(media::kWebContentsCaptureHiDpi)) { // Check if the capture scale needs to be modified. The content_size @@ -201,6 +205,9 @@ preferred_size = gfx::ScaleToFlooredSize( preferred_size, static_cast<float>(1 / scale_ratio)); } + DVLOG(3) << __func__ << ": x_ratio=" << x_ratio << " y_ratio=" << y_ratio + << " scale_ratio=" << scale_ratio + << " preferred_size=" << preferred_size.ToString(); } } return preferred_size; @@ -222,10 +229,18 @@ // capture size, which should never happen. constexpr float kMinFactor = 1.0f; - // Ideally is that the |content_size| is the same as |capture_size_|, so if - // we are achieving that with current settings we can exit early. - if (content_size.width() == capture_size_.width() && - content_size.height() == capture_size_.height()) { + // The content rectangle is letterboxed within the capture size rectangle. + // Calculate the effective scaled size after this is applied, and use + // this size for ratio calculations. + gfx::Size letterbox_size = + media::ComputeLetterboxRegion(gfx::Rect(capture_size_), content_size) + .size(); + + // Ideally the |content_size| should be the same as |letterbox_size|, so if + // we are achieving that with current settings we can exit early. Also + // accept almost-equal sizes to avoid oscillations due to rounding errors. + if (std::abs(content_size.width() - letterbox_size.width()) < 4 && + std::abs(content_size.height() - letterbox_size.height()) < 4) { return capture_scale_override_; } @@ -236,15 +251,25 @@ content_size, 1.0f / context_->GetScaleOverrideForCapture()); // Next, determine what the ideal scale factors in each direction would have - // been for this frame. - const gfx::Vector2dF factors( - static_cast<float>(capture_size_.width()) / unscaled_content_size.width(), - static_cast<float>(capture_size_.height()) / - unscaled_content_size.height()); + // been for this frame. The factors should be nearly equal after letterboxing. + const gfx::Vector2dF factors(static_cast<float>(letterbox_size.width()) / + unscaled_content_size.width(), + static_cast<float>(letterbox_size.height()) / + unscaled_content_size.height()); // We prefer to err on the side of having to downscale in one direction rather // than upscale in the other direction, so we use the largest scale factor. const float largest_factor = std::max(factors.x(), factors.y()); + + DVLOG(3) << __func__ << ":" + << " capture_size_=" << capture_size_.ToString() + << " letterbox_size=" << letterbox_size.ToString() + << " content_size=" << content_size.ToString() + << " unscaled_content_size=" << unscaled_content_size.ToString() + << " context_->GetScaleOverrideForCapture()=" + << context_->GetScaleOverrideForCapture() + << " factors.x()=" << factors.x() << " factors.y()=" << factors.y() + << " largest_factor=" << largest_factor; return std::clamp(largest_factor, kMinFactor, kMaxFactor); }
diff --git a/content/browser/media/capture/web_contents_frame_tracker_unittest.cc b/content/browser/media/capture/web_contents_frame_tracker_unittest.cc index 1585fe8..df9f4e1 100644 --- a/content/browser/media/capture/web_contents_frame_tracker_unittest.cc +++ b/content/browser/media/capture/web_contents_frame_tracker_unittest.cc
@@ -394,10 +394,26 @@ tracker()->SetCapturedContentSize(gfx::Size(1920, 1080)); EXPECT_DOUBLE_EQ(context()->scale_override(), 2.0f); - // If a frame ends up being larger than the capture_size, we should - // end up using the maximum scale override of 2.0. - tracker()->SetCapturedContentSize(gfx::Size(2304, 1080)); - EXPECT_DOUBLE_EQ(context()->scale_override(), 2.0f); + // If a frame ends up being larger than the capture_size, the scale + // should get adjusted downwards so that the post-scaling size matches + // the capture size. This assumes a current scale override of 2.0f. + tracker()->SetCapturedContentSize(gfx::Size(2560, 1440)); + EXPECT_DOUBLE_EQ(context()->scale_override(), 1.5f); + + // The scaled size should now match the capture size with a scale + // override of 1.5. + tracker()->SetCapturedContentSize(gfx::Size(1920, 1080)); + EXPECT_DOUBLE_EQ(context()->scale_override(), 1.5f); + + // The scaling calculation is based on fitting a scaled copy of the + // source rectangle within the capture region, preserving aspect ratio. + // If the content size changes in a way that doesn't affect the scale + // factor (i.e. letterboxing or pillarboxing), the scale override remains + // unchanged. + tracker()->SetCapturedContentSize(gfx::Size(1080, 1080)); + EXPECT_DOUBLE_EQ(context()->scale_override(), 1.5f); + tracker()->SetCapturedContentSize(gfx::Size(1920, 540)); + EXPECT_DOUBLE_EQ(context()->scale_override(), 1.5f); // When we stop the tracker, the web contents issues a preferred size change // of the "old" size--so it shouldn't change.
diff --git a/content/browser/media/capture/web_contents_video_capture_device.cc b/content/browser/media/capture/web_contents_video_capture_device.cc index a95698a9..925b0026 100644 --- a/content/browser/media/capture/web_contents_video_capture_device.cc +++ b/content/browser/media/capture/web_contents_video_capture_device.cc
@@ -75,13 +75,18 @@ const gfx::Rect& content_rect, mojo::PendingRemote<viz::mojom::FrameSinkVideoConsumerFrameCallbacks> callbacks) { - const gfx::Size new_size = content_rect.size(); - if (new_size != content_size_) { - GetUIThreadTaskRunner({})->PostTask( - FROM_HERE, - base::BindOnce(&WebContentsFrameTracker::SetCapturedContentSize, - tracker_->AsWeakPtr(), content_rect.size())); - content_size_ = new_size; + if (info->metadata.source_size.has_value()) { + const gfx::Size new_size = *info->metadata.source_size; + // Only update the captured content size when the size changes. See also + // the comment in WebContentsFrameTracker::SetCapturedContentSize which + // expects that behavior. + if (new_size != content_size_) { + GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, + base::BindOnce(&WebContentsFrameTracker::SetCapturedContentSize, + tracker_->AsWeakPtr(), new_size)); + content_size_ = new_size; + } } FrameSinkVideoCaptureDevice::OnFrameCaptured( @@ -103,6 +108,12 @@ FROM_HERE, base::BindOnce(&WebContentsFrameTracker::DidStopCapturingWebContents, tracker_->AsWeakPtr())); + + // Currently, the video capture device is effectively a single-use object, so + // resetting capture_size_ isn't strictly necessary, but it helps ensure that + // SetCapturedContentSize works consistently in case the objects get reused in + // the future. + content_size_.SetSize(0, 0); } } // namespace content
diff --git a/content/public/test/browser_test_base.cc b/content/public/test/browser_test_base.cc index fdf71ef..b4a8a8b 100644 --- a/content/public/test/browser_test_base.cc +++ b/content/public/test/browser_test_base.cc
@@ -597,7 +597,10 @@ base::i18n::AllowMultipleInitializeCallsForTesting(); base::i18n::InitializeICU(); - ContentMainDelegate* delegate = GetContentMainDelegateForTesting(); + ContentMainDelegate* delegate = GetCustomContentMainDelegate(); + if (!delegate) + delegate = GetContentMainDelegateForTesting(); + // The delegate should have been set by JNI_OnLoad for the test target. DCHECK(delegate); @@ -725,6 +728,8 @@ auto params = CopyContentMainParams(); params.ui_task = std::move(ui_task); params.created_main_parts_closure = std::move(created_main_parts_closure); + if (auto* custom_delegate = GetCustomContentMainDelegate()) + params.delegate = custom_delegate; EXPECT_EQ(expected_exit_code_, ContentMain(std::move(params))); #endif // BUILDFLAG(IS_ANDROID) @@ -1125,4 +1130,8 @@ CreatedBrowserMainParts(browser_main_parts); } +ContentMainDelegate* BrowserTestBase::GetCustomContentMainDelegate() { + return nullptr; +} + } // namespace content
diff --git a/content/public/test/browser_test_base.h b/content/public/test/browser_test_base.h index c91fdc83..a537032 100644 --- a/content/public/test/browser_test_base.h +++ b/content/public/test/browser_test_base.h
@@ -42,6 +42,7 @@ namespace content { class BrowserMainParts; +class ContentMainDelegate; class WebContents; class BrowserTestBase : public ::testing::Test { @@ -122,6 +123,12 @@ // PreEarlyInitialization() has been called. virtual void CreatedBrowserMainParts(BrowserMainParts* browser_main_parts) {} + // Override this to provide a custom ContentMainDelegate for the test. The + // returned object must live at least until + // TearDownInProcessBrowserTextFixture is called. If nullptr is returned the + // test will use the default delegate. + virtual ContentMainDelegate* GetCustomContentMainDelegate(); + // GTest assertions that the connection to `network_service_test_` did not get // dropped unexpectedly. void AssertThatNetworkServiceDidNotCrash();
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn index d824c2a..78e1f80 100644 --- a/content/test/BUILD.gn +++ b/content/test/BUILD.gn
@@ -1826,6 +1826,7 @@ } else { # Non-Android. sources += [ + "../app/content_main_runner_impl_browsertest.cc", "../browser/direct_sockets/direct_sockets_open_browsertest.cc", "../browser/direct_sockets/direct_sockets_tcp_browsertest.cc", "../browser/direct_sockets/direct_sockets_udp_browsertest.cc", @@ -1846,6 +1847,7 @@ ] deps += [ "//content/public/browser:proto", + "//sandbox/policy", "//ui/base/clipboard:clipboard_test_support", ] data += [ "//content/test/data/clipboard/" ]
diff --git a/extensions/browser/api/audio/audio_api.cc b/extensions/browser/api/audio/audio_api.cc index 7c11629..f0e715cb 100644 --- a/extensions/browser/api/audio/audio_api.cc +++ b/extensions/browser/api/audio/audio_api.cc
@@ -15,9 +15,6 @@ #include "extensions/browser/api/audio/pref_names.h" #include "extensions/browser/event_router.h" #include "extensions/common/api/audio.h" -#include "extensions/common/extension.h" -#include "extensions/common/features/behavior_feature.h" -#include "extensions/common/features/feature_provider.h" namespace { const char* const kGetDevicesErrorMsg = @@ -39,34 +36,6 @@ return std::make_unique<AudioDeviceIdCalculator>(context); } -// Checks if an extension is allowlisted to use deprecated version of audio API. -// TODO(tbarzic): Retire this allowlist and remove the deprecated API methods, -// properties and events. This is currently targeted for M-60 -// (http://crbug.com/697279). -bool CanUseDeprecatedAudioApi(const Extension* extension) { - if (!extension) - return false; - - const Feature* allow_deprecated_audio_api_feature = - FeatureProvider::GetBehaviorFeatures()->GetFeature( - behavior_feature::kAllowDeprecatedAudioApi); - if (!allow_deprecated_audio_api_feature) - return false; - - return allow_deprecated_audio_api_feature->IsAvailableToExtension(extension) - .is_available(); -} - -bool CanReceiveDeprecatedAudioEvent( - content::BrowserContext* browser_context, - Feature::Context target_context, - const Extension* extension, - const base::DictionaryValue* filter, - std::unique_ptr<base::Value::List>* event_args, - mojom::EventFilteringInfoPtr* event_filtering_info_out) { - return CanUseDeprecatedAudioApi(extension); -} - } // namespace static base::LazyInstance< @@ -95,19 +64,6 @@ return service_.get(); } -void AudioAPI::OnDeviceChanged() { - EventRouter* event_router = EventRouter::Get(browser_context_); - if (!event_router) - return; - - auto event = std::make_unique<Event>(events::AUDIO_ON_DEVICE_CHANGED, - audio::OnDeviceChanged::kEventName, - std::vector<base::Value>()); - event->will_dispatch_callback = - base::BindRepeating(&CanReceiveDeprecatedAudioEvent); - event_router->BroadcastEvent(std::move(event)); -} - void AudioAPI::OnLevelChanged(const std::string& id, int level) { EventRouter* event_router = EventRouter::Get(browser_context_); if (!event_router) @@ -155,28 +111,6 @@ /////////////////////////////////////////////////////////////////////////////// -ExtensionFunction::ResponseAction AudioGetInfoFunction::Run() { - if (!CanUseDeprecatedAudioApi(extension())) { - return RespondNow( - Error("audio.getInfo is deprecated, use audio.getDevices instead.")); - } - - AudioService* service = - AudioAPI::GetFactoryInstance()->Get(browser_context())->GetService(); - DCHECK(service); - OutputInfo output_info; - InputInfo input_info; - if (!service->GetInfo(&output_info, &input_info)) { - return RespondNow( - Error("Error occurred when querying audio device information.")); - } - - return RespondNow( - ArgumentList(audio::GetInfo::Results::Create(output_info, input_info))); -} - -/////////////////////////////////////////////////////////////////////////////// - ExtensionFunction::ResponseAction AudioGetDevicesFunction::Run() { std::unique_ptr<audio::GetDevices::Params> params( audio::GetDevices::Params::Create(args())); @@ -225,31 +159,19 @@ AudioAPI::GetFactoryInstance()->Get(browser_context())->GetService(); DCHECK(service); - if (params->ids.as_device_id_lists) { #if BUILDFLAG(IS_CHROMEOS_LACROS) - // TODO: deprecated string lists are not implemented in Lacros - if (service->SetActiveDeviceLists( - params->ids.as_device_id_lists->input.get(), - params->ids.as_device_id_lists->output.get(), - base::BindOnce(&AudioSetActiveDevicesFunction::OnResponse, this))) { - return RespondLater(); - } - return RespondNow(Error(kSetActiveDevicesErrorMsg)); -#else - if (!service->SetActiveDeviceLists( - params->ids.as_device_id_lists->input.get(), - params->ids.as_device_id_lists->output.get())) { - return RespondNow(Error(kSetActiveDevicesErrorMsg)); - } -#endif - } else if (params->ids.as_strings) { - if (!CanUseDeprecatedAudioApi(extension())) { - return RespondNow( - Error("String list |ids| is deprecated, use DeviceIdLists type.")); - } - service->SetActiveDevices(*params->ids.as_strings); + if (service->SetActiveDeviceLists( + params->ids.input.get(), params->ids.output.get(), + base::BindOnce(&AudioSetActiveDevicesFunction::OnResponse, this))) { + return RespondLater(); } - return RespondNow(NoArguments()); +#else + if (service->SetActiveDeviceLists(params->ids.input.get(), + params->ids.output.get())) { + return RespondNow(NoArguments()); + } +#endif + return RespondNow(Error(kSetActiveDevicesErrorMsg)); } void AudioSetActiveDevicesFunction::OnResponse(bool success) { @@ -270,55 +192,22 @@ AudioAPI::GetFactoryInstance()->Get(browser_context())->GetService(); DCHECK(service); - if (!CanUseDeprecatedAudioApi(extension())) { - if (params->properties.volume) - return RespondNow(Error("|volume| property is deprecated, use |level|.")); - - if (params->properties.gain) - return RespondNow(Error("|gain| property is deprecated, use |level|.")); - - if (params->properties.is_muted) { - return RespondNow( - Error("|isMuted| property is deprecated, use |audio.setMute|.")); - } - } - bool level_set = !!params->properties.level; int level_value = level_set ? *params->properties.level : -1; #if BUILDFLAG(IS_CHROMEOS_LACROS) - // deprecated volume_value and gain_value are not implemented in lacros - // see (http://crbug.com/697279) if (level_set && service->SetDeviceSoundLevel( params->id, level_value, base::BindOnce(&AudioSetPropertiesFunction::OnResponse, this))) { return RespondLater(); } - return RespondNow(Error(kLevelPropErrorMsg)); #else - - int volume_value = params->properties.volume.get() ? - *params->properties.volume : -1; - - int gain_value = params->properties.gain.get() ? - *params->properties.gain : -1; - - // |volume_value| and |gain_value| are deprecated in favor of |level_value|; - // they are kept around only to ensure backward-compatibility and should be - // ignored if |level_value| is set. - if (!service->SetDeviceSoundLevel(params->id, - level_set ? level_value : volume_value, - level_set ? level_value : gain_value)) - return RespondNow(Error(kLevelPropErrorMsg)); - - if (params->properties.is_muted.get() && - !service->SetMuteForDevice(params->id, *params->properties.is_muted)) { - return RespondNow(Error("Could not set mute property.")); + if (level_set && service->SetDeviceSoundLevel(params->id, level_value)) { + return RespondNow(NoArguments()); } - - return RespondNow(NoArguments()); #endif + return RespondNow(Error(kLevelPropErrorMsg)); } void AudioSetPropertiesFunction::OnResponse(bool success) {
diff --git a/extensions/browser/api/audio/audio_api.h b/extensions/browser/api/audio/audio_api.h index 61f8e71..11b3b95 100644 --- a/extensions/browser/api/audio/audio_api.h +++ b/extensions/browser/api/audio/audio_api.h
@@ -39,7 +39,6 @@ static const bool kServiceRedirectedInIncognito = true; // AudioService::Observer implementation. - void OnDeviceChanged() override; void OnLevelChanged(const std::string& id, int level) override; void OnMuteChanged(bool is_input, bool is_muted) override; void OnDevicesChanged(const DeviceInfoList& devices) override; @@ -60,15 +59,6 @@ audio_service_observation_{this}; }; -class AudioGetInfoFunction : public ExtensionFunction { - public: - DECLARE_EXTENSION_FUNCTION("audio.getInfo", AUDIO_GETINFO) - - protected: - ~AudioGetInfoFunction() override {} - ResponseAction Run() override; -}; - class AudioGetDevicesFunction : public ExtensionFunction { public: DECLARE_EXTENSION_FUNCTION("audio.getDevices", AUDIO_GETDEVICES)
diff --git a/extensions/browser/api/audio/audio_apitest_chromeos.cc b/extensions/browser/api/audio/audio_apitest_chromeos.cc index c2cc292..f38ae9b 100644 --- a/extensions/browser/api/audio/audio_apitest_chromeos.cc +++ b/extensions/browser/api/audio/audio_apitest_chromeos.cc
@@ -278,28 +278,4 @@ EXPECT_TRUE(result_catcher.GetNextResult()) << result_catcher.message(); } -class AllowlistedAudioApiTest : public AudioApiTest { - public: - AllowlistedAudioApiTest() = default; - ~AllowlistedAudioApiTest() override = default; - - void SetUpCommandLine(base::CommandLine* command_line) override { - command_line->AppendSwitchASCII( - extensions::switches::kAllowlistedExtensionID, - "jlgnoeceollaejlkenecblnjmdcfhfgc"); - } -}; - -IN_PROC_BROWSER_TEST_F(AllowlistedAudioApiTest, DeprecatedApi) { - // Set up the audio nodes for testing. - AudioNodeList audio_nodes = { - CreateAudioNode(kJabraSpeaker1, 2), CreateAudioNode(kJabraSpeaker2, 2), - CreateAudioNode(kHDMIOutput, 2), CreateAudioNode(kJabraMic1, 2), - CreateAudioNode(kJabraMic2, 2), CreateAudioNode(kUSBCameraMic, 2)}; - - ChangeAudioNodes(audio_nodes); - - EXPECT_TRUE(RunAppTest("api_test/audio/deprecated_api")) << message_; -} - } // namespace extensions
diff --git a/extensions/browser/api/audio/audio_service.cc b/extensions/browser/api/audio/audio_service.cc index c2dffa4..e7d6d5d 100644 --- a/extensions/browser/api/audio/audio_service.cc +++ b/extensions/browser/api/audio/audio_service.cc
@@ -16,25 +16,21 @@ void RemoveObserver(Observer* observer) override; // Start to query audio device information. - bool GetInfo(OutputInfo* output_info_out, InputInfo* input_info_out) override; bool GetDevices(const api::audio::DeviceFilter* filter, DeviceInfoList* devices_out) override; bool GetDevices( const api::audio::DeviceFilter* filter, base::OnceCallback<void(bool, DeviceInfoList)> callback) override; - void SetActiveDevices(const DeviceIdList& device_list) override; bool SetActiveDeviceLists(const DeviceIdList* input_devices, const DeviceIdList* output_devives) override; bool SetActiveDeviceLists(const DeviceIdList* input_devices, const DeviceIdList* output_devives, base::OnceCallback<void(bool)> callback) override; bool SetDeviceSoundLevel(const std::string& device_id, - int volume, - int gain) override; + int level_value) override; bool SetDeviceSoundLevel(const std::string& device_id, int level_value, base::OnceCallback<void(bool)> callback) override; - bool SetMuteForDevice(const std::string& device_id, bool value) override; bool SetMute(bool is_input, bool value) override; bool SetMute(bool is_input, bool value, @@ -57,12 +53,6 @@ return std::make_unique<AudioServiceImpl>(); } -bool AudioServiceImpl::GetInfo(OutputInfo* output_info_out, - InputInfo* input_info_out) { - // TODO: implement this for platforms other than Chrome OS. - return false; -} - bool AudioServiceImpl::GetDevices(const api::audio::DeviceFilter* filter, DeviceInfoList* devices_out) { return false; @@ -87,12 +77,8 @@ return false; } -void AudioServiceImpl::SetActiveDevices(const DeviceIdList& device_list) { -} - bool AudioServiceImpl::SetDeviceSoundLevel(const std::string& device_id, - int volume, - int gain) { + int level_value) { return false; } @@ -103,11 +89,6 @@ return false; } -bool AudioServiceImpl::SetMuteForDevice(const std::string& device_id, - bool value) { - return false; -} - bool AudioServiceImpl::SetMute(bool is_input, bool value) { return false; }
diff --git a/extensions/browser/api/audio/audio_service.h b/extensions/browser/api/audio/audio_service.h index ddb7cd3b..84e7d2e 100644 --- a/extensions/browser/api/audio/audio_service.h +++ b/extensions/browser/api/audio/audio_service.h
@@ -14,8 +14,6 @@ namespace extensions { -using OutputInfo = std::vector<api::audio::OutputDeviceInfo>; -using InputInfo = std::vector<api::audio::InputDeviceInfo>; using DeviceIdList = std::vector<std::string>; using DeviceInfoList = std::vector<api::audio::AudioDeviceInfo>; @@ -25,9 +23,6 @@ public: class Observer { public: - // Called when anything changes to the audio device configuration. - virtual void OnDeviceChanged() = 0; - // Called when the sound level of an active audio device changes. virtual void OnLevelChanged(const std::string& id, int level) = 0; @@ -56,13 +51,6 @@ virtual void AddObserver(Observer* observer) = 0; virtual void RemoveObserver(Observer* observer) = 0; - // Start to query audio device information. Should be called on UI thread. - // Populates |output_info_out| and |input_info_out| with the results. - // Returns true on success. - // DEPRECATED: Use |GetDevices| instead. - virtual bool GetInfo(OutputInfo* output_info_out, - InputInfo* input_info_out) = 0; - // Retrieves list of audio devices that satisfy |filter|. Populates // |devices_out| with retrieved devices. // If |filter->is_active| is set, |devices_out| will contain only devices @@ -100,29 +88,15 @@ const DeviceIdList* output_devives, base::OnceCallback<void(bool)> callback) = 0; - // Sets the active devices to the devices specified by |device_list|. - // It can pass in the "complete" active device list of either input - // devices, or output devices, or both. If only input devices are passed in, - // it will only change the input devices' active status, output devices will - // NOT be changed; similarly for the case if only output devices are passed. - // If the devices specified in |new_active_ids| are already active, they will - // remain active. Otherwise, the old active devices will be de-activated - // before we activate the new devices with the same type(input/output). - virtual void SetActiveDevices(const DeviceIdList& device_list) = 0; - // Set the sound level properties (volume or gain) of a device. virtual bool SetDeviceSoundLevel(const std::string& device_id, - int volume, - int gain) = 0; + int level_value) = 0; // Same as above, but also passes if operation succeeded into a |callback|. virtual bool SetDeviceSoundLevel(const std::string& device_id, int level_value, base::OnceCallback<void(bool)> callback) = 0; - // Sets the mute property of a device. - virtual bool SetMuteForDevice(const std::string& device_id, bool value) = 0; - // Sets mute property for audio input (if |is_input| is true) or output (if // |is_input| is false). virtual bool SetMute(bool is_input, bool value) = 0;
diff --git a/extensions/browser/api/audio/audio_service_chromeos.cc b/extensions/browser/api/audio/audio_service_chromeos.cc index 0d727c17..adf380b 100644 --- a/extensions/browser/api/audio/audio_service_chromeos.cc +++ b/extensions/browser/api/audio/audio_service_chromeos.cc
@@ -20,8 +20,6 @@ namespace extensions { using api::audio::AudioDeviceInfo; -using api::audio::InputDeviceInfo; -using api::audio::OutputDeviceInfo; using ::ash::AudioDevice; using ::ash::AudioDeviceType; using ::ash::CrasAudioHandler; @@ -87,25 +85,21 @@ void RemoveObserver(AudioService::Observer* observer) override; // Start to query audio device information. - bool GetInfo(OutputInfo* output_info_out, InputInfo* input_info_out) override; bool GetDevices(const api::audio::DeviceFilter* filter, DeviceInfoList* devices_out) override; bool GetDevices( const api::audio::DeviceFilter* filter, base::OnceCallback<void(bool, DeviceInfoList)> callback) override; - void SetActiveDevices(const DeviceIdList& device_list) override; bool SetActiveDeviceLists(const DeviceIdList* input_devices, const DeviceIdList* output_devives) override; bool SetActiveDeviceLists(const DeviceIdList* input_devices, const DeviceIdList* output_devives, base::OnceCallback<void(bool)> callback) override; bool SetDeviceSoundLevel(const std::string& device_id, - int volume, - int gain) override; + int level_value) override; bool SetDeviceSoundLevel(const std::string& device_id, int level_value, base::OnceCallback<void(bool)> callback) override; - bool SetMuteForDevice(const std::string& device_id, bool value) override; bool SetMute(bool is_input, bool value) override; bool SetMute(bool is_input, bool value, @@ -125,7 +119,6 @@ void OnActiveInputNodeChanged() override; private: - void NotifyDeviceChanged(); void NotifyLevelChanged(uint64_t id, int level); void NotifyMuteChanged(bool is_input, bool is_muted); void NotifyDevicesChanged(); @@ -172,43 +165,6 @@ observer_list_.RemoveObserver(observer); } -bool AudioServiceImpl::GetInfo(OutputInfo* output_info_out, - InputInfo* input_info_out) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - DCHECK(cras_audio_handler_); - DCHECK(output_info_out); - DCHECK(input_info_out); - - if (!cras_audio_handler_) - return false; - - ash::AudioDeviceList devices; - cras_audio_handler_->GetAudioDevices(&devices); - for (size_t i = 0; i < devices.size(); ++i) { - if (!devices[i].is_input) { - OutputDeviceInfo info; - info.id = base::NumberToString(devices[i].id); - info.name = devices[i].device_name + ": " + devices[i].display_name; - info.is_active = devices[i].active; - info.volume = - cras_audio_handler_->GetOutputVolumePercentForDevice(devices[i].id); - info.is_muted = - cras_audio_handler_->IsOutputMutedForDevice(devices[i].id); - output_info_out->push_back(std::move(info)); - } else { - InputDeviceInfo info; - info.id = base::NumberToString(devices[i].id); - info.name = devices[i].device_name + ": " + devices[i].display_name; - info.is_active = devices[i].active; - info.gain = - cras_audio_handler_->GetInputGainPercentForDevice(devices[i].id); - info.is_muted = cras_audio_handler_->IsInputMutedForDevice(devices[i].id); - input_info_out->push_back(std::move(info)); - } - } - return true; -} - bool AudioServiceImpl::GetDevices(const api::audio::DeviceFilter* filter, DeviceInfoList* devices_out) { if (!cras_audio_handler_) @@ -245,21 +201,6 @@ return false; } -void AudioServiceImpl::SetActiveDevices(const DeviceIdList& device_list) { - DCHECK(cras_audio_handler_); - if (!cras_audio_handler_) - return; - - CrasAudioHandler::NodeIdList id_list; - for (const auto& id : device_list) { - const AudioDevice* device = - cras_audio_handler_->GetDeviceFromId(GetIdFromStr(id)); - if (device) - id_list.push_back(device->id); - } - cras_audio_handler_->ChangeActiveNodes(id_list); -} - bool AudioServiceImpl::SetActiveDeviceLists( const DeviceIdList* input_devices, const DeviceIdList* output_devives) { @@ -300,8 +241,7 @@ } bool AudioServiceImpl::SetDeviceSoundLevel(const std::string& device_id, - int volume, - int gain) { + int level_value) { DCHECK(cras_audio_handler_); if (!cras_audio_handler_) return false; @@ -311,11 +251,8 @@ if (!device) return false; - if (!device->is_input && volume != -1) { - cras_audio_handler_->SetVolumeGainPercentForDevice(device->id, volume); - return true; - } else if (device->is_input && gain != -1) { - cras_audio_handler_->SetVolumeGainPercentForDevice(device->id, gain); + if (level_value != -1) { + cras_audio_handler_->SetVolumeGainPercentForDevice(device->id, level_value); return true; } @@ -331,21 +268,6 @@ return false; } -bool AudioServiceImpl::SetMuteForDevice(const std::string& device_id, - bool value) { - DCHECK(cras_audio_handler_); - if (!cras_audio_handler_) - return false; - - const AudioDevice* device = - cras_audio_handler_->GetDeviceFromId(GetIdFromStr(device_id)); - if (!device) - return false; - - cras_audio_handler_->SetMuteForDevice(device->id, value); - return true; -} - bool AudioServiceImpl::SetMute(bool is_input, bool value) { DCHECK(cras_audio_handler_); if (!cras_audio_handler_) @@ -449,35 +371,18 @@ NotifyDevicesChanged(); } -void AudioServiceImpl::OnActiveOutputNodeChanged() { - NotifyDeviceChanged(); -} +void AudioServiceImpl::OnActiveOutputNodeChanged() {} -void AudioServiceImpl::OnActiveInputNodeChanged() { - NotifyDeviceChanged(); -} - -void AudioServiceImpl::NotifyDeviceChanged() { - for (auto& observer : observer_list_) - observer.OnDeviceChanged(); -} +void AudioServiceImpl::OnActiveInputNodeChanged() {} void AudioServiceImpl::NotifyLevelChanged(uint64_t id, int level) { for (auto& observer : observer_list_) observer.OnLevelChanged(base::NumberToString(id), level); - - // Notify DeviceChanged event for backward compatibility. - // TODO(jennyz): remove this code when the old version of hotrod retires. - NotifyDeviceChanged(); } void AudioServiceImpl::NotifyMuteChanged(bool is_input, bool is_muted) { for (auto& observer : observer_list_) observer.OnMuteChanged(is_input, is_muted); - - // Notify DeviceChanged event for backward compatibility. - // TODO(jennyz): remove this code when the old version of hotrod retires. - NotifyDeviceChanged(); } void AudioServiceImpl::NotifyDevicesChanged() { @@ -493,10 +398,6 @@ for (auto& observer : observer_list_) observer.OnDevicesChanged(device_info_list); - - // Notify DeviceChanged event for backward compatibility. - // TODO(jennyz): remove this code when the old version of hotrod retires. - NotifyDeviceChanged(); } AudioService::Ptr AudioService::CreateInstance(
diff --git a/extensions/browser/api/audio/audio_service_lacros.cc b/extensions/browser/api/audio/audio_service_lacros.cc index 7a49a3cc..bfa84e9 100644 --- a/extensions/browser/api/audio/audio_service_lacros.cc +++ b/extensions/browser/api/audio/audio_service_lacros.cc
@@ -85,15 +85,6 @@ AudioServiceLacros::~AudioServiceLacros() = default; -bool AudioServiceLacros::GetInfo(OutputInfo* output_info_out, - InputInfo* input_info_out) { - // This method is used by a deprecated GetInfo method. - // Not implemented in lacros-chrome. - // TODO: remove deprecated methods (b/235198864) - NOTIMPLEMENTED(); - return false; -} - bool AudioServiceLacros::GetDevices(const api::audio::DeviceFilter* filter, DeviceInfoList* devices_out) { // Not used in lacros-chrome, chrome.audio is asynchronous via a callback. @@ -157,16 +148,8 @@ return true; } -void AudioServiceLacros::SetActiveDevices(const DeviceIdList& device_list) { - // This method is used by a deprecated SetActiveDevices variant. - // Not implemented in lacros-chrome. - // TODO: remove deprecated methods (b/235198864) - NOTIMPLEMENTED(); -} - bool AudioServiceLacros::SetDeviceSoundLevel(const std::string& device_id, - int volume, - int gain) { + int level_value) { // Not used in lacros-chrome, chrome.audio is asynchronous via a callback. NOTREACHED(); return false; @@ -188,11 +171,6 @@ return true; } -bool AudioServiceLacros::SetMuteForDevice(const std::string& device_id, - bool value) { - return false; -} - bool AudioServiceLacros::SetMute(bool is_input, bool value) { // Not used in lacros-chrome, chrome.audio is asynchronous via a callback. NOTREACHED();
diff --git a/extensions/browser/api/audio/audio_service_lacros.h b/extensions/browser/api/audio/audio_service_lacros.h index db9d1ba..a44cf6e 100644 --- a/extensions/browser/api/audio/audio_service_lacros.h +++ b/extensions/browser/api/audio/audio_service_lacros.h
@@ -27,25 +27,21 @@ void AddObserver(Observer* observer) override; void RemoveObserver(Observer* observer) override; - bool GetInfo(OutputInfo* output_info_out, InputInfo* input_info_out) override; bool GetDevices(const api::audio::DeviceFilter* filter, DeviceInfoList* devices_out) override; bool GetDevices( const api::audio::DeviceFilter* filter, base::OnceCallback<void(bool, DeviceInfoList)> callback) override; - void SetActiveDevices(const DeviceIdList& device_list) override; bool SetActiveDeviceLists(const DeviceIdList* input_devices, const DeviceIdList* output_devives) override; bool SetActiveDeviceLists(const DeviceIdList* input_devices, const DeviceIdList* output_devives, base::OnceCallback<void(bool)> callback) override; bool SetDeviceSoundLevel(const std::string& device_id, - int volume, - int gain) override; + int level_value) override; bool SetDeviceSoundLevel(const std::string& device_id, int level_value, base::OnceCallback<void(bool)> callback) override; - bool SetMuteForDevice(const std::string& device_id, bool value) override; bool SetMute(bool is_input, bool value) override; bool SetMute(bool is_input, bool value,
diff --git a/extensions/browser/api/networking_private/lacros_networking_private_observer.cc b/extensions/browser/api/networking_private/lacros_networking_private_observer.cc index 5c2be3e74..efa68a3f 100644 --- a/extensions/browser/api/networking_private/lacros_networking_private_observer.cc +++ b/extensions/browser/api/networking_private/lacros_networking_private_observer.cc
@@ -79,6 +79,12 @@ } } +void LacrosNetworkingPrivateObserver::OnCertificateListsChanged() { + for (auto& observer : lacros_observers_) { + observer.OnCertificateListsChanged(); + } +} + void LacrosNetworkingPrivateObserver::AddObserver( extensions::NetworkingPrivateDelegateObserver* observer) { lacros_observers_.AddObserver(observer);
diff --git a/extensions/browser/api/networking_private/lacros_networking_private_observer.h b/extensions/browser/api/networking_private/lacros_networking_private_observer.h index 34e99af..752bf2e 100644 --- a/extensions/browser/api/networking_private/lacros_networking_private_observer.h +++ b/extensions/browser/api/networking_private/lacros_networking_private_observer.h
@@ -32,6 +32,7 @@ void OnPortalDetectionCompleted( const std::string& networkGuid, crosapi::mojom::CaptivePortalStatus status) override; + void OnCertificateListsChanged() override; void AddObserver(extensions::NetworkingPrivateDelegateObserver* observer); void RemoveObserver(extensions::NetworkingPrivateDelegateObserver* observer);
diff --git a/extensions/browser/api/networking_private/networking_private_delegate_observer.h b/extensions/browser/api/networking_private/networking_private_delegate_observer.h index 9a784d6..fb49bfc 100644 --- a/extensions/browser/api/networking_private/networking_private_delegate_observer.h +++ b/extensions/browser/api/networking_private/networking_private_delegate_observer.h
@@ -39,6 +39,9 @@ std::string networkGuid, api::networking_private::CaptivePortalStatus status) = 0; + // Notifies observers when any certificate list has changed. + virtual void OnCertificateListsChanged() = 0; + protected: virtual ~NetworkingPrivateDelegateObserver() {} };
diff --git a/extensions/browser/api/networking_private/networking_private_event_router_nonchromeos.cc b/extensions/browser/api/networking_private/networking_private_event_router_nonchromeos.cc index 2a8761a..bee455a4 100644 --- a/extensions/browser/api/networking_private/networking_private_event_router_nonchromeos.cc +++ b/extensions/browser/api/networking_private/networking_private_event_router_nonchromeos.cc
@@ -46,6 +46,7 @@ void OnPortalDetectionCompleted( std::string networkGuid, api::networking_private::CaptivePortalStatus status) override; + void OnCertificateListsChanged() override; private: // Decide if we should listen for network changes or not. If there are any @@ -195,6 +196,20 @@ event_router->BroadcastEvent(std::move(extension_event)); } +void NetworkingPrivateEventRouterImpl::OnCertificateListsChanged() { + EventRouter* event_router = EventRouter::Get(browser_context_); + if (!event_router) { + return; + } + + auto args(api::networking_private::OnCertificateListsChanged::Create()); + auto extension_event = std::make_unique<Event>( + events::NETWORKING_PRIVATE_ON_CERTIFICATE_LISTS_CHANGED, + api::networking_private::OnCertificateListsChanged::kEventName, + std::move(args)); + event_router->BroadcastEvent(std::move(extension_event)); +} + NetworkingPrivateEventRouter* NetworkingPrivateEventRouter::Create( content::BrowserContext* browser_context) { return new NetworkingPrivateEventRouterImpl(browser_context);
diff --git a/extensions/browser/extension_event_histogram_value.h b/extensions/browser/extension_event_histogram_value.h index 07fb305b..4afa5df 100644 --- a/extensions/browser/extension_event_histogram_value.h +++ b/extensions/browser/extension_event_histogram_value.h
@@ -42,7 +42,7 @@ APP_WINDOW_ON_RESTORED = 21, DELETED_AUDIO_MODEM_ON_RECEIVED = 22, DELETED_AUDIO_MODEM_ON_TRANSMIT_FAIL = 23, - AUDIO_ON_DEVICE_CHANGED = 24, + DELETED_AUDIO_ON_DEVICE_CHANGED = 24, AUDIO_ON_DEVICES_CHANGED = 25, AUDIO_ON_LEVEL_CHANGED = 26, AUDIO_ON_MUTE_CHANGED = 27,
diff --git a/extensions/browser/extension_function_histogram_value.h b/extensions/browser/extension_function_histogram_value.h index 69781d5..2e2cc3d 100644 --- a/extensions/browser/extension_function_histogram_value.h +++ b/extensions/browser/extension_function_histogram_value.h
@@ -515,7 +515,7 @@ DELETED_BLUETOOTH_REMOVEPROFILE = 454, DELETED_BLUETOOTH_GETPROFILES = 455, EXPERIMENTAL_IDENTITY_REMOVECACHEDAUTHTOKEN = 456, - AUDIO_GETINFO = 457, + DELETED_AUDIO_GETINFO = 457, AUDIO_SETACTIVEDEVICES = 458, AUDIO_SETPROPERTIES = 459, USB_RESETDEVICE = 460, @@ -1723,7 +1723,7 @@ SHAREDSTORAGEPRIVATE_GET = 1660, SHAREDSTORAGEPRIVATE_SET = 1661, SHAREDSTORAGEPRIVATE_REMOVE = 1662, - FILEMANAGERPRIVATEINTERNAL_GETFILESRESTRICTEDBYDLP = 1663, + FILEMANAGERPRIVATEINTERNAL_GETDLPMETADATA = 1663, WMDESKSPRIVATE_GETALLDESKS = 1664, AUTOTESTPRIVATE_FORCEAUTOTHEMEMODE = 1665, OS_TELEMETRY_GETSTATEFULPARTITIONINFO = 1666,
diff --git a/extensions/common/api/_behavior_features.json b/extensions/common/api/_behavior_features.json index 7a546ee7..e9a19c4 100644 --- a/extensions/common/api/_behavior_features.json +++ b/extensions/common/api/_behavior_features.json
@@ -110,21 +110,6 @@ "location": "policy", "platforms": ["chromeos"] }], - "allow_deprecated_audio_api": { - "channel": "stable", - "extension_types": ["platform_app"], - "allowlist": [ - "8C3741E3AF0B93B6E8E0DDD499BB0B74839EA578", - "E703483CEF33DEC18B4B6DD84B5C776FB9182BDB", - "A3BC37E2148AC4E99BE4B16AF9D42DD1E592BBBE", // http://crbug.com/335729 - "1C93BD3CF875F4A73C0B2A163BB8FBDA8B8B3D80", // http://crbug.com/335729 - "307E96539209F95A1A8740C713E6998A73657D96", // http://crbug.com/335729 - "4F25792AF1AA7483936DE29C07806F203C7170A0", // http://crbug.com/407693 - "BD8781D757D830FC2E85470A1B6E8A718B7EE0D9", // http://crbug.com/407693 - "4AC2B6C63C6480D150DFDA13E4A5956EB1D0DDBB", // http://crbug.com/407693 - "81986D4F846CEDDDB962643FA501D1780DD441BB" // http://crbug.com/407693 - ] - }, "allow_secondary_kiosk_app_enabled_on_launch": { "channel": "dev", "extension_types": ["platform_app"]
diff --git a/extensions/common/api/audio.idl b/extensions/common/api/audio.idl index cb821b4..917be46 100644 --- a/extensions/common/api/audio.idl +++ b/extensions/common/api/audio.idl
@@ -34,34 +34,6 @@ OTHER }; - [nodoc, deprecated = "Used only with the deprecated $(ref:getInfo)."] - dictionary OutputDeviceInfo { - // The unique identifier of the audio output device. - DOMString id; - // The user-friendly name (e.g. "Bose Amplifier"). - DOMString name; - // True if this is the current active device. - boolean isActive; - // True if this is muted. - boolean isMuted; - // The output volume ranging from 0.0 to 100.0. - double volume; - }; - - [nodoc, deprecated = "Used only with the deprecated $(ref:getInfo)."] - dictionary InputDeviceInfo { - // The unique identifier of the audio input device. - DOMString id; - // The user-friendly name (e.g. "USB Microphone"). - DOMString name; - // True if this is the current active device. - boolean isActive; - // True if this is muted. - boolean isMuted; - // The input gain ranging from 0.0 to 100.0. - double gain; - }; - dictionary AudioDeviceInfo { // The unique identifier of the audio device. DOMString id; @@ -92,22 +64,10 @@ }; dictionary DeviceProperties { - // True if this is muted. - [nodoc, deprecated="Use $(ref:setMute) to set mute state."] - boolean? isMuted; - - // If this is an output device then this field indicates the output volume. - // If this is an input device then this field is ignored. - [nodoc, deprecated="Use |level| to set output volume."] double? volume; - - // If this is an input device then this field indicates the input gain. - // If this is an output device then this field is ignored. - [nodoc, deprecated="Use |level| to set input gain."] double? gain; - // <p> // The audio device's desired sound level. Defaults to the device's // current sound level. - // </p> + // </p> // <p>If used with audio input device, represents audio device gain.</p> // <p>If used with audio output device, represents audio device volume.</p> long? level; @@ -142,8 +102,6 @@ long level; }; - callback GetInfoCallback = void(OutputDeviceInfo[] outputInfo, - InputDeviceInfo[] inputInfo); callback GetDevicesCallback = void(AudioDeviceInfo[] devices); callback GetMuteCallback = void(boolean value); callback EmptyCallback = void(); @@ -153,7 +111,7 @@ // |filter|: Device properties by which to filter the list of returned // audio devices. If the filter is not set or set to <code>{}</code>, // returned device list will contain all available audio devices. - // |callback|: Reports the requested list of audio devices. + // |callback|: Reports the requested list of audio devices. static void getDevices(optional DeviceFilter filter, GetDevicesCallback callback); @@ -163,12 +121,7 @@ // unaffected. // </p> // <p>It is an error to pass in a non-existent device ID.</p> - // <p><b>NOTE:</b> While the method signature allows device IDs to be - // passed as a list of strings, this method of setting active devices - // is deprecated and should not be relied upon to work. Please use - // $(ref:DeviceIdLists) instead. - // </p> - static void setActiveDevices((DeviceIdLists or DOMString[]) ids, + static void setActiveDevices(DeviceIdLists ids, EmptyCallback callback); // Sets the properties for the input or output device. @@ -189,10 +142,6 @@ static void setMute(StreamType streamType, boolean isMuted, optional EmptyCallback callback); - - // Gets the information of all audio output and input devices. - [nodoc, deprecated="Use $(ref:getDevices) instead."] - static void getInfo(GetInfoCallback callback); }; interface Events { @@ -208,10 +157,5 @@ // existing devices being removed. // |devices|: List of all present audio devices after the change. static void onDeviceListChanged(AudioDeviceInfo[] devices); - - // Fired when anything changes to the audio device configuration. - [nodoc, deprecated="Use more granular $(ref:onLevelChanged), - $(ref:onMuteChanged) and $(ref:onDeviceListChanged) instead."] - static void onDeviceChanged(); }; };
diff --git a/extensions/common/features/behavior_feature.cc b/extensions/common/features/behavior_feature.cc index db470df..68eb0a0 100644 --- a/extensions/common/features/behavior_feature.cc +++ b/extensions/common/features/behavior_feature.cc
@@ -17,8 +17,6 @@ const char kSigninScreen[] = "signin_screen"; -const char kAllowDeprecatedAudioApi[] = "allow_deprecated_audio_api"; - const char kAllowSecondaryKioskAppEnabledOnLaunch[] = "allow_secondary_kiosk_app_enabled_on_launch";
diff --git a/extensions/common/features/behavior_feature.h b/extensions/common/features/behavior_feature.h index 3c4b6312..7ed3e17 100644 --- a/extensions/common/features/behavior_feature.h +++ b/extensions/common/features/behavior_feature.h
@@ -15,7 +15,6 @@ extern const char kZoomWithoutBubble[]; extern const char kAllowUsbDevicesPermissionInterfaceClass[]; extern const char kSigninScreen[]; -extern const char kAllowDeprecatedAudioApi[]; extern const char kAllowSecondaryKioskAppEnabledOnLaunch[]; extern const char kKeyPermissionsInLoginScreen[]; extern const char kImprivataInSessionExtension[];
diff --git a/extensions/test/data/api_test/audio/deprecated_api/manifest.json b/extensions/test/data/api_test/audio/deprecated_api/manifest.json deleted file mode 100644 index 3cde7f13..0000000 --- a/extensions/test/data/api_test/audio/deprecated_api/manifest.json +++ /dev/null
@@ -1,8 +0,0 @@ -{ - "key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4Gb8dd92HGWI64TMqr7Qr+A0WwG2kMhoNYR6bYO/0klVnNdZ5q8u46wvqu3aNkzhbe5r7Zf4utKenC6dPMm22b/4+Qge1ng+NHRbCSiwcy3JMhrO93gGQLueP5KRQhy+fXTeAJugAj4vR8nkfYOJaeauosh1f7I4D3Gy2XI+E5mo3/TUVxxRgOYMZIYsXlPStdhUuPe3QltZZxPCNv98UX30F1NhrNoeKIHyf83++Egxb/CwMtX9Dog15V56qBbiuXLECWu7+GY/GCKt9LAX5ieyEziV6Uq8/ISB1hwOThQWPFRd7NbHVisPGwyoMPX4DL57eYfKAwl1U2KbP+KdAQIDAQAB", - "app": { "background": { "scripts": ["test.js"] } }, - "manifest_version": 2, - "name": "Audio API Test Extension", - "permissions": ["audio"], - "version": "1.0" -}
diff --git a/extensions/test/data/api_test/audio/deprecated_api/test.js b/extensions/test/data/api_test/audio/deprecated_api/test.js deleted file mode 100644 index e6658789..0000000 --- a/extensions/test/data/api_test/audio/deprecated_api/test.js +++ /dev/null
@@ -1,237 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -/** - * Asserts that device property values match properties in |expectedProperties|. - * The method will *not* assert that the device contains *only* properties - * specified in expected properties. - * @param {Object} expectedProperties Expected device properties. - * @param {Object} device Device object to test. - */ -function assertDeviceMatches(expectedProperties, device) { - Object.keys(expectedProperties).forEach(function(key) { - chrome.test.assertEq(expectedProperties[key], device[key], - 'Property ' + key + ' of device ' + device.id); - }); -} - -/** - * Verifies that list of devices contains all and only devices from set of - * expected devices. If will fail the test if an unexpected device is found. - * - * @param {Object.<string, Object>} expectedDevices Expected set of test - * devices. Maps device ID to device properties. - * @param {Array.<Object>} devices List of input devices. - */ -function assertDevicesMatch(expectedDevices, devices) { - var deviceIds = {}; - devices.forEach(function(device) { - chrome.test.assertFalse(!!deviceIds[device.id], - 'Duplicated device id: \'' + device.id + '\'.'); - deviceIds[device.id] = true; - }); - - function sortedKeys(obj) { - return Object.keys(obj).sort(); - } - chrome.test.assertEq(sortedKeys(expectedDevices), sortedKeys(deviceIds)); - - devices.forEach(function(device) { - assertDeviceMatches(expectedDevices[device.id], device); - }); -} - -/** - * @param {Array.<Object>} devices List of devices returned by - * chrome.audio.getInfo or chrome.audio.getDevices. - * @return {Object.<string, Object>} List of devices formatted as map of - * expected devices used to assert devices match expectation. - */ -function deviceListToExpectedDevicesMap(devices) { - var expectedDevicesMap = {}; - devices.forEach(function(device) { - expectedDevicesMap[device.id] = device; - }); - return expectedDevicesMap; -} - -function EventListener(targetEvent) { - this.targetEvent = targetEvent; - this.listener = this.handleEvent.bind(this); - this.targetEvent.addListener(this.listener); - this.eventCount = 0; -} - -EventListener.prototype.handleEvent = function() { - ++this.eventCount; -} - -EventListener.prototype.reset = function() { - this.targetEvent.removeListener(this.listener); -} - -var deviceChangedListener = null; - -chrome.test.runTests([ - // Sets up a listener for audio.onDeviceChanged event - - // |verifyDeviceChangedEvents| test will later verify that - // onDeviceChanged events have been observed. - function startDeviceChangedListener() { - deviceChangedListener = new EventListener(chrome.audio.onDeviceChanged); - chrome.test.succeed(); - }, - - function getInfoTest() { - // Test output devices. Maps device ID -> tested device properties. - var kTestOutputDevices = { - '30001': { - id: '30001', - name: 'Jabra Speaker: Jabra Speaker 1' - }, - '30002': { - id: '30002', - name: 'Jabra Speaker: Jabra Speaker 2' - }, - '30003': { - id: '30003', - name: 'HDMI output: HDA Intel MID' - } - }; - - // Test input devices. Maps device ID -> tested device properties. - var kTestInputDevices = { - '40001': { - id: '40001', - name: 'Jabra Mic: Jabra Mic 1' - }, - '40002': { - id: '40002', - name: 'Jabra Mic: Jabra Mic 2' - }, - '40003': { - id: '40003', - name: 'Webcam Mic: Logitech Webcam' - } - }; - - chrome.audio.getInfo(chrome.test.callbackPass( - function(outputInfo, inputInfo) { - assertDevicesMatch(kTestOutputDevices, outputInfo); - assertDevicesMatch(kTestInputDevices, inputInfo); - })); - }, - - function setActiveDevicesTest() { - //Test output devices. Maps device ID -> tested device properties. - var kTestDevices = { - '30001': { - id: '30001', - isActive: false - }, - '30002': { - id: '30002', - isActive: false - }, - '30003': { - id: '30003', - isActive: true - }, - '40001': { - id: '40001', - isActive: false - }, - '40002': { - id: '40002', - isActive: true - }, - '40003': { - id: '40003', - isActive: false - } - }; - - chrome.audio.setActiveDevices([ - '30003', - '40002' - ], chrome.test.callbackPass(function() { - chrome.audio.getDevices(chrome.test.callbackPass(function(devices) { - assertDevicesMatch(kTestDevices, devices); - })); - })); - }, - - function setPropertiesTest() { - chrome.audio.getInfo(chrome.test.callbackPass(function( - initialOutput, initialInput) { - var expectedInput = deviceListToExpectedDevicesMap(initialInput); - var expectedOutput = deviceListToExpectedDevicesMap(initialOutput); - - // Update expected input devices with values that should be changed in - // test. - var updatedInput = expectedInput['40002']; - chrome.test.assertFalse(updatedInput.isMuted); - chrome.test.assertFalse(updatedInput.gain === 55); - updatedInput.isMuted = true; - updatedInput.gain = 55; - - // Update expected output devices with values that should be changed in - // test. - var updatedOutput = expectedOutput['30001']; - chrome.test.assertFalse(updatedOutput.volume === 35); - updatedOutput.volume = 35; - - chrome.audio.setProperties('30001', { - volume: 35 - }, chrome.test.callbackPass(function() { - chrome.audio.setProperties('40002', { - isMuted: true, - gain: 55 - }, chrome.test.callbackPass(function() { - chrome.audio.getInfo(chrome.test.callbackPass(function( - output, input) { - assertDevicesMatch(expectedOutput, output); - assertDevicesMatch(expectedInput, input); - })); - })); - })); - })); - }, - - function setPropertiesInvalidValuesTest() { - chrome.audio.getInfo(chrome.test.callbackPass(function( - initialOutput, initialInput) { - var expectedOutput = deviceListToExpectedDevicesMap(initialOutput); - var expectedInput = deviceListToExpectedDevicesMap(initialInput); - var expectedError = 'Could not set volume/gain properties'; - - chrome.audio.setProperties('30001', { - isMuted: true, - // Output device - should have volume set. - gain: 55 - }, chrome.test.callbackFail(expectedError, function() { - chrome.audio.setProperties('40002', { - isMuted: true, - // Input device - should have gain set. - volume:55 - }, chrome.test.callbackFail(expectedError, function() { - // Assert that device properties haven't changed. - chrome.audio.getInfo(chrome.test.callbackPass(function( - output, input) { - assertDevicesMatch(expectedOutput, output); - assertDevicesMatch(expectedInput, input); - })); - })); - })); - })); - }, - - function verifyDeviceChangedEvents() { - chrome.test.assertTrue(!!deviceChangedListener); - chrome.test.assertTrue(deviceChangedListener.eventCount > 0); - deviceChangedListener.reset(); - deviceChangedListener = null; - chrome.test.succeed(); - }, - -]);
diff --git a/extensions/test/data/api_test/audio/test.js b/extensions/test/data/api_test/audio/test.js index eeb5d8db..215571f 100644 --- a/extensions/test/data/api_test/audio/test.js +++ b/extensions/test/data/api_test/audio/test.js
@@ -66,32 +66,9 @@ return devices.map(function(device) {return device.id;}).sort(); } -function EventListener(targetEvent) { - this.targetEvent = targetEvent; - this.listener = this.handleEvent.bind(this); - this.targetEvent.addListener(this.listener); - this.eventCount = 0; -} - -EventListener.prototype.handleEvent = function() { - ++this.eventCount; -} - -EventListener.prototype.reset = function() { - this.targetEvent.removeListener(this.listener); -} - var deviceChangedListener = null; chrome.test.runTests([ - // Sets up a listener for audio.onDeviceChanged event - - // |verifyNoDeviceChangedEvents| test will later verify that no - // onDeviceChanged events have been observed. - function startDeviceChangedListener() { - deviceChangedListener = new EventListener(chrome.audio.onDeviceChanged); - chrome.test.succeed(); - }, - function getDevicesTest() { // Test output devices. Maps device ID -> tested device properties. var kTestDevices = { @@ -456,82 +433,4 @@ })); })); }, - - function verifyNoDeviceChangedEvents() { - chrome.test.assertTrue(!!deviceChangedListener); - chrome.test.assertEq(0, deviceChangedListener.eventCount); - deviceChangedListener.reset(); - deviceChangedListener = null; - chrome.test.succeed(); - }, - - // Tests verifying the app doesn't have access to deprecated part of the API: - function deprecated_GetInfoTest() { - chrome.audio.getInfo(chrome.test.callbackFail( - 'audio.getInfo is deprecated, use audio.getDevices instead.')); - }, - - function deprecated_setProperties_isMuted() { - chrome.audio.getDevices(chrome.test.callbackPass(function(initial) { - var expectedDevices = deviceListToExpectedDevicesMap(initial); - var expectedError = - '|isMuted| property is deprecated, use |audio.setMute|.'; - - chrome.audio.setProperties('30001', { - isMuted: true, - // Output device - should have volume set. - level: 55 - }, chrome.test.callbackFail(expectedError, function() { - // Assert that device properties haven't changed. - chrome.audio.getDevices(chrome.test.callbackPass(function(devices) { - assertDevicesMatch(expectedDevices, devices); - })); - })); - })); - }, - - function deprecated_setProperties_volume() { - chrome.audio.getDevices(chrome.test.callbackPass(function(initial) { - var expectedDevices = deviceListToExpectedDevicesMap(initial); - var expectedError = '|volume| property is deprecated, use |level|.'; - - chrome.audio.setProperties('30001', { - volume: 2, - // Output device - should have volume set. - level: 55 - }, chrome.test.callbackFail(expectedError, function() { - // Assert that device properties haven't changed. - chrome.audio.getDevices(chrome.test.callbackPass(function(devices) { - assertDevicesMatch(expectedDevices, devices); - })); - })); - })); - }, - - function deprecated_setProperties_gain() { - chrome.audio.getDevices(chrome.test.callbackPass(function(initial) { - var expectedDevices = deviceListToExpectedDevicesMap(initial); - var expectedError = '|gain| property is deprecated, use |level|.'; - - chrome.audio.setProperties('40001', { - gain: 2, - // Output device - should have volume set. - level: 55 - }, chrome.test.callbackFail(expectedError, function() { - // Assert that device properties haven't changed. - chrome.audio.getDevices(chrome.test.callbackPass(function(devices) { - assertDevicesMatch(expectedDevices, devices); - })); - })); - })); - }, - - function deprecated_SetActiveDevicesTest() { - var kExpectedError = - 'String list |ids| is deprecated, use DeviceIdLists type.'; - chrome.audio.setActiveDevices([ - '30003', - '40002' - ], chrome.test.callbackFail(kExpectedError)); - }, ]);
diff --git a/gpu/command_buffer/service/shared_image_backing_factory_angle_vulkan.cc b/gpu/command_buffer/service/shared_image_backing_factory_angle_vulkan.cc index 33206e1f..b7bfe43d 100644 --- a/gpu/command_buffer/service/shared_image_backing_factory_angle_vulkan.cc +++ b/gpu/command_buffer/service/shared_image_backing_factory_angle_vulkan.cc
@@ -597,7 +597,7 @@ context_state->progress_reporter()), context_state_(context_state) { DCHECK(context_state_->GrContextIsVulkan()); - DCHECK(gl::GLSurfaceEGL::GetGLDisplayEGL()->ext->b_EGL_ANGLE_vulkan_image); + DCHECK(gl::GLSurfaceEGL::GetGLDisplayEGL()->IsANGLEVulkanImageSupported()); } SharedImageBackingFactoryAngleVulkan::~SharedImageBackingFactoryAngleVulkan() =
diff --git a/gpu/command_buffer/service/shared_image_backing_factory_ozone.cc b/gpu/command_buffer/service/shared_image_backing_factory_ozone.cc index 8d5944e..ae564df0 100644 --- a/gpu/command_buffer/service/shared_image_backing_factory_ozone.cc +++ b/gpu/command_buffer/service/shared_image_backing_factory_ozone.cc
@@ -22,7 +22,6 @@ #include "ui/gfx/gpu_memory_buffer.h" #include "ui/gfx/native_pixmap.h" #include "ui/gl/buildflags.h" -#include "ui/gl/gl_bindings.h" #include "ui/gl/gl_surface_egl.h" #include "ui/ozone/public/ozone_platform.h" #include "ui/ozone/public/surface_factory_ozone.h" @@ -235,7 +234,7 @@ return false; } if (used_by_gl && - !gl::GLSurfaceEGL::GetGLDisplayEGL()->ext->b_EGL_KHR_image) { + !gl::GLSurfaceEGL::GetGLDisplayEGL()->HasEGLExtension("EGL_KHR_image")) { return false; } #else
diff --git a/gpu/command_buffer/service/shared_image_factory.cc b/gpu/command_buffer/service/shared_image_factory.cc index 1f37a592b..a92b327f 100644 --- a/gpu/command_buffer/service/shared_image_factory.cc +++ b/gpu/command_buffer/service/shared_image_factory.cc
@@ -264,7 +264,7 @@ #endif // BUILDFLAG(ENABLE_VULKAN) bool egl_ext_supported = - gl::GLSurfaceEGL::GetGLDisplayEGL()->ext->b_EGL_KHR_image; + gl::GLSurfaceEGL::GetGLDisplayEGL()->HasEGLExtension("EGL_KHR_image"); bool glx_ext_supported = false; #if defined(USE_OZONE) #if BUILDFLAG(OZONE_PLATFORM_X11)
diff --git a/gpu/config/gpu_info_collector.cc b/gpu/config/gpu_info_collector.cc index d95ffa8..56406bb 100644 --- a/gpu/config/gpu_info_collector.cc +++ b/gpu/config/gpu_info_collector.cc
@@ -386,11 +386,13 @@ base::UmaHistogramSparse("GPU.MaxMSAASampleCount", max_samples); #if BUILDFLAG(IS_ANDROID) - gl::GLDisplayEGL* display = gl::GLSurfaceEGL::GetGLDisplayEGL(); gpu_info->can_support_threaded_texture_mailbox = - display->ext->b_EGL_KHR_fence_sync && - display->ext->b_EGL_KHR_image_base && - display->ext->b_EGL_KHR_gl_texture_2D_image && + gl::GLSurfaceEGL::GetGLDisplayEGL()->HasEGLExtension( + "EGL_KHR_fence_sync") && + gl::GLSurfaceEGL::GetGLDisplayEGL()->HasEGLExtension( + "EGL_KHR_image_base") && + gl::GLSurfaceEGL::GetGLDisplayEGL()->HasEGLExtension( + "EGL_KHR_gl_texture_2D_image") && gfx::HasExtension(extension_set, "GL_OES_EGL_image"); #else gl::GLWindowSystemBindingInfo window_system_binding_info; @@ -564,7 +566,7 @@ const GpuPreferences& prefs) { // Populate the list of ANGLE features by querying the functions exposed by // EGL_ANGLE_feature_control if it's available. - if (gl::g_driver_egl.client_ext.b_EGL_ANGLE_feature_control) { + if (gl::GLSurfaceEGL::GetGLDisplayEGL()->IsANGLEFeatureControlSupported()) { EGLDisplay display = gl::GLSurfaceEGL::GetGLDisplayEGL()->GetHardwareDisplay(); EGLAttrib feature_count = 0;
diff --git a/headless/lib/browser/headless_web_contents_impl.cc b/headless/lib/browser/headless_web_contents_impl.cc index 9108af1..807879aa 100644 --- a/headless/lib/browser/headless_web_contents_impl.cc +++ b/headless/lib/browser/headless_web_contents_impl.cc
@@ -10,6 +10,7 @@ #include <vector> #include "base/bind.h" +#include "base/command_line.h" #include "base/memory/ptr_util.h" #include "base/memory/raw_ptr.h" #include "base/memory/weak_ptr.h" @@ -34,6 +35,7 @@ #include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents_delegate.h" #include "content/public/common/bindings_policy.h" +#include "content/public/common/content_switches.h" #include "content/public/common/origin_util.h" #include "headless/lib/browser/headless_browser_context_impl.h" #include "headless/lib/browser/headless_browser_impl.h" @@ -320,6 +322,14 @@ browser_context->options()->accept_language(); web_contents_->GetMutableRendererPrefs()->hinting = browser_context->options()->font_render_hinting(); + + base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); + if (command_line->HasSwitch(switches::kForceWebRtcIPHandlingPolicy)) { + web_contents_->GetMutableRendererPrefs()->webrtc_ip_handling_policy = + command_line->GetSwitchValueASCII( + switches::kForceWebRtcIPHandlingPolicy); + } + web_contents_->SetDelegate(web_contents_delegate_.get()); render_process_host_->AddObserver(this); agent_host_->AddObserver(this);
diff --git a/ios/build/tools/convert_gn_xcodeproj.py b/ios/build/tools/convert_gn_xcodeproj.py index 1f30bd9d..603d343 100755 --- a/ios/build/tools/convert_gn_xcodeproj.py +++ b/ios/build/tools/convert_gn_xcodeproj.py
@@ -351,39 +351,42 @@ root_dir, project_dir, old_project_dir, obj['name'], product_path, tests) + root_object = project.objects[json_data['rootObject']] + main_group = project.objects[root_object['mainGroup']] - source = GetOrCreateRootGroup(project, json_data['rootObject'], 'Source') - AddMarkdownToProject(project, root_dir, source) - SortFileReferencesByName(project, source) + sources = None + for child_key in main_group['children']: + child = project.objects[child_key] + if child.get('name') == 'Source' or child.get('name') == 'Sources': + sources = child + break + + if sources is None: + sources = main_group + + AddMarkdownToProject(project, root_dir, sources, sources is main_group) + SortFileReferencesByName(project, sources, root_object.get('productRefGroup')) objects = collections.OrderedDict(sorted(project.objects.items())) WriteXcodeProject(project_dir, json.dumps(json_data)) -def CreateGroup(project, parent_group, group_name, path=None): +def CreateGroup(project, parent_group, group_name, use_relative_paths): group_object = { 'children': [], 'isa': 'PBXGroup', - 'name': group_name, 'sourceTree': '<group>', } - if path is not None: - group_object['path'] = path + if use_relative_paths: + group_object['path'] = group_name + else: + group_object['name'] = group_name parent_group_name = parent_group.get('name', '') group_object_key = project.AddObject(parent_group_name, group_object) parent_group['children'].append(group_object_key) return group_object -def GetOrCreateRootGroup(project, root_object, group_name): - main_group = project.objects[project.objects[root_object]['mainGroup']] - for child_key in main_group['children']: - child = project.objects[child_key] - if child['name'] == group_name: - return child - return CreateGroup(project, main_group, group_name, path='../..') - - class ObjectKey(object): """Wrapper around PBXFileReference and PBXGroup for sorting. @@ -401,19 +404,24 @@ is checked and compared in alphabetic order. """ - def __init__(self, obj): + def __init__(self, obj, last): self.isa = obj['isa'] if 'name' in obj: self.name = obj['name'] else: self.name = obj['path'] + self.last = last def __lt__(self, other): + if self.last != other.last: + return other.last if self.isa != other.isa: return self.isa > other.isa return self.name < other.name def __gt__(self, other): + if self.last != other.last: + return self.last if self.isa != other.isa: return self.isa < other.isa return self.name > other.name @@ -422,9 +430,10 @@ return self.isa == other.isa and self.name == other.name -def SortFileReferencesByName(project, group_object): +def SortFileReferencesByName(project, group_object, products_group_ref): SortFileReferencesByNameWithSortKey( - project, group_object, lambda ref: ObjectKey(project.objects[ref])) + project, group_object, + lambda ref: ObjectKey(project.objects[ref], ref == products_group_ref)) def SortFileReferencesByNameWithSortKey(project, group_object, sort_key): @@ -435,7 +444,7 @@ SortFileReferencesByNameWithSortKey(project, child, sort_key) -def AddMarkdownToProject(project, root_dir, group_object): +def AddMarkdownToProject(project, root_dir, group_object, use_relative_paths): list_files_cmd = ['git', '-C', root_dir, 'ls-files', '*.md'] paths = check_output(list_files_cmd).splitlines() ios_internal_dir = os.path.join(root_dir, 'ios_internal') @@ -448,31 +457,43 @@ "fileEncoding": "4", "isa": "PBXFileReference", "lastKnownFileType": "net.daringfireball.markdown", - "name": os.path.basename(path), - "path": path, "sourceTree": "<group>" } - new_markdown_entry_id = project.AddObject('sources', new_markdown_entry) - folder = GetFolderForPath(project, group_object, os.path.dirname(path)) + if use_relative_paths: + new_markdown_entry['path'] = os.path.basename(path) + else: + new_markdown_entry['name'] = os.path.basename(path) + new_markdown_entry['path'] = path + folder = GetFolderForPath( + project, group_object, os.path.dirname(path), + use_relative_paths) + folder_name = folder.get('name', None) + if folder_name is None: + folder_name = folder.get('path', 'sources') + new_markdown_entry_id = project.AddObject(folder_name, new_markdown_entry) folder['children'].append(new_markdown_entry_id) -def GetFolderForPath(project, group_object, path): +def GetFolderForPath(project, group_object, path, use_relative_paths): objects = project.objects if not path: return group_object for folder in path.split('/'): children = group_object['children'] new_root = None - for child in children: - if objects[child]['isa'] == 'PBXGroup' and \ - objects[child]['name'] == folder: - new_root = objects[child] - break + for child_key in children: + child = objects[child_key] + if child['isa'] == 'PBXGroup': + child_name = child.get('name', None) + if child_name is None: + child_name = child.get('path') + if child_name == folder: + new_root = child + break if not new_root: # If the folder isn't found we could just cram it into the leaf existing # folder, but that leads to folders with tons of README.md inside. - new_root = CreateGroup(project, group_object, folder) + new_root = CreateGroup(project, group_object, folder, use_relative_paths) group_object = new_root return group_object
diff --git a/ios/chrome/browser/ui/first_run/OWNERS b/ios/chrome/browser/ui/first_run/OWNERS new file mode 100644 index 0000000..ce41692 --- /dev/null +++ b/ios/chrome/browser/ui/first_run/OWNERS
@@ -0,0 +1 @@ +jlebel@chromium.org
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 00029465..1ce55b2 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 @@ -6a201768b2d0f44fec5aae063409d5a13e75425d \ No newline at end of file +7776f31abf78d11b7350d5b31744300cfba5a2ab \ 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 a365619a..7bdb288d 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 @@ -71a4795d3484ebfe20945bd7ecb90914184c43b9 \ No newline at end of file +98188e2515d1e375167883bd88154e4e6437703a \ 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 fa680399..9570e9b4 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 @@ -a4d2036d8be0d9f73eddc1d69a08ec2be052b002 \ No newline at end of file +443a1b06914c5b658a657fca986dc598aea86e87 \ 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 5f9aeeee..9816eed 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 @@ -2b38eb6cd6862433dc763c33d82e99656d2394a4 \ No newline at end of file +3f86dac1459635954bd1e4d2f20af844e66e6dcc \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1 index e9fc6685..e1c924a 100644 --- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -985d24c939126ea502c1b0455a5f8f1eee2462d2 \ No newline at end of file +6ecf51009361a4779fe8bc09f0ff11e6acfa8ecc \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1 index 1b80ee9..eaf9926 100644 --- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -a6c33beeab199b66dce268531869022274356913 \ No newline at end of file +df9d5e658b048ae09fb1e9794b8c9982763d1399 \ 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 0ab9beed..e7424e3 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 @@ -1463b9b38c667cb45723ad93fed31b93902ea6a7 \ No newline at end of file +e6eb9295cf0298158b80aaa2b35419cdf9f2805e \ 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 47655229..18b241d 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 @@ -ecaae56795b8d4b3f2b8a0facc093e3dde87b131 \ No newline at end of file +2ae51309119eb83d7eec7a086dc4fc5eda8588f4 \ 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 ddf4bdf..d13d47f 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 @@ -3cb20e6d61c8152a1e0c08517c90a42792ecf5a2 \ No newline at end of file +05c64536bde680a3cec23c08416479c38e99216b \ 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 e8524c0..3fe28fb 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 @@ -2296badc07a9bc678307abbab68b8c2234a7b147 \ No newline at end of file +92ebcb591c43b55551d76bc7d88631c8798d7f25 \ No newline at end of file
diff --git a/media/base/video_frame_metadata.cc b/media/base/video_frame_metadata.cc index 6e82873..26214645 100644 --- a/media/base/video_frame_metadata.cc +++ b/media/base/video_frame_metadata.cc
@@ -35,6 +35,7 @@ MERGE_OPTIONAL_FIELD(capture_end_time, metadata_source); MERGE_OPTIONAL_FIELD(capture_counter, metadata_source); MERGE_OPTIONAL_FIELD(capture_update_rect, metadata_source); + MERGE_OPTIONAL_FIELD(source_size, metadata_source); MERGE_OPTIONAL_FIELD(region_capture_rect, metadata_source); MERGE_VALUE_FIELD(crop_version, metadata_source); MERGE_OPTIONAL_FIELD(copy_required, metadata_source);
diff --git a/media/base/video_frame_metadata.h b/media/base/video_frame_metadata.h index 26dbe8a..26ea562 100644 --- a/media/base/video_frame_metadata.h +++ b/media/base/video_frame_metadata.h
@@ -54,6 +54,12 @@ // fully contained within visible_rect(). absl::optional<gfx::Rect> capture_update_rect; + // For encoded frames, this is the original source size which may be different + // from the encoded size. It's used for the HiDPI tab capture heuristic. + // The size corresponds to the active region if region capture is active, + // or otherwise the full size of the captured source. + absl::optional<gfx::Size> source_size; + // If cropping was applied due to Region Capture to produce this frame, // then this reflects where the frame's contents originate from in the // original uncropped frame.
diff --git a/media/gpu/gpu_video_encode_accelerator_helpers.cc b/media/gpu/gpu_video_encode_accelerator_helpers.cc index 2f057cf..f9221bf 100644 --- a/media/gpu/gpu_video_encode_accelerator_helpers.cc +++ b/media/gpu/gpu_video_encode_accelerator_helpers.cc
@@ -9,6 +9,7 @@ #include "base/check_op.h" #include "base/notreached.h" #include "base/numerics/safe_conversions.h" +#include "media/base/bitrate.h" namespace media { namespace { @@ -193,8 +194,7 @@ VideoBitrateAllocation AllocateDefaultBitrateForTesting( const size_t num_spatial_layers, const size_t num_temporal_layers, - const uint32_t bitrate, - const bool uses_vbr) { + const Bitrate& bitrate) { // Higher spatial layers (those to the right) get more bitrate. constexpr double kSpatialLayersBitrateScaleFactors[][kMaxSpatialLayers] = { {1.00, 0.00, 0.00}, // For one spatial layer. @@ -210,11 +210,15 @@ for (size_t sid = 0; sid < num_spatial_layers; ++sid) { const double bitrate_factor = kSpatialLayersBitrateScaleFactors[num_spatial_layers - 1][sid]; - bitrates[sid] = bitrate * bitrate_factor; + bitrates[sid] = bitrate.target_bps() * bitrate_factor; } - return AllocateBitrateForDefaultEncodingWithBitrates( - bitrates, num_temporal_layers, uses_vbr); + const bool use_vbr = bitrate.mode() == Bitrate::Mode::kVariable; + auto allocation = AllocateBitrateForDefaultEncodingWithBitrates( + bitrates, num_temporal_layers, use_vbr); + if (use_vbr) + allocation.SetPeakBps(bitrate.peak_bps()); + return allocation; } } // namespace media
diff --git a/media/gpu/gpu_video_encode_accelerator_helpers.h b/media/gpu/gpu_video_encode_accelerator_helpers.h index cc454d7..32d88109 100644 --- a/media/gpu/gpu_video_encode_accelerator_helpers.h +++ b/media/gpu/gpu_video_encode_accelerator_helpers.h
@@ -7,6 +7,7 @@ #include <vector> +#include "media/base/bitrate.h" #include "media/base/video_bitrate_allocation.h" #include "media/gpu/media_gpu_export.h" #include "media/video/video_encode_accelerator.h" @@ -14,6 +15,8 @@ namespace media { +class Bitrate; + // Helper functions for VideoEncodeAccelerator implementations in GPU process. // Calculate the bitstream buffer size for VideoEncodeAccelerator. @@ -43,23 +46,19 @@ AllocateBitrateForDefaultEncoding(const VideoEncodeAccelerator::Config& config); // Create VideoBitrateAllocation with |num_spatial_layers|, -// |num_temporal_layers| and |bitrate|, additionally indicating if the -// constructed bitrate should |use_vbr|. |bitrate| is the bitrate of the entire -// stream. |num_temporal_layers| is the number of temporal layers in each -// spatial layer. |use_vbr| indicates whether the bitrate should have -// |Bitrate::Mode::kVariable.| -// First, |bitrate| is distributed to spatial layers based on libwebrtc bitrate -// division. Then the bitrate of each spatial layer is distributed to temporal -// layers in the spatial layer based on the same bitrate division ratio as a -// software encoder. If a variable bitrate is requested, the peak will be set -// equal to the target. -// TODO(crbug.com/1335250): merge |bitrate| and |uses_vbr| into a single Bitrate -// field. +// |num_temporal_layers| and |bitrate|. |bitrate.target_bps()| is the bitrate of +// the entire stream. |num_temporal_layers| is the number of temporal layers in +// each spatial layer. +// First, |bitrate.target_bps()| is distributed to spatial layers based on +// libwebrtc bitrate division. Then the bitrate of each spatial layer is +// distributed to temporal layers in the spatial layer based on the same bitrate +// division ratio as a software encoder. If a variable bitrate is requested, +// that is, |bitrate.mode()| is Bitrate::Mode::Variable, the peak will be set +// equal to the |bitrate.peak_bps()|. MEDIA_GPU_EXPORT VideoBitrateAllocation AllocateDefaultBitrateForTesting(const size_t num_spatial_layers, const size_t num_temporal_layers, - const uint32_t bitrate, - const bool uses_vbr); + const Bitrate& bitrate); } // namespace media #endif // MEDIA_GPU_GPU_VIDEO_ENCODE_ACCELERATOR_HELPERS_H_
diff --git a/media/gpu/test/video_encoder/video_encoder_test_environment.cc b/media/gpu/test/video_encoder/video_encoder_test_environment.cc index a3c6b906..3c8cf5e 100644 --- a/media/gpu/test/video_encoder/video_encoder_test_environment.cc +++ b/media/gpu/test/video_encoder/video_encoder_test_environment.cc
@@ -15,8 +15,8 @@ #include "build/buildflag.h" #include "build/chromeos_buildflags.h" #include "gpu/ipc/service/gpu_memory_buffer_factory.h" +#include "media/base/bitrate.h" #include "media/base/media_switches.h" -#include "media/base/video_bitrate_allocation.h" #include "media/gpu/buildflags.h" #include "media/gpu/gpu_video_encode_accelerator_helpers.h" #include "media/gpu/macros.h" @@ -174,18 +174,24 @@ combined_enabled_features.push_back(media::kVaapiVideoEncodeLinux); #endif - const bool use_vbr = bitrate_mode == Bitrate::Mode::kVariable; - const uint32_t bitrate = encode_bitrate.value_or( + const uint32_t target_bitrate = encode_bitrate.value_or( GetDefaultTargetBitrate(video->Resolution(), video->FrameRate())); - if (use_vbr && VideoCodecProfileToVideoCodec(profile) != VideoCodec::kH264) { + // TODO(b/181797390): Reconsider if this peak bitrate is reasonable. + const media::Bitrate bitrate = + bitrate_mode == media::Bitrate::Mode::kVariable + ? media::Bitrate::VariableBitrate(target_bitrate, + /*peak_bps=*/target_bitrate * 2) + : media::Bitrate::ConstantBitrate(target_bitrate); + if (bitrate.mode() == media::Bitrate::Mode::kVariable && + VideoCodecProfileToVideoCodec(profile) != VideoCodec::kH264) { LOG(ERROR) << "VBR is only supported for H264 encoding"; return nullptr; } return new VideoEncoderTestEnvironment( std::move(video), enable_bitstream_validator, output_folder, profile, - num_temporal_layers, num_spatial_layers, bitrate, use_vbr, - save_output_bitstream, reverse, frame_output_config, - combined_enabled_features, combined_disabled_features); + num_temporal_layers, num_spatial_layers, bitrate, save_output_bitstream, + reverse, frame_output_config, combined_enabled_features, + combined_disabled_features); } VideoEncoderTestEnvironment::VideoEncoderTestEnvironment( @@ -195,8 +201,7 @@ VideoCodecProfile profile, size_t num_temporal_layers, size_t num_spatial_layers, - uint32_t bitrate, - bool use_vbr, + const Bitrate& bitrate, bool save_output_bitstream, bool reverse, const FrameOutputConfig& frame_output_config, @@ -211,8 +216,7 @@ num_spatial_layers_(num_spatial_layers), bitrate_(AllocateDefaultBitrateForTesting(num_spatial_layers_, num_temporal_layers_, - bitrate, - use_vbr)), + bitrate)), spatial_layers_(GetDefaultSpatialLayers(bitrate_, video_.get(), num_spatial_layers_, @@ -254,7 +258,8 @@ return spatial_layers_; } -VideoBitrateAllocation VideoEncoderTestEnvironment::Bitrate() const { +const VideoBitrateAllocation& VideoEncoderTestEnvironment::BitrateAllocation() + const { return bitrate_; }
diff --git a/media/gpu/test/video_encoder/video_encoder_test_environment.h b/media/gpu/test/video_encoder/video_encoder_test_environment.h index 77ed7c63..6099d22 100644 --- a/media/gpu/test/video_encoder/video_encoder_test_environment.h +++ b/media/gpu/test/video_encoder/video_encoder_test_environment.h
@@ -21,6 +21,9 @@ } namespace media { + +class Bitrate; + namespace test { class Video; @@ -67,7 +70,7 @@ const std::vector<VideoEncodeAccelerator::Config::SpatialLayer>& SpatialLayers() const; // Get the target bitrate (bits/second). - VideoBitrateAllocation Bitrate() const; + const VideoBitrateAllocation& BitrateAllocation() const; // Whether the encoded bitstream is saved to disk. bool SaveOutputBitstream() const; // True if the video should play backwards at reaching the end of video. @@ -96,8 +99,7 @@ VideoCodecProfile profile, size_t num_temporal_layers, size_t num_spatial_layers, - uint32_t bitrate, - bool use_vbr, + const media::Bitrate& bitrate, bool save_output_bitstream, bool reverse, const FrameOutputConfig& frame_output_config,
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 8f07a9f1..478259a9 100644 --- a/media/gpu/vaapi/vp9_vaapi_video_encoder_delegate_unittest.cc +++ b/media/gpu/vaapi/vp9_vaapi_video_encoder_delegate_unittest.cc
@@ -344,7 +344,7 @@ auto initial_bitrate_allocation = AllocateDefaultBitrateForTesting( num_spatial_layers, num_temporal_layers, - kDefaultVideoEncodeAcceleratorConfig.bitrate.target_bps(), false); + kDefaultVideoEncodeAcceleratorConfig.bitrate); std::vector<gfx::Size> svc_layer_size = GetDefaultSpatialLayerResolutions(num_spatial_layers); if (num_spatial_layers > 1u || num_temporal_layers > 1u) { @@ -365,12 +365,12 @@ } } - EXPECT_CALL(*mock_rate_ctrl_, UpdateRateControl(MatchRtcConfigWithRates( - AllocateDefaultBitrateForTesting( - num_spatial_layers, num_temporal_layers, - config.bitrate.target_bps(), false), - VideoEncodeAccelerator::kDefaultFramerate, - num_temporal_layers, svc_layer_size))) + EXPECT_CALL(*mock_rate_ctrl_, + UpdateRateControl(MatchRtcConfigWithRates( + AllocateDefaultBitrateForTesting( + num_spatial_layers, num_temporal_layers, config.bitrate), + VideoEncodeAccelerator::kDefaultFramerate, + num_temporal_layers, svc_layer_size))) .Times(1) .WillOnce(Return()); @@ -496,7 +496,8 @@ uint8_t expected_temporal_layer_id, uint32_t bitrate, uint32_t framerate) { auto bitrate_allocation = AllocateDefaultBitrateForTesting( - num_spatial_layers, num_temporal_layers, bitrate, false); + num_spatial_layers, num_temporal_layers, + media::Bitrate::ConstantBitrate(bitrate)); UpdateRatesAndEncode(bitrate_allocation, framerate, /*valid_rates_request=*/true, is_key_pic, spatial_layer_resolutions, num_temporal_layers, @@ -627,7 +628,7 @@ const VideoBitrateAllocation kDefaultBitrateAllocation = AllocateDefaultBitrateForTesting( num_spatial_layers, num_temporal_layers, - kDefaultVideoEncodeAcceleratorConfig.bitrate.target_bps(), false); + kDefaultVideoEncodeAcceleratorConfig.bitrate); const std::vector<gfx::Size> kDefaultSpatialLayers = GetDefaultSpatialLayerResolutions(num_spatial_layers); const uint32_t kFramerate = @@ -657,7 +658,7 @@ const VideoBitrateAllocation kDefaultBitrateAllocation = AllocateDefaultBitrateForTesting( num_spatial_layers, num_temporal_layers, - kDefaultVideoEncodeAcceleratorConfig.bitrate.target_bps(), false); + kDefaultVideoEncodeAcceleratorConfig.bitrate); std::vector<VideoBitrateAllocation> invalid_bitrate_allocations; constexpr uint32_t kBitrate = 1234u; auto bitrate_allocation = kDefaultBitrateAllocation;
diff --git a/media/gpu/video_encode_accelerator_perf_tests.cc b/media/gpu/video_encode_accelerator_perf_tests.cc index 8095496..7323234 100644 --- a/media/gpu/video_encode_accelerator_perf_tests.cc +++ b/media/gpu/video_encode_accelerator_perf_tests.cc
@@ -512,7 +512,7 @@ bool measure_quality) { Video* video = g_env->GenerateNV12Video(); VideoCodecProfile profile = g_env->Profile(); - const media::VideoBitrateAllocation& bitrate = g_env->Bitrate(); + const media::VideoBitrateAllocation& bitrate = g_env->BitrateAllocation(); const std::vector<VideoEncodeAccelerator::Config::SpatialLayer>& spatial_layers = g_env->SpatialLayers(); std::vector<std::unique_ptr<BitstreamProcessor>> bitstream_processors; @@ -707,14 +707,15 @@ uint32_t target_bitrate = 0; uint32_t actual_bitrate = 0; if (!spatial_idx && !temporal_idx) { - target_bitrate = g_env->Bitrate().GetSumBps(); + target_bitrate = g_env->BitrateAllocation().GetSumBps(); actual_bitrate = stats.Bitrate(); } else { CHECK(spatial_idx && temporal_idx); // Target and actual bitrates in temporal layer encoding are the sum of // bitrates of the temporal layers in the spatial layer. for (size_t tid = 0; tid <= *temporal_idx; ++tid) { - target_bitrate += g_env->Bitrate().GetBitrateBps(*spatial_idx, tid); + target_bitrate += + g_env->BitrateAllocation().GetBitrateBps(*spatial_idx, tid); actual_bitrate += stats.LayerBitrate(*spatial_idx, tid); } }
diff --git a/media/gpu/video_encode_accelerator_tests.cc b/media/gpu/video_encode_accelerator_tests.cc index c8c21cb9..6208f28 100644 --- a/media/gpu/video_encode_accelerator_tests.cc +++ b/media/gpu/video_encode_accelerator_tests.cc
@@ -132,7 +132,7 @@ CHECK_LE(spatial_layers.size(), 1u); return VideoEncoderClientConfig(g_env->Video(), g_env->Profile(), - spatial_layers, g_env->Bitrate(), + spatial_layers, g_env->BitrateAllocation(), g_env->Reverse()); } @@ -498,11 +498,6 @@ GTEST_SKIP() << "Skip SHMEM input test cases in spatial SVC encoding"; auto config = GetDefaultConfig(); - const Bitrate::Mode bitrate_mode = config.bitrate_allocation.GetMode(); - if (bitrate_mode == Bitrate::Mode::kVariable) { - config.bitrate_allocation.SetPeakBps(config.bitrate_allocation.GetSumBps() * - 2); - } config.num_frames_to_encode = kNumFramesToEncodeForBitrateCheck; auto encoder = CreateVideoEncoder(g_env->Video(), config); // Set longer event timeout than the default (30 sec) because encoding 2160p @@ -517,9 +512,10 @@ EXPECT_TRUE(encoder->WaitForBitstreamProcessors()); // TODO(b/181797390): Reconsider bitrate check for VBR encoding if this fails // on some boards. - const double tolerance = bitrate_mode == Bitrate::Mode::kConstant - ? kBitrateTolerance - : kVariableBitrateTolerance; + const double tolerance = + config.bitrate_allocation.GetMode() == Bitrate::Mode::kConstant + ? kBitrateTolerance + : kVariableBitrateTolerance; EXPECT_NEAR(encoder->GetStats().Bitrate(), config.bitrate_allocation.GetSumBps(), tolerance * config.bitrate_allocation.GetSumBps()); @@ -528,7 +524,7 @@ TEST_F(VideoEncoderTest, BitrateCheck_DynamicBitrate) { if (g_env->SpatialLayers().size() > 1) GTEST_SKIP() << "Skip SHMEM input test cases in spatial SVC encoding"; - if (g_env->Bitrate().GetMode() != Bitrate::Mode::kConstant) { + if (g_env->BitrateAllocation().GetMode() != Bitrate::Mode::kConstant) { GTEST_SKIP() << "Skip Dynamic bitrate change checks for non-CBR bitrate mode"; } @@ -552,9 +548,9 @@ const uint32_t second_bitrate = first_bitrate * 3 / 2; encoder->ResetStats(); encoder->UpdateBitrate( - AllocateDefaultBitrateForTesting(config.num_spatial_layers, - config.num_temporal_layers, - second_bitrate, /*uses_vbr=*/false), + AllocateDefaultBitrateForTesting( + config.num_spatial_layers, config.num_temporal_layers, + Bitrate::ConstantBitrate(second_bitrate)), config.framerate); encoder->Encode(); EXPECT_TRUE(encoder->WaitForFlushDone()); @@ -569,7 +565,7 @@ TEST_F(VideoEncoderTest, BitrateCheck_DynamicFramerate) { if (g_env->SpatialLayers().size() > 1) GTEST_SKIP() << "Skip SHMEM input test cases in spatial SVC encoding"; - if (g_env->Bitrate().GetMode() != Bitrate::Mode::kConstant) { + if (g_env->BitrateAllocation().GetMode() != Bitrate::Mode::kConstant) { GTEST_SKIP() << "Skip dynamic framerate change checks for non-CBR bitrate mode"; } @@ -614,8 +610,8 @@ Video* nv12_video = g_env->GenerateNV12Video(); VideoEncoderClientConfig config(nv12_video, g_env->Profile(), - g_env->SpatialLayers(), g_env->Bitrate(), - g_env->Reverse()); + g_env->SpatialLayers(), + g_env->BitrateAllocation(), g_env->Reverse()); config.input_storage_type = VideoEncodeAccelerator::Config::StorageType::kGpuMemoryBuffer; @@ -652,7 +648,14 @@ auto* nv12_video = g_env->GenerateNV12Video(); // Set 1/4 of the original bitrate because the area of |output_resolution| is // 1/4 of the original resolution. - uint32_t new_bitrate = g_env->Bitrate().GetSumBps() / 4; + uint32_t new_target_bitrate = g_env->BitrateAllocation().GetSumBps() / 4; + // TODO(b/181797390): Reconsider if this peak bitrate is reasonable. + const Bitrate new_bitrate = + g_env->BitrateAllocation().GetMode() == Bitrate::Mode::kConstant + ? Bitrate::ConstantBitrate(new_target_bitrate) + : Bitrate::VariableBitrate(new_target_bitrate, + new_target_bitrate * 2); + auto spatial_layers = g_env->SpatialLayers(); size_t num_temporal_layers = 1u; if (!spatial_layers.empty()) { @@ -662,12 +665,10 @@ spatial_layers[0].bitrate_bps /= 4; num_temporal_layers = spatial_layers[0].num_of_temporal_layers; } - bool uses_vbr = g_env->Bitrate().GetMode() == Bitrate::Mode::kVariable; VideoEncoderClientConfig config( nv12_video, g_env->Profile(), spatial_layers, AllocateDefaultBitrateForTesting(/*num_spatial_layers=*/1u, - num_temporal_layers, new_bitrate, - uses_vbr), + num_temporal_layers, new_bitrate), g_env->Reverse()); config.output_resolution = output_resolution; config.input_storage_type = @@ -709,8 +710,8 @@ expanded_resolution, expanded_visible_rect); ASSERT_TRUE(nv12_expanded_video); VideoEncoderClientConfig config(nv12_expanded_video.get(), g_env->Profile(), - g_env->SpatialLayers(), g_env->Bitrate(), - g_env->Reverse()); + g_env->SpatialLayers(), + g_env->BitrateAllocation(), g_env->Reverse()); config.output_resolution = original_resolution; config.input_storage_type = VideoEncodeAccelerator::Config::StorageType::kGpuMemoryBuffer; @@ -751,8 +752,8 @@ expanded_resolution, expanded_visible_rect); ASSERT_TRUE(nv12_expanded_video); VideoEncoderClientConfig config(nv12_expanded_video.get(), g_env->Profile(), - g_env->SpatialLayers(), g_env->Bitrate(), - g_env->Reverse()); + g_env->SpatialLayers(), + g_env->BitrateAllocation(), g_env->Reverse()); config.output_resolution = original_resolution; config.input_storage_type = VideoEncodeAccelerator::Config::StorageType::kGpuMemoryBuffer; @@ -785,7 +786,7 @@ return bitrate_allocation; }; - const auto& default_allocation = g_env->Bitrate(); + const auto& default_allocation = g_env->BitrateAllocation(); std::vector<VideoBitrateAllocation> bitrate_allocations; // Deactivate the top layer. @@ -812,8 +813,8 @@ bitrate_allocations.emplace_back(bitrate_allocation); VideoEncoderClientConfig config(nv12_video, g_env->Profile(), - g_env->SpatialLayers(), g_env->Bitrate(), - g_env->Reverse()); + g_env->SpatialLayers(), + g_env->BitrateAllocation(), g_env->Reverse()); config.input_storage_type = VideoEncodeAccelerator::Config::StorageType::kGpuMemoryBuffer; std::vector<size_t> num_frames_to_encode(bitrate_allocations.size());
diff --git a/media/gpu/windows/dxva_video_decode_accelerator_win.cc b/media/gpu/windows/dxva_video_decode_accelerator_win.cc index 88c4996..622686b1 100644 --- a/media/gpu/windows/dxva_video_decode_accelerator_win.cc +++ b/media/gpu/windows/dxva_video_decode_accelerator_win.cc
@@ -1554,11 +1554,11 @@ RETURN_ON_HR_FAILURE(hr, "Failed to pass D3D manager to decoder", false); } - gl::GLDisplayEGL* display = gl::GLSurfaceEGL::GetGLDisplayEGL(); - if (!display->ext->b_EGL_EXT_pixel_format_float) + if (!gl::GLSurfaceEGL::GetGLDisplayEGL()->IsPixelFormatFloatSupported()) use_fp16_ = false; - EGLDisplay egl_display = display->GetHardwareDisplay(); + EGLDisplay egl_display = + gl::GLSurfaceEGL::GetGLDisplayEGL()->GetHardwareDisplay(); while (true) { std::vector<EGLint> config_attribs = {EGL_BUFFER_SIZE, 32,
diff --git a/media/mojo/mojom/media_types.mojom b/media/mojo/mojom/media_types.mojom index ba8b55be..77dab2c7 100644 --- a/media/mojo/mojom/media_types.mojom +++ b/media/mojo/mojom/media_types.mojom
@@ -287,6 +287,8 @@ gfx.mojom.Rect? capture_update_rect; + gfx.mojom.Size? source_size; + gfx.mojom.Rect? region_capture_rect; uint32 crop_version;
diff --git a/media/mojo/mojom/video_frame_metadata_mojom_traits.cc b/media/mojo/mojom/video_frame_metadata_mojom_traits.cc index c8417a4b..c325ce7 100644 --- a/media/mojo/mojom/video_frame_metadata_mojom_traits.cc +++ b/media/mojo/mojom/video_frame_metadata_mojom_traits.cc
@@ -63,6 +63,7 @@ READ_AND_ASSIGN_OPT(base::UnguessableToken, overlay_plane_id, OverlayPlaneId); + READ_AND_ASSIGN_OPT(gfx::Size, source_size, SourceSize); READ_AND_ASSIGN_OPT(gfx::Rect, capture_update_rect, CaptureUpdateRect); READ_AND_ASSIGN_OPT(gfx::Rect, region_capture_rect, RegionCaptureRect); @@ -81,4 +82,4 @@ return true; } -} // namespace mojo \ No newline at end of file +} // namespace mojo
diff --git a/media/mojo/mojom/video_frame_metadata_mojom_traits.h b/media/mojo/mojom/video_frame_metadata_mojom_traits.h index 1ce7fbd2..3f8ac38 100644 --- a/media/mojo/mojom/video_frame_metadata_mojom_traits.h +++ b/media/mojo/mojom/video_frame_metadata_mojom_traits.h
@@ -104,6 +104,11 @@ return input.capture_update_rect; } + static const absl::optional<gfx::Size>& source_size( + const media::VideoFrameMetadata& input) { + return input.source_size; + } + static const absl::optional<gfx::Rect>& region_capture_rect( const media::VideoFrameMetadata& input) { return input.region_capture_rect;
diff --git a/media/webrtc/audio_processor.cc b/media/webrtc/audio_processor.cc index 586fea2..17e440b 100644 --- a/media/webrtc/audio_processor.cc +++ b/media/webrtc/audio_processor.cc
@@ -30,7 +30,7 @@ #include "media/webrtc/helpers.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/webrtc/modules/audio_processing/include/audio_processing.h" -#include "third_party/webrtc_overrides/task_queue_factory.h" +#include "third_party/webrtc_overrides/metronome_task_queue_factory.h" namespace media {
diff --git a/net/cert/internal/cert_issuer_source_static.cc b/net/cert/internal/cert_issuer_source_static.cc index e6ddb27..592b7cca 100644 --- a/net/cert/internal/cert_issuer_source_static.cc +++ b/net/cert/internal/cert_issuer_source_static.cc
@@ -14,6 +14,10 @@ cert->normalized_subject().AsStringPiece(), std::move(cert))); } +void CertIssuerSourceStatic::Clear() { + intermediates_.clear(); +} + void CertIssuerSourceStatic::SyncGetIssuersOf(const ParsedCertificate* cert, ParsedCertificateList* issuers) { auto range =
diff --git a/net/cert/internal/cert_issuer_source_static.h b/net/cert/internal/cert_issuer_source_static.h index 39d3187..1dfd3a0 100644 --- a/net/cert/internal/cert_issuer_source_static.h +++ b/net/cert/internal/cert_issuer_source_static.h
@@ -27,6 +27,9 @@ // provide. void AddCert(scoped_refptr<ParsedCertificate> cert); + // Clears the set of certificates. + void Clear(); + // CertIssuerSource implementation: void SyncGetIssuersOf(const ParsedCertificate* cert, ParsedCertificateList* issuers) override;
diff --git a/net/cert/internal/system_trust_store.cc b/net/cert/internal/system_trust_store.cc index a665c3b..5124a6e 100644 --- a/net/cert/internal/system_trust_store.cc +++ b/net/cert/internal/system_trust_store.cc
@@ -217,6 +217,8 @@ TrustStoreMac::TrustImplType ParamToTrustImplType( int param, TrustStoreMac::TrustImplType default_impl) { + // These values are used in experiment configs, do not change or reuse the + // numbers. switch (param) { case 1: return TrustStoreMac::TrustImplType::kDomainCache; @@ -224,6 +226,8 @@ return TrustStoreMac::TrustImplType::kSimple; case 3: return TrustStoreMac::TrustImplType::kLruCache; + case 4: + return TrustStoreMac::TrustImplType::kDomainCacheFullCerts; default: return default_impl; } @@ -310,7 +314,7 @@ TrustStoreMac* GetGlobalTrustStoreMacForCRS() { constexpr TrustStoreMac::TrustImplType kDefaultMacTrustImplForCRS = - TrustStoreMac::TrustImplType::kDomainCache; + TrustStoreMac::TrustImplType::kDomainCacheFullCerts; static base::NoDestructor<TrustStoreMac> static_trust_store_mac( kSecPolicyAppleSSL, GetTrustStoreImplParam(kDefaultMacTrustImplForCRS), GetTrustStoreCacheSize(), TrustStoreMac::TrustDomains::kUserAndAdmin);
diff --git a/net/cert/internal/trust_store_mac.cc b/net/cert/internal/trust_store_mac.cc index 5a179e71..26950081 100644 --- a/net/cert/internal/trust_store_mac.cc +++ b/net/cert/internal/trust_store_mac.cc
@@ -14,12 +14,15 @@ #include "base/logging.h" #include "base/mac/foundation_util.h" #include "base/mac/mac_logging.h" +#include "base/metrics/histogram_functions.h" #include "base/no_destructor.h" +#include "base/strings/strcat.h" #include "base/synchronization/lock.h" #include "crypto/mac_security_services_lock.h" #include "net/base/hash_value.h" #include "net/base/network_notification_thread_mac.h" #include "net/cert/internal/cert_errors.h" +#include "net/cert/internal/cert_issuer_source_static.h" #include "net/cert/internal/parse_name.h" #include "net/cert/internal/parsed_certificate.h" #include "net/cert/known_roots_mac.h" @@ -447,6 +450,139 @@ base::flat_map<SHA256HashValue, TrustStatusDetails> trust_status_cache_; }; +// Caches certificates and calculated trust status for certificates present in +// a single trust domain. +class TrustDomainCacheFullCerts { + public: + struct TrustStatusDetails { + TrustStatus trust_status = TrustStatus::UNKNOWN; + int debug_info = 0; + }; + + TrustDomainCacheFullCerts(SecTrustSettingsDomain domain, + CFStringRef policy_oid) + : domain_(domain), policy_oid_(policy_oid) { + DCHECK(policy_oid_); + } + + TrustDomainCacheFullCerts(const TrustDomainCacheFullCerts&) = delete; + TrustDomainCacheFullCerts& operator=(const TrustDomainCacheFullCerts&) = + delete; + + // (Re-)Initializes the cache with the certs in |domain_| set to UNKNOWN trust + // status. + void Initialize() { + trust_status_cache_.clear(); + cert_issuer_source_.Clear(); + + base::ScopedCFTypeRef<CFArrayRef> cert_array; + OSStatus rv; + { + base::AutoLock lock(crypto::GetMacSecurityServicesLock()); + rv = SecTrustSettingsCopyCertificates(domain_, + cert_array.InitializeInto()); + } + if (rv != noErr) { + // Note: SecTrustSettingsCopyCertificates can legitimately return + // errSecNoTrustSettings if there are no trust settings in |domain_|. + HistogramTrustDomainCertCount(0U); + return; + } + std::vector<std::pair<SHA256HashValue, TrustStatusDetails>> + trust_status_vector; + for (CFIndex i = 0, size = CFArrayGetCount(cert_array); i < size; ++i) { + SecCertificateRef cert = reinterpret_cast<SecCertificateRef>( + const_cast<void*>(CFArrayGetValueAtIndex(cert_array, i))); + base::ScopedCFTypeRef<CFDataRef> der_data(SecCertificateCopyData(cert)); + if (!der_data) { + LOG(ERROR) << "SecCertificateCopyData error"; + continue; + } + auto buffer = x509_util::CreateCryptoBuffer(base::make_span( + CFDataGetBytePtr(der_data.get()), CFDataGetLength(der_data.get()))); + CertErrors errors; + ParseCertificateOptions options; + options.allow_invalid_serial_numbers = true; + scoped_refptr<ParsedCertificate> parsed_cert = + ParsedCertificate::Create(std::move(buffer), options, &errors); + if (!parsed_cert) { + LOG(ERROR) << "Error parsing certificate:\n" << errors.ToDebugString(); + continue; + } + cert_issuer_source_.AddCert(parsed_cert); + trust_status_vector.emplace_back(x509_util::CalculateFingerprint256(cert), + TrustStatusDetails()); + } + HistogramTrustDomainCertCount(trust_status_vector.size()); + trust_status_cache_ = base::flat_map<SHA256HashValue, TrustStatusDetails>( + std::move(trust_status_vector)); + } + + // Returns the trust status for |cert| in |domain_|. + TrustStatus IsCertTrusted(const ParsedCertificate* cert, + const SHA256HashValue& cert_hash, + base::SupportsUserData* debug_data) { + auto cache_iter = trust_status_cache_.find(cert_hash); + if (cache_iter == trust_status_cache_.end()) { + // Cert does not have trust settings in this domain, return UNSPECIFIED. + UpdateUserData(0, debug_data, + TrustStoreMac::TrustImplType::kDomainCacheFullCerts); + return TrustStatus::UNSPECIFIED; + } + + if (cache_iter->second.trust_status != TrustStatus::UNKNOWN) { + // Cert has trust settings and trust has already been calculated, return + // the cached value. + UpdateUserData(cache_iter->second.debug_info, debug_data, + TrustStoreMac::TrustImplType::kDomainCacheFullCerts); + return cache_iter->second.trust_status; + } + + // Cert has trust settings but trust has not been calculated yet. + // Calculate it now, insert into cache, and return. + TrustStatus cert_trust = IsCertificateTrustedForPolicyInDomain( + cert, policy_oid_, domain_, &cache_iter->second.debug_info); + cache_iter->second.trust_status = cert_trust; + UpdateUserData(cache_iter->second.debug_info, debug_data, + TrustStoreMac::TrustImplType::kDomainCacheFullCerts); + return cert_trust; + } + + // Returns true if the certificate with |cert_hash| is present in |domain_|. + bool ContainsCert(const SHA256HashValue& cert_hash) const { + return trust_status_cache_.find(cert_hash) != trust_status_cache_.end(); + } + + // Returns a CertIssuerSource containing all the certificates that are + // present in |domain_|. + CertIssuerSource& cert_issuer_source() { return cert_issuer_source_; } + + private: + void HistogramTrustDomainCertCount(size_t count) const { + base::StringPiece domain_name; + switch (domain_) { + case kSecTrustSettingsDomainUser: + domain_name = "User"; + break; + case kSecTrustSettingsDomainAdmin: + domain_name = "Admin"; + break; + case kSecTrustSettingsDomainSystem: + domain_name = "System"; + break; + } + base::UmaHistogramCounts1000( + base::StrCat( + {"Net.CertVerifier.MacTrustDomainCertCount.", domain_name}), + count); + } + + const SecTrustSettingsDomain domain_; + const CFStringRef policy_oid_; + base::flat_map<SHA256HashValue, TrustStatusDetails> trust_status_cache_; + CertIssuerSourceStatic cert_issuer_source_; +}; + SHA256HashValue CalculateFingerprint256(const der::Input& buffer) { SHA256HashValue sha256; SHA256(buffer.UnsafeData(), buffer.Length(), sha256.data); @@ -592,6 +728,9 @@ virtual bool IsKnownRoot(const ParsedCertificate* cert) = 0; virtual TrustStatus IsCertTrusted(const ParsedCertificate* cert, base::SupportsUserData* debug_data) = 0; + virtual bool ImplementsSyncGetIssuersOf() const { return false; } + virtual void SyncGetIssuersOf(const ParsedCertificate* cert, + ParsedCertificateList* issuers) {} virtual void InitializeTrustCache() = 0; }; @@ -699,6 +838,128 @@ TrustDomainCache user_domain_cache_ GUARDED_BY(cache_lock_); }; +// TrustImplDomainCacheFullCerts uses SecTrustSettingsCopyCertificates to get +// the list of certs in each trust domain and caches the full certificates so +// that pathbuilding does not need to touch any Mac APIs unless one of those +// certificates is encountered, at which point the calculated trust status of +// that cert is cached. The cache is reset if trust settings are modified. +class TrustStoreMac::TrustImplDomainCacheFullCerts + : public TrustStoreMac::TrustImpl { + public: + explicit TrustImplDomainCacheFullCerts(CFStringRef policy_oid, + TrustDomains domains) + : use_system_domain_cache_(domains == TrustDomains::kAll), + admin_domain_cache_(kSecTrustSettingsDomainAdmin, policy_oid), + user_domain_cache_(kSecTrustSettingsDomainUser, policy_oid) { + if (use_system_domain_cache_) { + system_domain_cache_ = std::make_unique<TrustDomainCacheFullCerts>( + kSecTrustSettingsDomainSystem, policy_oid); + } + keychain_observer_ = std::make_unique<KeychainTrustObserver>(); + } + + TrustImplDomainCacheFullCerts(const TrustImplDomainCacheFullCerts&) = delete; + TrustImplDomainCacheFullCerts& operator=( + const TrustImplDomainCacheFullCerts&) = delete; + + ~TrustImplDomainCacheFullCerts() override { + GetNetworkNotificationThreadMac()->DeleteSoon( + FROM_HERE, std::move(keychain_observer_)); + } + + // Returns true if |cert| is present in kSecTrustSettingsDomainSystem. + bool IsKnownRoot(const ParsedCertificate* cert) override { + if (!use_system_domain_cache_) + return false; + SHA256HashValue cert_hash = CalculateFingerprint256(cert->der_cert()); + + base::AutoLock lock(cache_lock_); + MaybeInitializeCache(); + return system_domain_cache_->ContainsCert(cert_hash); + } + + // Returns the trust status for |cert|. + TrustStatus IsCertTrusted(const ParsedCertificate* cert, + base::SupportsUserData* debug_data) override { + SHA256HashValue cert_hash = CalculateFingerprint256(cert->der_cert()); + + base::AutoLock lock(cache_lock_); + MaybeInitializeCache(); + + // Evaluate trust domains in user, admin, system order. Admin settings can + // override system ones, and user settings can override both admin and + // system. + for (TrustDomainCacheFullCerts* trust_domain_cache : + {&user_domain_cache_, &admin_domain_cache_}) { + TrustStatus ts = + trust_domain_cache->IsCertTrusted(cert, cert_hash, debug_data); + if (ts != TrustStatus::UNSPECIFIED) + return ts; + } + if (use_system_domain_cache_) { + return system_domain_cache_->IsCertTrusted(cert, cert_hash, debug_data); + } + + // Cert did not have trust settings in any domain. + return TrustStatus::UNSPECIFIED; + } + + bool ImplementsSyncGetIssuersOf() const override { return true; } + + void SyncGetIssuersOf(const ParsedCertificate* cert, + ParsedCertificateList* issuers) override { + base::AutoLock lock(cache_lock_); + MaybeInitializeCache(); + user_domain_cache_.cert_issuer_source().SyncGetIssuersOf(cert, issuers); + admin_domain_cache_.cert_issuer_source().SyncGetIssuersOf(cert, issuers); + if (system_domain_cache_) { + system_domain_cache_->cert_issuer_source().SyncGetIssuersOf(cert, + issuers); + } + } + + // Initializes the cache, if it isn't already initialized. + void InitializeTrustCache() override { + base::AutoLock lock(cache_lock_); + MaybeInitializeCache(); + } + + private: + // (Re-)Initialize the cache if necessary. Must be called after acquiring + // |cache_lock_| and before accessing any of the |*_domain_cache_| members. + void MaybeInitializeCache() EXCLUSIVE_LOCKS_REQUIRED(cache_lock_) { + cache_lock_.AssertAcquired(); + int64_t keychain_iteration = keychain_observer_->Iteration(); + if (iteration_ == keychain_iteration) + return; + + iteration_ = keychain_iteration; + user_domain_cache_.Initialize(); + admin_domain_cache_.Initialize(); + if (use_system_domain_cache_ && !system_domain_initialized_) { + // In practice, the system trust domain does not change during runtime, + // and SecTrustSettingsCopyCertificates on the system domain is quite + // slow, so the system domain cache is not reset on keychain changes. + system_domain_cache_->Initialize(); + system_domain_initialized_ = true; + } + } + + std::unique_ptr<KeychainTrustObserver> keychain_observer_; + // Store whether to use the system domain in a const bool that is initialized + // in constructor so it is safe to read without having to lock first. + const bool use_system_domain_cache_; + + base::Lock cache_lock_; + // |cache_lock_| must be held while accessing any following members. + int64_t iteration_ GUARDED_BY(cache_lock_) = -1; + bool system_domain_initialized_ GUARDED_BY(cache_lock_) = false; + std::unique_ptr<TrustDomainCacheFullCerts> system_domain_cache_ + GUARDED_BY(cache_lock_); + TrustDomainCacheFullCerts admin_domain_cache_ GUARDED_BY(cache_lock_); + TrustDomainCacheFullCerts user_domain_cache_ GUARDED_BY(cache_lock_); +}; + // TrustImplNoCache is the simplest approach which calls // SecTrustSettingsCopyTrustSettings on every cert checked, with no caching. class TrustStoreMac::TrustImplNoCache : public TrustStoreMac::TrustImpl { @@ -906,6 +1167,10 @@ trust_cache_ = std::make_unique<TrustImplLRUCache>(policy_oid, cache_size, domains); break; + case TrustImplType::kDomainCacheFullCerts: + trust_cache_ = + std::make_unique<TrustImplDomainCacheFullCerts>(policy_oid, domains); + break; } } @@ -921,6 +1186,11 @@ void TrustStoreMac::SyncGetIssuersOf(const ParsedCertificate* cert, ParsedCertificateList* issuers) { + if (trust_cache_->ImplementsSyncGetIssuersOf()) { + trust_cache_->SyncGetIssuersOf(cert, issuers); + return; + } + base::ScopedCFTypeRef<CFDataRef> name_data = GetMacNormalizedIssuer(cert); if (!name_data) return;
diff --git a/net/cert/internal/trust_store_mac.h b/net/cert/internal/trust_store_mac.h index 693cb122..971173aa 100644 --- a/net/cert/internal/trust_store_mac.h +++ b/net/cert/internal/trust_store_mac.h
@@ -74,11 +74,14 @@ COPY_TRUST_SETTINGS_ERROR = 1 << 11, }; + // NOTE: When updating this enum, also update ParamToTrustImplType in + // system_trust_store.cc enum class TrustImplType { kUnknown = 0, kDomainCache = 1, kSimple = 2, kLruCache = 3, + kDomainCacheFullCerts = 4, }; enum class TrustDomains { @@ -148,6 +151,7 @@ private: class TrustImpl; class TrustImplDomainCache; + class TrustImplDomainCacheFullCerts; class TrustImplNoCache; class TrustImplLRUCache;
diff --git a/net/cert/internal/trust_store_mac_unittest.cc b/net/cert/internal/trust_store_mac_unittest.cc index 1d5ab31..2ac15591 100644 --- a/net/cert/internal/trust_store_mac_unittest.cc +++ b/net/cert/internal/trust_store_mac_unittest.cc
@@ -16,6 +16,7 @@ #include "base/strings/string_number_conversions.h" #include "base/strings/string_split.h" #include "base/synchronization/lock.h" +#include "base/test/metrics/histogram_tester.h" #include "crypto/mac_security_services_lock.h" #include "crypto/sha2.h" #include "net/cert/internal/cert_errors.h" @@ -282,6 +283,8 @@ const TrustStoreMac::TrustImplType trust_impl = std::get<0>(GetParam()); const IsKnownRootTestOrder is_known_root_test_order = std::get<1>(GetParam()); const TrustStoreMac::TrustDomains trust_domains = std::get<2>(GetParam()); + + base::HistogramTester histogram_tester; TrustStoreMac trust_store(kSecPolicyAppleX509Basic, trust_impl, kDefaultCacheSize, trust_domains); @@ -402,6 +405,20 @@ trust_debug_data2->combined_trust_debug_info()); EXPECT_EQ(trust_debug_data->trust_impl(), trust_debug_data2->trust_impl()); } + + if (trust_impl == TrustStoreMac::TrustImplType::kDomainCacheFullCerts) { + // Since this is testing the actual platform trust settings, we don't know + // what values the histogram should be for each domain, so just verify that + // the histogram is recorded (or not) depending on the requested trust + // domains. + histogram_tester.ExpectTotalCount( + "Net.CertVerifier.MacTrustDomainCertCount.User", 1); + histogram_tester.ExpectTotalCount( + "Net.CertVerifier.MacTrustDomainCertCount.Admin", 1); + histogram_tester.ExpectTotalCount( + "Net.CertVerifier.MacTrustDomainCertCount.System", + (trust_domains == TrustStoreMac::TrustDomains::kAll) ? 1 : 0); + } } INSTANTIATE_TEST_SUITE_P( @@ -410,7 +427,8 @@ testing::Combine( testing::Values(TrustStoreMac::TrustImplType::kDomainCache, TrustStoreMac::TrustImplType::kSimple, - TrustStoreMac::TrustImplType::kLruCache), + TrustStoreMac::TrustImplType::kLruCache, + TrustStoreMac::TrustImplType::kDomainCacheFullCerts), // Some TrustImpls may calculate/cache IsKnownRoot values and trust // values independently, so test with calling IsKnownRoot both before // and after GetTrust to try to ensure there is no ordering issue with
diff --git a/remoting/protocol/webrtc_transport.cc b/remoting/protocol/webrtc_transport.cc index 2760bc0c..348f68b 100644 --- a/remoting/protocol/webrtc_transport.cc +++ b/remoting/protocol/webrtc_transport.cc
@@ -44,7 +44,7 @@ #include "third_party/webrtc/api/video_codecs/builtin_video_decoder_factory.h" #include "third_party/webrtc/media/engine/webrtc_media_engine.h" #include "third_party/webrtc/modules/audio_processing/include/audio_processing.h" -#include "third_party/webrtc_overrides/task_queue_factory.h" +#include "third_party/webrtc_overrides/metronome_task_queue_factory.h" using jingle_xmpp::QName; using jingle_xmpp::XmlElement; @@ -278,7 +278,7 @@ pcf_deps.network_thread = worker_thread; pcf_deps.worker_thread = worker_thread; pcf_deps.signaling_thread = rtc::Thread::Current(); - pcf_deps.task_queue_factory = CreateWebRtcTaskQueueFactory(); + pcf_deps.task_queue_factory = CreateWebRtcMetronomeTaskQueueFactory(); pcf_deps.call_factory = webrtc::CreateCallFactory(); pcf_deps.event_log_factory = std::make_unique<webrtc::RtcEventLogFactory>( pcf_deps.task_queue_factory.get());
diff --git a/services/cert_verifier/public/mojom/trial_comparison_cert_verifier.mojom b/services/cert_verifier/public/mojom/trial_comparison_cert_verifier.mojom index 5e92388c..8461107 100644 --- a/services/cert_verifier/public/mojom/trial_comparison_cert_verifier.mojom +++ b/services/cert_verifier/public/mojom/trial_comparison_cert_verifier.mojom
@@ -71,6 +71,7 @@ kDomainCache = 1, kSimple = 2, kLruCache = 3, + kDomainCacheFullCerts = 4, }; [EnableIf=is_mac] MacTrustImplType mac_trust_impl;
diff --git a/services/cert_verifier/trial_comparison_cert_verifier_mojo.cc b/services/cert_verifier/trial_comparison_cert_verifier_mojo.cc index aba886e8..d75a2461 100644 --- a/services/cert_verifier/trial_comparison_cert_verifier_mojo.cc +++ b/services/cert_verifier/trial_comparison_cert_verifier_mojo.cc
@@ -41,6 +41,9 @@ case net::TrustStoreMac::TrustImplType::kLruCache: return cert_verifier::mojom::CertVerifierDebugInfo::MacTrustImplType:: kLruCache; + case net::TrustStoreMac::TrustImplType::kDomainCacheFullCerts: + return cert_verifier::mojom::CertVerifierDebugInfo::MacTrustImplType:: + kDomainCacheFullCerts; } } #endif
diff --git a/services/device/generic_sensor/README.md b/services/device/generic_sensor/README.md index a15397c..3674c23 100644 --- a/services/device/generic_sensor/README.md +++ b/services/device/generic_sensor/README.md
@@ -1,160 +1,630 @@ # Sensors -`services/device/generic_sensor` contains the platform-specific parts of the Sensor APIs -implementation. +[TOC] -Sensors Mojo interfaces are defined in the `services/device/public/mojom` subdirectory. +## Introduction -## Web-exposed Interfaces +This document explains how sensor APIs (such as Ambient Light Sensor, +Accelerometer, Gyroscope, Magnetometer) are implemented in Chromium. -### [Generic Sensors](https://www.w3.org/TR/generic-sensor/) +This directory contains the platform-specific parts of the +implementation, which is used, among others, by the [Generic Sensor +API](https://w3c.github.io/sensors/) and the [Device Orientation +API](https://w3c.github.io/deviceorientation/). -The Generic Sensors API is implemented in `third_party/blink/renderer/modules/sensor` and exposes the following sensor types as JavaScript objects: +The document describes the Generic Sensor API implementation in both +the renderer and the browser process and lists important +implementation details, such as how data from a single platform sensor +is distributed among multiple JavaScript sensor instances and how +sensor configurations are managed. -* [AbsoluteOrientationSensor] → ABSOLUTE_ORIENTATION_QUATERNION -* [Accelerometer] → ACCELEROMETER -* [AmbientLightSensor] → AMBIENT_LIGHT -* [GravitySensor] → GRAVITY -* [Gyroscope] → GYROSCOPE -* [LinearAccelerationSensor] → LINEAR_ACCELEROMETER -* [Magnetometer] → MAGNETOMETER -* [RelativeOrientationSensor] → RELATIVE_ORIENTATION_QUATERNION +## Background -[AbsoluteOrientationSensor]: ../../../third_party/blink/renderer/modules/sensor/absolute_orientation_sensor.idl -[Accelerometer]: ../../../third_party/blink/renderer/modules/sensor/accelerometer.idl -[AmbientLightSensor]: ../../../third_party/blink/renderer/modules/sensor/ambient_light_sensor.idl -[GravitySensor]: ../../../third_party/blink/renderer/modules/sensor/gravity_sensor.idl -[Gyroscope]: ../../../third_party/blink/renderer/modules/sensor/gyroscope.idl -[LinearAccelerationSensor]: ../../../third_party/blink/renderer/modules/sensor/linear_acceleration_sensor.idl -[Magnetometer]: ../../../third_party/blink/renderer/modules/sensor/magnetometer.idl -[RelativeOrientationSensor]: ../../../third_party/blink/renderer/modules/sensor/relative_orientation_sensor.idl +The Generic Sensor API defines base interfaces that should be implemented by +concrete sensors. In most cases, concrete sensors should only define +sensor-specific data structures and, if required, sensor configuration options. -### [DeviceOrientation Events](https://www.w3.org/TR/orientation-event/) +The same approach is applied to the implementation in Chromium, which was +designed with the following requirements in mind: -The DeviceOrientation Events API is implemented in `third_party/blink/renderer/modules/device_orientation` and exposes two events based on the following sensors: +1. Share the crucial parts of functionality between the concrete sensor + implementations. Avoid the code duplication and thus simplify maintenance and + development of new features. +1. Support simultaneous existence and functioning of multiple JS Sensor + instances of the same type that can have different configurations and + lifetimes. +1. Support for both “slow” sensors that provide periodic updates (e.g. + Ambient Light, Proximity), and “fast” streaming sensors that have low-latency + requirements for sensor reading updates (motion sensors). -* [DeviceMotionEvent] - * ACCELEROMETER: populates the `accelerationIncludingGravity` field - * LINEAR_ACCELEROMETER: populates the `acceleration` field - * GRAVITY: populates the `gravity` field - * GYROSCOPE: populates the `rotationRate` field -* [DeviceOrientationEvent] - * ABSOLUTE_ORIENTATION_EULER_ANGLES (when a listener for the `'deviceorientationabsolute'` event is added) - * RELATIVE_ORIENTATION_EULER_ANGLES (when a listener for the `'deviceorientation'` event is added) +**Note**: the implementation is architected in such a way that Blink (i.e. +`third_party/blink/renderer/modules/sensor`) is just a consumer of the data from +`services/device/generic_sensor` like any other. For example, the Blink [Device +Orientation API](/third_party/blink/renderer/modules/device_orientation/) +consumes sensor data from `//services` independently from the Blink Generic +Sensor implementation. The same applies to +[`device/vr/orientation`](/device/vr/orientation). -[DeviceMotionEvent]: ../../../third_party/blink/renderer/modules/device_orientation/device_motion_event.idl -[DeviceOrientationEvent]: ../../../third_party/blink/renderer/modules/device_orientation/device_orientation_event.idl +## Implementation Design -The content renderer layer is located in `third_party/blink/renderer/modules/device_orientation`. +### Main components and APIs -Testing: +The Generic Sensor API implementation consists of two main components: the +`sensor` module in Blink +([//third_party/blink/renderer/modules/sensor/](/third_party/blink/renderer/modules/sensor/)) +which contains JS bindings for Generic Sensor API and concrete sensors APIs, and +the `generic_sensor` device service +([//services/device/generic_sensor/](/services/device/generic_sensor/)) \- a set +of classes running on the service process side that eventually call system APIs +to access the actual device sensor data. -* Browser tests are located in `content/browser/device_sensors`. -* Layout tests are located in `third_party/WebKit/LayoutTests/device_orientation`. -* Web platform tests are located in `third_party/WebKit/LayoutTests/external/wpt/orientation-event` and are a mirror of the [web-platform-tests GitHub repository](https://github.com/web-platform-tests/wpt). +The `//services` side also includes a few other directories: -## Permissions +* `//services/device/public/cpp/generic_sensor` contains C++ classes and data + structures used by both `//services/device/generic_sensor` as well as its + consumers. +* `//services/device/public/mojom` contains Mojo interfaces by the Generic + Sensor implementation. + * [SensorProvider](/services/device/public/mojom/sensor_provider.mojom) is + a “factory-like” interface that provides data about the sensors present + on the device and their capabilities (reporting mode, maximum sampling + frequency), and allows users to request a specific sensor. + * [Sensor](/services/device/public/mojom/sensor.mojom) is an interface + wrapping a concrete device sensor. + * [SensorClient](/services/device/public/mojom/sensor.mojom) is + implemented by Blink (and other consumers) to be notified about errors + occurred on platform side and about sensor reading updates for sensors + with ‘onchange’ reporting mode. -The device service provides no support for permission checks. When the render process requests access to a sensor type this request is proxied through the browser process by [SensorProviderProxyImpl] which is responsible for checking the permissions granted to the requesting origin. +Actual sensor data is not passed to consumers (such as Blink) via Mojo +calls \- a shared memory buffer is used instead, thus we avoid filling up the +Mojo IPC channel with sensor data (for sensors with continuous reporting mode) when +the platform sensor has a high sampling frequency, and also avoid adding extra +latency. -[SensorProviderProxyImpl]: ../../../content/browser/generic_sensor/sensor_provider_proxy_impl.h +A high-level diagram of the Mojo architecture looks like this: -## Platform Support + -Support for the SensorTypes defined by the Mojo interface is summarized in this -table. An empty cell indicates that the sensor type is not supported on that -platform. +#### Sensor Fusion -| SensorType | Android | Linux and ChromeOS | macOS | Windows | -| --------------------------------- | ------------------------- | ------------------------------------- | ------------------------------------- | ----------------------------------------- | -| AMBIENT_LIGHT | TYPE_LIGHT | in_illuminance | AppleLMUController | Yes | -| PROXIMITY | | | | | -| ACCELEROMETER | TYPE_ACCELEROMETER | in_accel | SMCMotionSensor | Yes | -| LINEAR_ACCELEROMETER | See below | ACCELEROMETER (*) | | ACCELEROMETER (*) | -| GRAVITY | See below | ACCELEROMETER (*) | | ACCELEROMETER (*) | -| GYROSCOPE | TYPE_GYROSCOPE | in_anglvel | | Yes | -| MAGNETOMETER | TYPE_MAGNETIC_FIELD | in_magn | | Yes | -| PRESSURE | | | | | -| ABSOLUTE_ORIENTATION_EULER_ANGLES | See below | ACCELEROMETER and MAGNETOMETER (*) | | Yes | -| ABSOLUTE_ORIENTATION_QUATERNION | See below | ABSOLUTE_ORIENTATION_EULER_ANGLES (*) | | Yes | -| RELATIVE_ORIENTATION_EULER_ANGLES | See below | ACCELEROMETER and GYROSCOPE (*) | ACCELEROMETER (*) | | -| | | or ACCELEROMETER (*) | | | -| RELATIVE_ORIENTATION_QUATERNION | TYPE_GAME_ROTATION_VECTOR | RELATIVE_ORIENTATION_EULER_ANGLES (*) | RELATIVE_ORIENTATION_EULER_ANGLES (*) | | +Some sensors provide data that is obtained by combining readings from other +sensors (so-called low-level sensors). This process is called **sensor fusion**. +It can be done in hardware or software. -(Note: "*" means the sensor type is provided by sensor fusion.) +In Chromium, we sometimes perform software sensor fusion when a certain +hardware sensor is not available but "fusing" readings from other sensors +provides a similar reading. The fusion process involves reading data from one or +more sensors and applying a fusion algorithm to derive another reading from them +(possibly in a different unit). -### Android +The figure below figure shows an overview of the fusion sensor flow: -Sensors are implemented by passing through values provided by the -[Sensor](https://developer.android.com/reference/android/hardware/Sensor.html) -class. The TYPE_* values in the below descriptions correspond to the integer -constants from the android.hardware.Sensor used to provide data for a -SensorType. + -For GRAVITY, the following sensor fallback is used: -1. Use TYPE_GRAVITY directly -2. ACCELEROMETER, with a low-pass filter to isolate the effect of gravity +In the code, the main classes are +[`PlatformSensorFusion`](platform_sensor_fusion.h) and +[`PlatformSensorFusionAlgorithm`](platform_sensor_fusion_algorithm.h). -For LINEAR_ACCELEROMETER, the following sensor fallback is used: -1. Use TYPE_LINEAR_ACCELERATION directly -2. ACCELEROMETER, with a low-pass filter to isolate the effect of gravity +`PlatformSensorFusion` owns a `PlatformSensorFusionAlgorithm` instance. It +inherits from both `PlatformSensor` as well as `PlatformSensor::Client`. The +former indicates it can be treated by consumers as a regular sensor, while the +latter means that it subscribes to updates from low-level sensors (like +[`SensorImpl`](sensor_impl.h) itself). It is in its implementation of +`OnSensorReadingChanged()` that it invokes its `PlatformSensorFusionAlgorithm` +to fuse data from the underlying sensors. -For ABSOLUTE_ORIENTATION_EULER_ANGLES, the following sensor fallback is used: -1. ABSOLUTE_ORIENTATION_QUATERNION (if it uses TYPE_ROTATION_VECTOR - directly) -2. Combination of ACCELEROMETER and MAGNETOMETER +Once any of the low-level sensors receive a new value, it notifies its clients +(including the fusion sensor). The fusion sensor algorithm reads the low-level +sensor raw values and outputs a new reading, which is fed to +`PlatformSensor::UpdateSharedBufferAndNotifyClients()` as usual. -For ABSOLUTE_ORIENTATION_QUATERNION, the following sensor fallback is used: -1. Use TYPE_ROTATION_VECTOR directly -2. ABSOLUTE_ORIENTATION_EULER_ANGLES +### Security and Privacy -For RELATIVE_ORIENTATION_EULER_ANGLES, converts the data produced by -RELATIVE_ORIENTATION_QUATERNION to euler angles. +Platform sensor readings can expose more information about a device and +consequently lead to an increase in the [fingerprinting +surface](https://w3c.github.io/fingerprinting-guidance/) exposed by the +browser, eavesdropping, and keystroke monitoring. -### Linux and Chrome OS +The security and anti-fingerprinting considerations are also based on existing +literature on the topic, especially research on sensors exposed to native +applications on mobile devices: -On Linux, sensors are implemented by reading values from the IIO subsystem. -The values in the "Linux" column of the table above are the prefix of the -sysfs files Chrome searches for to provide data for a SensorType. +* [Gyrophone: Recognizing Speech from Gyroscope + Signals](https://crypto.stanford.edu/gyrophone/files/gyromic.pdf) +* [ACCessory: password inference using accelerometers on + smartphones](https://pdfs.semanticscholar.org/3673/2ae9fbf61f84eab43e60bc2bcb0a48d05b67.pdf) +* [Touchsignatures: identification of user touch actions and pins based on + mobile sensor data via javascript](https://arxiv.org/pdf/1602.04115.pdf) +* [SoK: Systematic Classification of Side-Channel Attacks on Mobile + Devices](https://arxiv.org/pdf/1611.03748.pdf) +* [Pin skimming: Exploiting the ambient-light sensor in mobile + devices](https://arxiv.org/pdf/1405.3760.pdf) +* [TapLogger: Inferring User Inputs On Smartphone Touchscreens Using On-board + Motion Sensors](https://pdfs.semanticscholar.org/c860/4311321f1b8f8fdc8acff8871a5bad2ad4ac.pdf) + +The Generic Sensor implementation in Chromium follows the [Mitigation +Strategies](https://w3c.github.io/sensors/#mitigation-strategies) section of +the Generic Sensor API specification. Namely, this means that: + +* The sensor APIs are only exposed to secure contexts (the same also applies + to the API exposed by the [Device Orientation + spec](https://w3c.github.io/deviceorientation/#idl-index)). +* There is integration with both the Permissions API and the Permissions + Policy API. +* Sensor readings are only available to documents whose visibility state is + "visible" (this also applies to the Device Orientation API). +* Sensor readings are only available for active documents whose origin is same + origin-domain with the currently focused area document. + +The Chromium implementation also applies additional privacy measures (some of +which are making their way back to the specification): + +* **Frequency**: The maximum sampling frequency is + [capped](/services/device/public/cpp/generic_sensor/sensor_traits.h) at 60Hz + for most sensor types. Ambient Light sensors and magnetometers are capped at + 10Hz. +* **Accuracy**: Readings are [quantized](#Rounding), and for some sensor types + readings which do not differ by a certain [threshold](#Threshold-checks) are + discarded and never exposed. + +There is no distinction in how the Generic Sensor APIs are exposed to regular +and incognito windows. + +### Classes & APIs + +#### //services main classes + +* `PlatformSensorProvider`: singleton class whose main functionality is to + create and track `PlatformSensor` instances. `PlatformSensorProvider` is + also responsible for creating a shared buffer for sensor readings. Every + platform has its own implementation of `PlatformSensorProvider` + (`PlatformSensorProviderAndroid`, `PlatformSensorProviderWin` etc), and the + generic part of the functionality is encapsulated inside the + `PlatformSensorProviderBase` class. + +* `PlatformSensor`: represents device sensor of a given type. There can be + only one `PlatformSensor` instance of the same type at a time, its ownership + is shared between existing `SensorImpl` instances. `PlatformSensor` is an + abstract class which encapsulates generic functionality and is inherited by + the platform-specific implementations (`PlatformSensorAndroid`, + `PlatformSensorWin` etc). + +* `SensorImpl`: implements the exposed `Sensor` Mojo interface and forwards + IPC calls to the owned PlatformSensor instance. `SensorImpl` implements the + `PlatformSensor::Client` interface to receive notifications from + `PlatformSensor`. + +* `SensorProviderImpl`: implements the exposed `SensorProvider` Mojo interface + and forwards IPC calls to the `PlatformSensorProvider` singleton instance. + +The classes above have the following ownership relationships: + +* `SensorProviderImpl` owns a single `PlatformSensorProvider` instance via a + `std::unique_ptr`. +* `SensorProviderImpl` owns all `SensorImpl` instances via a + `mojo::UniqueReceiverSet`. +* `PlatformSensor` is a ref-counted class, and a `SensorImpl` has a reference + to a `PlatformSensor`. +* `DeviceService` owns a single `SensorProviderImpl` instance. + `DeviceService::BindSensorProvider()` is responsible for creating a + `PlatformSensorProvider` if one does not exist and pass it to + `SensorProviderImpl`. + +#### Blink main classes + +* `Sensor`: implements bindings for the `Sensor` IDL interface. All classes + that implement concrete sensor interfaces (such as `AmbientLightSensor`, + `Gyroscope`, `Accelerometer`) must inherit from it. + +* `SensorProviderProxy`: owns one side of the `SensorProvider` Mojo interface + pipe and manages `SensorProxy` instances. This class supplements + `DOMWindow`, so `Sensor` obtains a `SensorProviderProxy` instance via + `SensorProviderProxy::From()` and uses it to the get `SensorProxy` instance + for a given sensor type. + +* `SensorProxy`: owns one side of the `Sensor` Mojo interface and implements + the `device::mojom::blink::SensorClient` Mojo interface. It also defines a + `SensorProxy::Observer` interface that is used to notify `Sensor` and its + subclasses of errors or data updates from the platform side. `Sensor` and + its subclasses interact with the `//services` side via `SensorProxy` (and + `SensorProviderProxy`) rather than owning the Mojo pipes themselves. + +In a `LocalDOMWindow`, there is one `SensorProxy` instance for a given sensor +type (ambient light, accelerometer, etc) whose ownership is shared among +`Sensor` instances. `SensorProxy` instances are created when `Sensor::start()` +is called and are destroyed when there are no more active Sensor instances left. + +### Code flow + +#### Low-level sensor + +The figure below shows the code flow for a low-level (i.e. non-fusion) sensor: + + + +Each OS-specific `PlatformSensor` implementation retrieves sensor readings +differently, but they all ultimately call +`PlatformSensor::UpdateSharedBufferAndNotifyClients()`. This function invokes +`PlatformSensor::UpdateSharedBuffer()` in +[`platform_sensor.cc`](platform_sensor.cc), which checks and transforms a +reading before storing it in the shared buffer: + +1. Sensors whose reporting mode is `mojom::ReportingMode::ON_CHANGE` (i.e. they + only send notifications when the reading has changed) first check if the new + value is different enough compared to the current value. What is considered + different enough (i.e. the threshold check) varies per sensor type (see + `PlatformSensor::IsSignificantlyDifferent()` for the base implementation). + [Threshold](#threshold)-chapter has more information why code uses threshold + value. And [Used threshold values](#used-threshold-values)-chapter has the + actual values. +1. If the check above passes, the so-called "raw" (unrounded) reading is stored + to [`last_raw_reading_`](platform_sensor.h). +1. The reading is rounded via `RoundSensorReading()` (in + [`platform_sensor_util.cc`](platform_sensor_util.cc)) using a per-type + algorithm. [Rounding](#rounding)-chapter has more information why sensor + values are rounded. +1. The rounded reading is stored in the shared buffer and becomes the value + that clients can read. + +#### Fusion sensor + +Fusion sensors behave similarly, but with extra steps at the end: + +1. They get notified of a new reading when + `PlatformSensor::UpdateSharedBufferAndNotifyClients()` invokes + `PlatformSensorFusion::OnSensorReadingChanged()`. +1. `PlatformSensorFusion::OnSensorReadingChanged()` invokes the sensor's fusion + algorithm, which fetches the low-level sensors' **raw** readings and fuses + them. +1. It invokes `UpdateSharedBufferAndNotifyClients()`, which will go through the + same threshold check and rounding process described above, but for the fused + reading. + +The figure below shows an example of the code flow: + + + +#### Rounding and threshold checks + +##### Rounding + +Rounding is a form of +[quantization](https://en.wikipedia.org/wiki/Quantization_(signal_processing)). +It is used to reduce the accuracy of raw sensor readings in order to help reduce +the fingerprinting surface exposed by sensors. For example, instead of exposing +an accelerometer reading of 12.34567m/s^2, we expose a value of 12.3m/s^2 +instead. https://crbug.com/1018180 and https://crbug.com/1031190 show examples +of issues we try to avoid by providing rounded readings. + +Choosing how much rounding to apply is a balance between reducing the +fingerprinting surface while also still providing values that are meaningful +enough to users. [`platform_sensor_util.h`](platform_sensor_util.h) contains the +values we use for each different sensor type. + +Currently magnetometer, pressure and proximity sensor readings are not rounded +(magnetometer is not exposed by default, and there is no backend implementation +for pressure and proximity sensors). + +##### Threshold checks + +To prevent small changes around the rounding border from triggering +notifications, a threshold check is performed and readings that fail it are +discarded. Rounding is the main measure to prevent fingerprinting and data +leaks, and the threshold checks play an auxiliary role in conjunction with it by +reducing the number of updates when a raw reading is hovering around a certain +value. + +**Note:** see the discussions in https://crrev.com/c/3666917 and +https://crbug.com/1332536 about the role threshold checks play as a mitigation +strategy. On the one hand, there is no mathematical analysis behind its use as a +security measure, on the other hand we know that it does reduce the number of +updates and does not increase the attack surface. + +**Note:** threshold checks are only performed for sensors whose reporting mode +is `ON_CHANGE`. We consider that for sensors with a `CONTINUOUS` reporting mode +it is more important to report readings at a certain rate than to ignore similar +readings. + +For example, if the code rounded readings to the nearest multiple of 50 and no +threshold checks were done, a change from a raw value of 24 (rounded to 0) to +25 (rounded to 50) would trigger a new reading notification, whereas requiring +the raw readings to differ by 25 guarantees that the readings must differ more +significantly to trigger a new notification. + +The actual checks differ by sensor type: + +* Ambient Light Sensor readings must differ by half of the rounding multiple + (`kAlsRoundingMultiple`), or 25 lux in practice. +* Fusion sensors default to requiring a difference of 0.1 in readings, which + can be changed by calling `PlatformSensorFusionAlgorithm::set_threshold()` +* Other low-level sensors only check for equality between current and new + readings at the moment. + +##### Execution order of rounding and threshold check + +We first perform a threshold check on the current and new raw readings and only +perform rounding and store the new rounded reading if the threshold check +passes. + +If we did rounding first, we would increase even more the area which rounding +already protects, and callers would get values that are too inaccurate. + +#### Permissions + +##### Permissions API integration + +The [`Sensor.start()`](https://w3c.github.io/sensors/#sensor-start) operation +in the Generic Sensor spec invokes the [request sensor +access](https://w3c.github.io/sensors/#request-sensor-access) abstract +operation so that permission checks (via the [Permissions +API](https://w3c.github.io/permissions/) are performed before a sensor is +started. + +In Chromium, the permission checks are done in the `//content/browser` side: +`SensorProviderProxyImpl::GetSensor()` invokes +`PermissionController::RequestPermissionFromCurrentDocument()` and only +connects to the `//services` side if permission has been granted. + +**Note**: At the moment, users are never prompted to grant access to a device's +sensors, access is either allowed or denied. This ended up happening for +historical reasons: the Device Orientation API was implemented first and neither +spec nor implementation were supposed to prompt for sensor access (it was +retrofitted into the spec years later), the Generic Sensor API was added to +Chromium later, the Device Orientation API in Blink was changed to use the same +backend in `//services`, and the permission behavior was kept to avoid breaking +user compatibility. Work to improve the situation for both the Device +Orientation API and the Generic Sensor API in Chromium is tracked in +https://crbug.com/947112. + +From a UI perspective, users are able to grant or deny access to sensors in the +global settings (chrome://settings/content) or on a per-site basis even before +work on issue 947112 is finished. + +##### Permissions policy integration + +The Chromium implementation follows the spec and integrates with the Permissions +Policy spec. + +The [Policy Controlled +Features](https://github.com/w3c/webappsec-permissions-policy/blob/main/features.md) +page lists the current status of different features. + +Blink performs checks in +[`Sensor::Sensor()`](/third_party/blink/renderer/modules/sensor/sensor.cc) by +calling `AreFeaturesEnabled()`, while the `content/` side also performs checks +in +[`SensorProviderProxyImpl::CheckFeaturePolicies()`](/content/browser/generic_sensor/sensor_provider_proxy_impl.cc). + +#### Reporting values to consumer + +##### Reporting modes + +Sensors have two ways of reporting new values as defined in +[`ReportingMode`](/services/device/public/mojom/sensor.mojom). The values are +based on the [Android sensor reporting +modes](https://source.android.com/devices/sensors/report-modes): + +* `ON_CHANGE`: Clients are notified via + `PlatformSensor::Client::OnSensorReadingChanged()` when the measured values + have changed. Different sensor types have different thresholds for + considering whether a change is significant enough to be reported as + discussed in [the round and thresholds + section](#rounding-and-threshold-checks). +* `CONTINUOUS`: Sensor readings are continuously updated at a frequency + derived from + [`PlatformSensorConfiguration.frequency`](/services/device/public/cpp/generic_sensor/platform_sensor_configuration.h). + The sampling frequency value is capped to 10Hz or 60Hz (defined in + [`sensor_traits.h`](/services/device/public/cpp/generic_sensor/sensor_traits.h)) + for security reasons as explained in the [Security and + Privacy](#Security-and-Privacy) section of this document. + `PlatformSensor::Client::OnSensorReadingChanged()` is never invoked, and + clients are expected to periodically fetch readings on their own via + `SensorReadingSharedBufferReader::GetReading()`. + +There is no default reporting mode: `PlatformSensor` subclasses are expected to +implement the `GetReportingMode()` method and return a value fit for the given +OS and sensor type. + +##### Configuration and frequency management + +As described above, there is always at most one `PlatformSensor` instance for a +given sensor type, and it can have multiple clients consuming its readings. Each +client might be interested in receiving readings at a different frequency, and +it is up to `PlatformSensor` to coordinate these requests and choose a reading +frequency. + +Clients first invoke the [`SensorProvider.GetSensor()` Mojo +method](/services/device/public/mojom/sensor_provider.mojom); on success, the +return values include a [`Sensor` Mojo +interface](/services/device/public/mojom/sensor.mojom). Clients then invoke the +`Sensor.AddConfiguration()` and `Sensor.RemoveConfiguration()` to add and remove +`SensorConfiguration` instances from the given `Sensor`. + +When a new configuration is added, `PlatformSensor::UpdateSensorInternal()` is +called and will ultimately choose the highest of all requested frequencies +(within the boundaries defined in +[sensor_traits.h](/services/device/public/cpp/generic_sensor/sensor_traits.h) +for security reasons). In other words, a client's requested frequency does not +necessarily match `PlatformSensor`'s actual sampling frequency (or the frequency +the OS ends up using). + +It is then up to each client to check a reading's timestamp and decide whether +to ignore it if not enough time has passed since the previous reading was +delivered. It is also possible for clients to simply process all readings +regardless of the actual sampling frequency. + +Blink adopts the former strategy: + +* For sensors with a `CONTINUOUS` reporting mode, `SensorProxyImpl` polls the + shared memory buffer at the highest requested frequency. For sensors with a + `ON_CHANGE` reporting mode, it will receive updates from the services side + via `SensorProxyImpl::SensorReadingChanged()`. +* Each individual `Sensor` instance connected to a `SensorProxyImpl` will be + notified via `Sensor::OnSensorReadingChanged()`, which takes care of + avoiding sending too many "reading" JS notifications depending on the Sensor + instance's requested frequency. + +##### Sensor readings shared buffer + +As mentioned above, sensor readings are not transmitted from the services side +to the consumers (such as the renderer process) via IPC calls, but with a +[shared memory buffer](/base/memory/read_only_shared_memory_region.h). +Read-write operations are synchronized via a seqlock mechanism. + +The `PlatformSensorProvider` singleton owned by `DeviceService` maintains a +shared memory mapping of the entire buffer. Only `PlatformSensorProvider` has +write access to it; all consumers only have read-access to the buffer. This +shared buffer is a contiguous sequence of `SensorReadingSharedBuffer`s, one per +`mojom::SensorType`. + +Each `SensorReadingBuffer` structure has 6 tightly-packed 64-bit floating +fields: **seqlock**, **timestamp**, **sensor reading 1**, **sensor reading 2**, +**sensor reading 3**, and **sensor reading 4**. This has a fixed size of 6 * 8 = +48 bytes. The whole shared buffer's size depends on `mojom::SensorType`'s size; +at the time of writing, there are 12 distinct sensor types, which means the +entire shared buffer handle is 12 * 48 = 576 bytes in size. +[sensor_reading.h](/services/device/public/cpp/generic_sensor/sensor_reading.h) +has the actual `SensorReading` data structure as well as the +`SensorReadingSharedBuffer` structure. + +The code treats each `SensorReadingBuffer` embedded in the mapping as completely +independent from the others: `SensorReadingSharedBuffer::GetOffset()` provides +the offset in the buffer corresponding to the `SensorReadingBuffer` representing +a given sensor type, `SensorReadingSharedBufferReader::Create()` requires an +offset to map only a specific portion of the shared buffer and, additionally, +each `SensorReadingBuffer` has its own `seqlock` for coordinating reads and +writes. + + + +In terms of code flow, the creation and sharing of the shared buffer when +between Blink calls `SensorProviderProxy::GetSensor()` works roughly like this: + +1. `SensorProviderProxy::GetSensor()` calls the `GetSensor()` operation in the + Sensor Mojo interface. +1. That is implemented by `SensorProviderImpl::GetSensor()`. It invokes + `PlatformSensorProviderBase::CloneSharedMemoryRegion()`. + 1. `PlatformSensorProviderBase::CloneSharedMemoryRegion()` initializes the + shared buffer and the mapping if necessary in + `PlatformSensorProviderBase::CreateSharedBufferIfNeeded()`. + 1. `PlatformSensorProviderBase::CloneSharedMemoryRegion()` returns a + read-only mapping handle. +1. If the platform sensor still needs to be created, + `SensorProviderImpl::GetSensor()` will invoke + `PlatformSensorProviderBase::CreateSensor()`, which invokes + `PlatformSensorProviderBase::GetSensorReadingSharedBufferForType()`. The + `SensorReadingSharedBuffer` pointer returned by this function is later + passed to `PlatformSensor` and its subclasses, which update it when the + readings change. +1. Ultimately, `PlatformSensorProviderBase::SensorCreated()` is called, and the + read-only shared buffer handle and the offset in it corresponding to the + sensor type being created are passed in `mojom::SensorInitParams`. +1. On the Blink side, `SensorProxyImpl::OnSensorCreated()` is invoked with the + `SensorInitParams` initialized above. It invokes + `SensorReadingSharedBufferReader::Create()` with the buffer and offset from + `SensorInitParams`, and that is what it later used to obtain readings. + +### Platform-specific details + +#### Android + +The Android implementation in `//services` consists of two parts, native (C++) +and Java. The native side includes `PlatformSensorProviderAndroid` and +`PlatformSensorAndroid`, while the Java side consists of the +`PlatformSensorProvider` and `PlatformSensor` classes that are included in the +`org.chromium.device.sensors` package. Java classes interface with Android +Sensor API to fetch readings from device sensors. The native and Java sides +communicate via JNI. + +The [`PlatformSensorProviderAndroid`](platform_sensor_provider_android.h) C++ +class inherits from `PlatformSensorProvider` and is responsible for creating a +`PlatformSensorProvider` (Java) instance via JNI. When the Java object is +created, all sensor creation requests are forwarded to the Java object. + +The [`PlatformSensorAndroid`](platform_sensor_android.h) C++ class inherits from +`PlatformSensor`, owns the `PlatformSensor` Java object and forwards start, stop +and other requests to it. + +The +[`PlatformSensorProvider`](android/java/src/org/chromium/device/sensors/PlatformSensorProvider.java) +Java class is responsible for thread management, and `PlatformSensor` creation. +It also owns the Android `SensorManager` object that is accessed by +`PlatformSensor` Java objects. + +The +[`PlatformSensor`](android/java/src/org/chromium/device/sensors/PlatformSensor.java) +Java class implements the `SensorEventListener` interface and owns the Android +`Sensor` object. `PlatformSensor` adds itself as an event listener to receive +sensor reading updates and forwards them to native side using the `native*` +methods. + +#### Windows + +The Windows backend has its [own README.md](windows/README.md). + +#### ChromeOS + On ChromeOS, sensors are implemented with Mojo connections to IIO Service, a CrOS daemon that provides sensors' data to other applications. -The ABSOLUTE_ORIENTATION_EULER_ANGLES sensor type is provided by interpreting -the value that can be read from the ACCELEROMETER and MAGNETOMETER. The -ABSOLUTE_ORIENTATION_QUATERNION sensor type is provided by interpreting the -value that can be read from the ABSOLUTE_ORIENTATION_EULER_ANGLES. The -RELATIVE_ORIENTATION_EULER_ANGLES sensor type is provided by interpreting the -value that can be read from the ACCELEROMETER and GYROSCOPE, or ACCELEROMETER. -The RELATIVE_ORIENTATION_QUATERNION sensor type is provided by interpreting the -value that can be read from the RELATIVE_ORIENTATION_EULER_ANGLES. -LINEAR_ACCELEROMETER sensor type is provided by implementing a low-pass-filter -over the values returned by the ACCELEROMETER in order to remove the -contribution of the gravitational force. -### macOS +_Need to add information about iio service and the platform-specific +implementation that reads sensor data and feeds it to Chromium_ -On this platform there is limited support for sensors. The AMBIENT_LIGHT sensor -type is provided by interpreting the value that can be read from the LMU. The -ACCELEROMETER sensor type is provided by interpreting the value that can be read -from the SMCMotionSensor. The RELATIVE_ORIENTATION_EULER_ANGLES sensor type is -provided by interpreting the value that can be read from the ACCELEROMETER. The -RELATIVE_ORIENTATION_QUATERNION sensor type is provided by interpreting the -value that can be read from the RELATIVE_ORIENTATION_EULER_ANGLES. +#### Linux -### Windows +Sensor data is exposed by the Linux kernel via its Industrial I/O (iio) +subsystem. Sensor readings and metadata are readable via sysfs; udev is used for +device enumeration and getting notifications about sensors that are added or +removed from the system. -Please refer to this [document](windows/README.md). +[`PlatformSensorProviderLinuxBase`](platform_sensor_provider_linux_base.h) is +shared between the Linux and ChromeOS implementations, and +[`PlatformSensorProviderLinux`](platform_sensor_provider_linux.h) is its +Linux-specific subclass. Similarly, +[`PlatformSensorLinux`](platform_sensor_linux.h) inherits from the base +`PlatformSensor` class. -## Testing +The implementation is supported by a few more classes: -Sensors platform unit tests are located in the current directory and its -subdirectories. +* [`SensorDeviceManager`](linux/sensor_device_manager.h): interfaces with udev + by subclassing `device::UdevWatcher::Observer`. It enumerates all sensors + exposed by the Linux kernel via udev, caches their information (frequency, + scaling value, sysfs location etc) and notifies users (i.e. + `PlatformSensorProviderLinux`) of changes later. +* [`SensorInfoLinux`](linux/sensor_data_linux.h): gathers all iio sensor + information in a single struct (frequency, scaling value, sysfs location + etc). +* [`SensorReader`](platform_sensor_reader_linux.h) and + [`PollingSensorReader`](platform_sensor_reader_linux.cc) implement the + reading and reporting of sensor data from sysfs. -The sensors unit tests file for Android is -`android/junit/src/org/chromium/device/sensors/PlatformSensorAndProviderTest.java`. +When a request for a specific type of sensor comes and +`PlatformSensorProviderLinux::CreateSensorInternal()` is called, it will either +cause `SensorDeviceManager` to start enumerating all available sensors if that +has not happened yet or look for a specific sensor in `SensorDeviceManager`'s +cache. That is then used to construct a new `PlatformSensorLinux` object (which +takes a `SensorInfoLinux` pointer), which then owns a `SensorReader` that uses +the `SensorInfoLinux` to know which sensor data to read and how to parse it. -Sensors browser tests are located in `content/test/data/generic_sensor`. +#### macOS -## Design Documents +`PlatformSensorProviderMac` implements `PlatformSensorProvider` and is +responsible for creating one of the two classes implementing sensor support on +Mac: -Please refer to the [design documentation](https://docs.google.com/document/d/1Ml65ZdW5AgIsZTszk4mD_ohr40pcrdVFOIf0ZtWxDv0) -for more details. +* [`PlatformSensorAccelerometerMac`](platform_sensor_accelerometer_mac.h) + exposes accelerometer data and can be in sensor fusion (e.g. + [`RelativeOrientationEulerAnglesFusionAlgorithmUsingAccelerometer`](relative_orientation_euler_angles_fusion_algorithm_using_accelerometer.h)). + It is backed by the + [`SuddenMotionSensor`](/third_party/sudden_motion_sensor/sudden_motion_sensor_mac.h) + code in third_party and thus relies on being able to read from the + SMCMotionSensor. +* [`PlatformSensorAmbientLightMac`](platform_sensor_ambient_light_mac.h) + exposed ambient light data from laptop models that support and expose it. + +As evidenced above, macOS provides limited support for reading sensor data, and +it is mostly restricted to older laptop models. In the future, it might be +possible to remove all the Mac code from `//services/device/generic_sensor`.
diff --git a/services/device/generic_sensor/docs/fusion_sensor_flow.png b/services/device/generic_sensor/docs/fusion_sensor_flow.png new file mode 100644 index 0000000..c16a41f7 --- /dev/null +++ b/services/device/generic_sensor/docs/fusion_sensor_flow.png Binary files differ
diff --git a/services/device/generic_sensor/docs/generic_sensor_framework_component_diagram.png b/services/device/generic_sensor/docs/generic_sensor_framework_component_diagram.png new file mode 100644 index 0000000..fec970d --- /dev/null +++ b/services/device/generic_sensor/docs/generic_sensor_framework_component_diagram.png Binary files differ
diff --git a/services/device/generic_sensor/docs/low_level_sensor_flow.png b/services/device/generic_sensor/docs/low_level_sensor_flow.png new file mode 100644 index 0000000..61e0a39 --- /dev/null +++ b/services/device/generic_sensor/docs/low_level_sensor_flow.png Binary files differ
diff --git a/services/device/generic_sensor/docs/overall_picture_of_sensor_flow.png b/services/device/generic_sensor/docs/overall_picture_of_sensor_flow.png new file mode 100644 index 0000000..dc5439b --- /dev/null +++ b/services/device/generic_sensor/docs/overall_picture_of_sensor_flow.png Binary files differ
diff --git a/services/device/generic_sensor/docs/shared_buffer.png b/services/device/generic_sensor/docs/shared_buffer.png new file mode 100644 index 0000000..59d0efb --- /dev/null +++ b/services/device/generic_sensor/docs/shared_buffer.png Binary files differ
diff --git a/services/network/restricted_cookie_manager.cc b/services/network/restricted_cookie_manager.cc index cee388b..2f2199c 100644 --- a/services/network/restricted_cookie_manager.cc +++ b/services/network/restricted_cookie_manager.cc
@@ -638,7 +638,11 @@ // TODO(pwnall): Validate the CanonicalCookie fields. // Update the creation and last access times. - base::Time now = base::Time::NowFromSystemTime(); + // Note: This used to be a call to NowFromSystemTime, but this caused + // inconsistency with the expiration date, which was capped checking + // against Now. If any issues crop up related to this change please + // contact the owners of http://crbug.com/1335859. + base::Time now = base::Time::Now(); // TODO(http://crbug.com/1024053): Log metrics const GURL& origin_url = origin_.GetURL(); net::CookieSourceScheme source_scheme =
diff --git a/testing/buildbot/chromium.android.fyi.json b/testing/buildbot/chromium.android.fyi.json index 7317259..41e109b 100644 --- a/testing/buildbot/chromium.android.fyi.json +++ b/testing/buildbot/chromium.android.fyi.json
@@ -8325,15 +8325,15 @@ { "args": [ "--additional-apk=apks/WebLayerShellSystemWebView.apk", - "--webview-apk-path=apks/SystemWebView.apk", "--test-runner-outdir", ".", - "--client-outdir", - "../../weblayer_instrumentation_test_M103/out/Release", "--implementation-outdir", ".", "--test-expectations", "../../weblayer/browser/android/javatests/skew/expectations.txt", + "--webview-apk-path=apks/SystemWebView.apk", + "--client-outdir", + "../../weblayer_instrumentation_test_M103/out/Release", "--client-version=103", "--gs-results-bucket=chromium-result-details", "--recover-devices", @@ -8359,7 +8359,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M103", - "revision": "version:103.0.5060.52" + "revision": "version:103.0.5060.53" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -8410,15 +8410,15 @@ { "args": [ "--additional-apk=apks/WebLayerShellSystemWebView.apk", - "--webview-apk-path=apks/SystemWebView.apk", "--test-runner-outdir", ".", - "--client-outdir", - "../../weblayer_instrumentation_test_M104/out/Release", "--implementation-outdir", ".", "--test-expectations", "../../weblayer/browser/android/javatests/skew/expectations.txt", + "--webview-apk-path=apks/SystemWebView.apk", + "--client-outdir", + "../../weblayer_instrumentation_test_M104/out/Release", "--client-version=104", "--gs-results-bucket=chromium-result-details", "--recover-devices", @@ -8835,15 +8835,15 @@ { "args": [ "--additional-apk=apks/WebLayerShellSystemWebView.apk", - "--webview-apk-path=apks/AOSP_SystemWebView.apk", "--test-runner-outdir", ".", "--client-outdir", ".", - "--implementation-outdir", - "../../weblayer_instrumentation_test_M103/out/Release", "--test-expectations", "../../weblayer/browser/android/javatests/skew/expectations.txt", + "--webview-apk-path=apks/AOSP_SystemWebView.apk", + "--implementation-outdir", + "../../weblayer_instrumentation_test_M103/out/Release", "--impl-version=103", "--gs-results-bucket=chromium-result-details", "--recover-devices", @@ -8869,7 +8869,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M103", - "revision": "version:103.0.5060.52" + "revision": "version:103.0.5060.53" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -8920,15 +8920,15 @@ { "args": [ "--additional-apk=apks/WebLayerShellSystemWebView.apk", - "--webview-apk-path=apks/AOSP_SystemWebView.apk", "--test-runner-outdir", ".", "--client-outdir", ".", - "--implementation-outdir", - "../../weblayer_instrumentation_test_M104/out/Release", "--test-expectations", "../../weblayer/browser/android/javatests/skew/expectations.txt", + "--webview-apk-path=apks/AOSP_SystemWebView.apk", + "--implementation-outdir", + "../../weblayer_instrumentation_test_M104/out/Release", "--impl-version=104", "--gs-results-bucket=chromium-result-details", "--recover-devices",
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json index ac73252..5e98dd5 100644 --- a/testing/buildbot/chromium.android.json +++ b/testing/buildbot/chromium.android.json
@@ -14740,10 +14740,11 @@ "--bucket", "chromium-result-details", "--test-name", - "webview_trichrome_cts_tests" + "webview_trichrome_cts_tests full_mode" ], "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, + "name": "webview_trichrome_cts_tests full_mode", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -14795,11 +14796,87 @@ "name": "shard #${SHARD_INDEX} logcats" } ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 2 + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "webview_trichrome_cts_tests", - "test_id_prefix": "ninja://android_webview/test:webview_trichrome_cts_tests/" + "test_id_prefix": "ninja://android_webview/test:webview_trichrome_cts_tests/", + "variant_id": "full_mode" + }, + { + "args": [ + "--exclude-annotation", + "AppModeFull", + "--test-apk-as-instant", + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android30.textpb" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "webview_trichrome_cts_tests instant_mode" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "name": "webview_trichrome_cts_tests instant_mode", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "chromium/android_webview/tools/cts_archive", + "location": "android_webview/tools/cts_archive", + "revision": "qF6dhyFMW7qFOzHo_Lu-bWxpbe-zRfL1KvHPQtQA3d0C" + }, + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4|e2-standard-4", + "os": "Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android30", + "path": ".android_emulator/generic_android30" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android30" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "webview_trichrome_cts_tests", + "test_id_prefix": "ninja://android_webview/test:webview_trichrome_cts_tests/", + "variant_id": "instant_mode" }, { "args": [ @@ -19551,10 +19628,11 @@ "--bucket", "chromium-result-details", "--test-name", - "webview_trichrome_64_cts_tests" + "webview_trichrome_64_cts_tests full_mode" ], "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, + "name": "webview_trichrome_64_cts_tests full_mode", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -19606,11 +19684,87 @@ "name": "shard #${SHARD_INDEX} logcats" } ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 2 + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "webview_trichrome_64_cts_tests", - "test_id_prefix": "ninja://android_webview/test:webview_trichrome_64_cts_tests/" + "test_id_prefix": "ninja://android_webview/test:webview_trichrome_64_cts_tests/", + "variant_id": "full_mode" + }, + { + "args": [ + "--exclude-annotation", + "AppModeFull", + "--test-apk-as-instant", + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "webview_trichrome_64_cts_tests instant_mode" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "name": "webview_trichrome_64_cts_tests instant_mode", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "chromium/android_webview/tools/cts_archive", + "location": "android_webview/tools/cts_archive", + "revision": "qF6dhyFMW7qFOzHo_Lu-bWxpbe-zRfL1KvHPQtQA3d0C" + }, + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "webview_trichrome_64_cts_tests", + "test_id_prefix": "ninja://android_webview/test:webview_trichrome_64_cts_tests/", + "variant_id": "instant_mode" }, { "args": [ @@ -46297,15 +46451,15 @@ { "args": [ "--additional-apk=apks/WebLayerShellSystemWebView.apk", - "--webview-apk-path=apks/SystemWebView.apk", "--test-runner-outdir", ".", - "--client-outdir", - "../../weblayer_instrumentation_test_M103/out/Release", "--implementation-outdir", ".", "--test-expectations", "../../weblayer/browser/android/javatests/skew/expectations.txt", + "--webview-apk-path=apks/SystemWebView.apk", + "--client-outdir", + "../../weblayer_instrumentation_test_M103/out/Release", "--client-version=103", "--gs-results-bucket=chromium-result-details", "--recover-devices", @@ -46331,7 +46485,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M103", - "revision": "version:103.0.5060.52" + "revision": "version:103.0.5060.53" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -46382,15 +46536,15 @@ { "args": [ "--additional-apk=apks/WebLayerShellSystemWebView.apk", - "--webview-apk-path=apks/SystemWebView.apk", "--test-runner-outdir", ".", - "--client-outdir", - "../../weblayer_instrumentation_test_M104/out/Release", "--implementation-outdir", ".", "--test-expectations", "../../weblayer/browser/android/javatests/skew/expectations.txt", + "--webview-apk-path=apks/SystemWebView.apk", + "--client-outdir", + "../../weblayer_instrumentation_test_M104/out/Release", "--client-version=104", "--gs-results-bucket=chromium-result-details", "--recover-devices", @@ -46807,15 +46961,15 @@ { "args": [ "--additional-apk=apks/WebLayerShellSystemWebView.apk", - "--webview-apk-path=apks/AOSP_SystemWebView.apk", "--test-runner-outdir", ".", "--client-outdir", ".", - "--implementation-outdir", - "../../weblayer_instrumentation_test_M103/out/Release", "--test-expectations", "../../weblayer/browser/android/javatests/skew/expectations.txt", + "--webview-apk-path=apks/AOSP_SystemWebView.apk", + "--implementation-outdir", + "../../weblayer_instrumentation_test_M103/out/Release", "--impl-version=103", "--gs-results-bucket=chromium-result-details", "--recover-devices", @@ -46841,7 +46995,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M103", - "revision": "version:103.0.5060.52" + "revision": "version:103.0.5060.53" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -46892,15 +47046,15 @@ { "args": [ "--additional-apk=apks/WebLayerShellSystemWebView.apk", - "--webview-apk-path=apks/AOSP_SystemWebView.apk", "--test-runner-outdir", ".", "--client-outdir", ".", - "--implementation-outdir", - "../../weblayer_instrumentation_test_M104/out/Release", "--test-expectations", "../../weblayer/browser/android/javatests/skew/expectations.txt", + "--webview-apk-path=apks/AOSP_SystemWebView.apk", + "--implementation-outdir", + "../../weblayer_instrumentation_test_M104/out/Release", "--impl-version=104", "--gs-results-bucket=chromium-result-details", "--recover-devices", @@ -47321,15 +47475,15 @@ { "args": [ "--additional-apk=apks/ChromePublic.apk", - "--webview-apk-path=apks/SystemWebView.apk", "--test-runner-outdir", ".", - "--client-outdir", - "../../weblayer_instrumentation_test_M103/out/Release", "--implementation-outdir", ".", "--test-expectations", "../../weblayer/browser/android/javatests/skew/expectations.txt", + "--webview-apk-path=apks/SystemWebView.apk", + "--client-outdir", + "../../weblayer_instrumentation_test_M103/out/Release", "--client-version=103", "--gs-results-bucket=chromium-result-details", "--recover-devices", @@ -47355,7 +47509,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M103", - "revision": "version:103.0.5060.52" + "revision": "version:103.0.5060.53" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -47406,15 +47560,15 @@ { "args": [ "--additional-apk=apks/ChromePublic.apk", - "--webview-apk-path=apks/SystemWebView.apk", "--test-runner-outdir", ".", - "--client-outdir", - "../../weblayer_instrumentation_test_M104/out/Release", "--implementation-outdir", ".", "--test-expectations", "../../weblayer/browser/android/javatests/skew/expectations.txt", + "--webview-apk-path=apks/SystemWebView.apk", + "--client-outdir", + "../../weblayer_instrumentation_test_M104/out/Release", "--client-version=104", "--gs-results-bucket=chromium-result-details", "--recover-devices", @@ -47831,15 +47985,15 @@ { "args": [ "--additional-apk=apks/ChromePublic.apk", - "--webview-apk-path=apks/AOSP_SystemWebView.apk", "--test-runner-outdir", ".", "--client-outdir", ".", - "--implementation-outdir", - "../../weblayer_instrumentation_test_M103/out/Release", "--test-expectations", "../../weblayer/browser/android/javatests/skew/expectations.txt", + "--webview-apk-path=apks/AOSP_SystemWebView.apk", + "--implementation-outdir", + "../../weblayer_instrumentation_test_M103/out/Release", "--impl-version=103", "--gs-results-bucket=chromium-result-details", "--recover-devices", @@ -47865,7 +48019,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M103", - "revision": "version:103.0.5060.52" + "revision": "version:103.0.5060.53" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -47916,15 +48070,15 @@ { "args": [ "--additional-apk=apks/ChromePublic.apk", - "--webview-apk-path=apks/AOSP_SystemWebView.apk", "--test-runner-outdir", ".", "--client-outdir", ".", - "--implementation-outdir", - "../../weblayer_instrumentation_test_M104/out/Release", "--test-expectations", "../../weblayer/browser/android/javatests/skew/expectations.txt", + "--webview-apk-path=apks/AOSP_SystemWebView.apk", + "--implementation-outdir", + "../../weblayer_instrumentation_test_M104/out/Release", "--impl-version=104", "--gs-results-bucket=chromium-result-details", "--recover-devices", @@ -48413,15 +48567,15 @@ { "args": [ "--additional-apk=apks/WebLayerShellSystemWebView.apk", - "--webview-apk-path=apks/SystemWebView.apk", "--test-runner-outdir", ".", - "--client-outdir", - "../../weblayer_instrumentation_test_M103/out/Release", "--implementation-outdir", ".", "--test-expectations", "../../weblayer/browser/android/javatests/skew/expectations.txt", + "--webview-apk-path=apks/SystemWebView.apk", + "--client-outdir", + "../../weblayer_instrumentation_test_M103/out/Release", "--client-version=103", "--gs-results-bucket=chromium-result-details", "--recover-devices", @@ -48447,7 +48601,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M103", - "revision": "version:103.0.5060.52" + "revision": "version:103.0.5060.53" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -48498,15 +48652,15 @@ { "args": [ "--additional-apk=apks/WebLayerShellSystemWebView.apk", - "--webview-apk-path=apks/SystemWebView.apk", "--test-runner-outdir", ".", - "--client-outdir", - "../../weblayer_instrumentation_test_M104/out/Release", "--implementation-outdir", ".", "--test-expectations", "../../weblayer/browser/android/javatests/skew/expectations.txt", + "--webview-apk-path=apks/SystemWebView.apk", + "--client-outdir", + "../../weblayer_instrumentation_test_M104/out/Release", "--client-version=104", "--gs-results-bucket=chromium-result-details", "--recover-devices", @@ -48923,15 +49077,15 @@ { "args": [ "--additional-apk=apks/WebLayerShellSystemWebView.apk", - "--webview-apk-path=apks/SystemWebView.apk", "--test-runner-outdir", ".", "--client-outdir", ".", - "--implementation-outdir", - "../../weblayer_instrumentation_test_M103/out/Release", "--test-expectations", "../../weblayer/browser/android/javatests/skew/expectations.txt", + "--webview-apk-path=apks/SystemWebView.apk", + "--implementation-outdir", + "../../weblayer_instrumentation_test_M103/out/Release", "--impl-version=103", "--gs-results-bucket=chromium-result-details", "--recover-devices", @@ -48957,7 +49111,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M103", - "revision": "version:103.0.5060.52" + "revision": "version:103.0.5060.53" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -49008,15 +49162,15 @@ { "args": [ "--additional-apk=apks/WebLayerShellSystemWebView.apk", - "--webview-apk-path=apks/SystemWebView.apk", "--test-runner-outdir", ".", "--client-outdir", ".", - "--implementation-outdir", - "../../weblayer_instrumentation_test_M104/out/Release", "--test-expectations", "../../weblayer/browser/android/javatests/skew/expectations.txt", + "--webview-apk-path=apks/SystemWebView.apk", + "--implementation-outdir", + "../../weblayer_instrumentation_test_M104/out/Release", "--impl-version=104", "--gs-results-bucket=chromium-result-details", "--recover-devices", @@ -49505,15 +49659,15 @@ { "args": [ "--additional-apk=apks/WebLayerShellSystemWebView.apk", - "--webview-apk-path=apks/SystemWebView.apk", "--test-runner-outdir", ".", - "--client-outdir", - "../../weblayer_instrumentation_test_M103/out/Release", "--implementation-outdir", ".", "--test-expectations", "../../weblayer/browser/android/javatests/skew/expectations.txt", + "--webview-apk-path=apks/SystemWebView.apk", + "--client-outdir", + "../../weblayer_instrumentation_test_M103/out/Release", "--client-version=103", "--gs-results-bucket=chromium-result-details", "--recover-devices", @@ -49539,7 +49693,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M103", - "revision": "version:103.0.5060.52" + "revision": "version:103.0.5060.53" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -49590,15 +49744,15 @@ { "args": [ "--additional-apk=apks/WebLayerShellSystemWebView.apk", - "--webview-apk-path=apks/SystemWebView.apk", "--test-runner-outdir", ".", - "--client-outdir", - "../../weblayer_instrumentation_test_M104/out/Release", "--implementation-outdir", ".", "--test-expectations", "../../weblayer/browser/android/javatests/skew/expectations.txt", + "--webview-apk-path=apks/SystemWebView.apk", + "--client-outdir", + "../../weblayer_instrumentation_test_M104/out/Release", "--client-version=104", "--gs-results-bucket=chromium-result-details", "--recover-devices", @@ -50015,15 +50169,15 @@ { "args": [ "--additional-apk=apks/WebLayerShellSystemWebView.apk", - "--webview-apk-path=apks/SystemWebView.apk", "--test-runner-outdir", ".", "--client-outdir", ".", - "--implementation-outdir", - "../../weblayer_instrumentation_test_M103/out/Release", "--test-expectations", "../../weblayer/browser/android/javatests/skew/expectations.txt", + "--webview-apk-path=apks/SystemWebView.apk", + "--implementation-outdir", + "../../weblayer_instrumentation_test_M103/out/Release", "--impl-version=103", "--gs-results-bucket=chromium-result-details", "--recover-devices", @@ -50049,7 +50203,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M103", - "revision": "version:103.0.5060.52" + "revision": "version:103.0.5060.53" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -50100,15 +50254,15 @@ { "args": [ "--additional-apk=apks/WebLayerShellSystemWebView.apk", - "--webview-apk-path=apks/SystemWebView.apk", "--test-runner-outdir", ".", "--client-outdir", ".", - "--implementation-outdir", - "../../weblayer_instrumentation_test_M104/out/Release", "--test-expectations", "../../weblayer/browser/android/javatests/skew/expectations.txt", + "--webview-apk-path=apks/SystemWebView.apk", + "--implementation-outdir", + "../../weblayer_instrumentation_test_M104/out/Release", "--impl-version=104", "--gs-results-bucket=chromium-result-details", "--recover-devices", @@ -50282,10 +50436,11 @@ "--bucket", "chromium-result-details", "--test-name", - "webview_trichrome_cts_tests" + "webview_trichrome_cts_tests full_mode" ], "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, + "name": "webview_trichrome_cts_tests full_mode", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -50337,11 +50492,87 @@ "name": "shard #${SHARD_INDEX} logcats" } ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 2 + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "webview_trichrome_cts_tests", - "test_id_prefix": "ninja://android_webview/test:webview_trichrome_cts_tests/" + "test_id_prefix": "ninja://android_webview/test:webview_trichrome_cts_tests/", + "variant_id": "full_mode" + }, + { + "args": [ + "--exclude-annotation", + "AppModeFull", + "--test-apk-as-instant", + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android29.textpb" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "webview_trichrome_cts_tests instant_mode" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "name": "webview_trichrome_cts_tests instant_mode", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "chromium/android_webview/tools/cts_archive", + "location": "android_webview/tools/cts_archive", + "revision": "qF6dhyFMW7qFOzHo_Lu-bWxpbe-zRfL1KvHPQtQA3d0C" + }, + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4|e2-standard-4", + "os": "Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android29", + "path": ".android_emulator/generic_android29" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android29" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "webview_trichrome_cts_tests", + "test_id_prefix": "ninja://android_webview/test:webview_trichrome_cts_tests/", + "variant_id": "instant_mode" } ] }
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl index c612a30..c51929d 100644 --- a/testing/buildbot/test_suites.pyl +++ b/testing/buildbot/test_suites.pyl
@@ -5364,34 +5364,12 @@ }, }, - 'webview_trichrome_64_cts_tests_gtest': { - 'webview_trichrome_64_cts_tests': { - 'swarming': { - 'shards': 2, - 'cipd_packages': [ - { - "cipd_package": 'chromium/android_webview/tools/cts_archive', - 'location': 'android_webview/tools/cts_archive', - 'revision': 'qF6dhyFMW7qFOzHo_Lu-bWxpbe-zRfL1KvHPQtQA3d0C', - } - ] - }, - }, + 'webview_trichrome_64_cts_tests': { + 'webview_trichrome_64_cts_tests': {}, }, - 'webview_trichrome_cts_tests_gtest': { - 'webview_trichrome_cts_tests': { - 'swarming': { - 'shards': 2, - 'cipd_packages': [ - { - "cipd_package": 'chromium/android_webview/tools/cts_archive', - 'location': 'android_webview/tools/cts_archive', - 'revision': 'qF6dhyFMW7qFOzHo_Lu-bWxpbe-zRfL1KvHPQtQA3d0C', - } - ] - }, - }, + 'webview_trichrome_cts_tests': { + 'webview_trichrome_cts_tests': {}, }, 'webview_ui_instrumentation_tests': { @@ -5599,40 +5577,10 @@ 'android_ddready_vr_gtests', ], - 'android_11_emulator_gtests': [ - 'android_emulator_specific_chrome_public_tests', - 'android_monochrome_smoke_tests', - 'android_smoke_tests', - 'android_specific_chromium_gtests', # Already includes gl_gtests. - 'chromium_gtests', - 'chromium_gtests_for_devices_with_graphical_output', - 'linux_flavor_specific_chromium_gtests', - 'system_webview_shell_instrumentation_tests', # Not an experimental test - 'weblayer_android_gtests', - 'weblayer_gtests', - 'webview_trichrome_cts_tests_gtest', - 'webview_ui_instrumentation_tests', - ], - 'android_12_dbg_emulator_gtests': [ 'android_trichrome_smoke_tests', ], - 'android_12_emulator_gtests': [ - 'android_emulator_specific_chrome_public_tests', - 'android_monochrome_smoke_tests', - 'android_smoke_tests', - 'android_specific_chromium_gtests', # Already includes gl_gtests. - 'chromium_gtests', - 'chromium_gtests_for_devices_with_graphical_output', - 'linux_flavor_specific_chromium_gtests', - 'system_webview_shell_instrumentation_tests', # Not an experimental test - 'weblayer_android_gtests', - 'weblayer_gtests', - 'webview_trichrome_64_cts_tests_gtest', - 'webview_ui_instrumentation_tests', - ], - # This is the same as 'android_marshmallow_gtests' # with the addition of 'webview_cts_tests_gtest' and # 'webview_ui_instrumentation_tests' @@ -6701,6 +6649,46 @@ 'matrix_compound_suites': { + 'android_11_emulator_gtests': { + 'android_emulator_specific_chrome_public_tests': {}, + 'android_monochrome_smoke_tests': {}, + 'android_smoke_tests': {}, + 'android_specific_chromium_gtests': {}, # Already includes gl_gtests. + 'chromium_gtests': {}, + 'chromium_gtests_for_devices_with_graphical_output': {}, + 'linux_flavor_specific_chromium_gtests': {}, + 'system_webview_shell_instrumentation_tests': {}, # Not an experimental test + 'weblayer_android_gtests': {}, + 'weblayer_gtests': {}, + 'webview_trichrome_cts_tests': { + 'variants': [ + 'WEBVIEW_TRICHROME_FULL_CTS_TESTS', + 'WEBVIEW_TRICHROME_INSTANT_CTS_TESTS', + ] + }, + 'webview_ui_instrumentation_tests': {}, + }, + + 'android_12_emulator_gtests': { + 'android_emulator_specific_chrome_public_tests': {}, + 'android_monochrome_smoke_tests': {}, + 'android_smoke_tests': {}, + 'android_specific_chromium_gtests': {}, # Already includes gl_gtests. + 'chromium_gtests': {}, + 'chromium_gtests_for_devices_with_graphical_output': {}, + 'linux_flavor_specific_chromium_gtests': {}, + 'system_webview_shell_instrumentation_tests': {}, # Not an experimental test + 'weblayer_android_gtests': {}, + 'weblayer_gtests': {}, + 'webview_trichrome_64_cts_tests': { + 'variants': [ + 'WEBVIEW_TRICHROME_FULL_CTS_TESTS', + 'WEBVIEW_TRICHROME_INSTANT_CTS_TESTS', + ] + }, + 'webview_ui_instrumentation_tests': {}, + }, + 'android_weblayer_x86_10_gtests': { 'weblayer_instrumentation_tests': { 'variants': [ @@ -7591,6 +7579,15 @@ }, }, + 'webview_trichrome_10_cts_tests_gtest': { + 'webview_trichrome_cts_tests': { + 'variants': [ + 'WEBVIEW_TRICHROME_FULL_CTS_TESTS', + 'WEBVIEW_TRICHROME_INSTANT_CTS_TESTS', + ] + } + }, + 'win_optional_gpu_tests_rel_gpu_telemetry_tests': { 'gpu_common_and_optional_telemetry_tests': { 'variants': [
diff --git a/testing/buildbot/variants.pyl b/testing/buildbot/variants.pyl index 8497fbe..864399af 100644 --- a/testing/buildbot/variants.pyl +++ b/testing/buildbot/variants.pyl
@@ -460,18 +460,48 @@ 'ios_runtime_cache_16_0', ], }, + 'WEBVIEW_TRICHROME_FULL_CTS_TESTS': { + 'identifier': 'full_mode', + 'swarming': { + 'cipd_packages': [ + { + 'cipd_package': 'chromium/android_webview/tools/cts_archive', + 'location': 'android_webview/tools/cts_archive', + 'revision': 'qF6dhyFMW7qFOzHo_Lu-bWxpbe-zRfL1KvHPQtQA3d0C', + } + ] + }, + }, + 'WEBVIEW_TRICHROME_INSTANT_CTS_TESTS': { + 'identifier': 'instant_mode', + 'swarming': { + 'cipd_packages': [ + { + 'cipd_package': 'chromium/android_webview/tools/cts_archive', + 'location': 'android_webview/tools/cts_archive', + 'revision': 'qF6dhyFMW7qFOzHo_Lu-bWxpbe-zRfL1KvHPQtQA3d0C', + } + ] + }, + 'args': [ + '--exclude-annotation', + 'AppModeFull', + '--test-apk-as-instant', + ], + 'test': 'webview_trichrome_cts_tests', + }, 'WEBLAYER_10_AND_M_IMPL_SKEW_TESTS_NTH_MILESTONE': { 'args': [ - '--webview-apk-path=apks/AOSP_SystemWebView.apk', '--test-runner-outdir', '.', '--client-outdir', '.', - '--implementation-outdir', - '../../weblayer_instrumentation_test_M104/out/Release', '--test-expectations', '../../weblayer/browser/android/javatests/skew/expectations.txt', - '--impl-version=104', + '--webview-apk-path=apks/AOSP_SystemWebView.apk', + '--implementation-outdir', + '../../weblayer_instrumentation_test_M104/out/Release', + '--impl-version=104' ], 'identifier': 'with_impl_from_104', 'swarming': { @@ -479,23 +509,23 @@ { 'cipd_package': 'chromium/testing/weblayer-x86', 'location': 'weblayer_instrumentation_test_M104', - 'revision': 'version:104.0.5112.8', + 'revision': 'version:104.0.5112.8' } - ], - }, + ] + } }, 'WEBLAYER_10_AND_M_IMPL_SKEW_TESTS_NTH_MINUS_ONE_MILESTONE': { 'args': [ - '--webview-apk-path=apks/AOSP_SystemWebView.apk', '--test-runner-outdir', '.', '--client-outdir', '.', - '--implementation-outdir', - '../../weblayer_instrumentation_test_M103/out/Release', '--test-expectations', '../../weblayer/browser/android/javatests/skew/expectations.txt', - '--impl-version=103', + '--webview-apk-path=apks/AOSP_SystemWebView.apk', + '--implementation-outdir', + '../../weblayer_instrumentation_test_M103/out/Release', + '--impl-version=103' ], 'identifier': 'with_impl_from_103', 'swarming': { @@ -503,10 +533,10 @@ { 'cipd_package': 'chromium/testing/weblayer-x86', 'location': 'weblayer_instrumentation_test_M103', - 'revision': 'version:103.0.5060.52', + 'revision': 'version:103.0.5060.53' } - ], - }, + ] + } }, 'WEBLAYER_10_AND_M_IMPL_SKEW_TESTS_NTH_MINUS_TWO_MILESTONE': { 'args': [ @@ -606,16 +636,16 @@ }, 'WEBLAYER_IMPL_SKEW_TESTS_NTH_MILESTONE': { 'args': [ - '--webview-apk-path=apks/SystemWebView.apk', '--test-runner-outdir', '.', '--client-outdir', '.', - '--implementation-outdir', - '../../weblayer_instrumentation_test_M104/out/Release', '--test-expectations', '../../weblayer/browser/android/javatests/skew/expectations.txt', - '--impl-version=104', + '--webview-apk-path=apks/SystemWebView.apk', + '--implementation-outdir', + '../../weblayer_instrumentation_test_M104/out/Release', + '--impl-version=104' ], 'identifier': 'with_impl_from_104', 'swarming': { @@ -623,23 +653,23 @@ { 'cipd_package': 'chromium/testing/weblayer-x86', 'location': 'weblayer_instrumentation_test_M104', - 'revision': 'version:104.0.5112.8', + 'revision': 'version:104.0.5112.8' } - ], - }, + ] + } }, 'WEBLAYER_IMPL_SKEW_TESTS_NTH_MINUS_ONE_MILESTONE': { 'args': [ - '--webview-apk-path=apks/SystemWebView.apk', '--test-runner-outdir', '.', '--client-outdir', '.', - '--implementation-outdir', - '../../weblayer_instrumentation_test_M103/out/Release', '--test-expectations', '../../weblayer/browser/android/javatests/skew/expectations.txt', - '--impl-version=103', + '--webview-apk-path=apks/SystemWebView.apk', + '--implementation-outdir', + '../../weblayer_instrumentation_test_M103/out/Release', + '--impl-version=103' ], 'identifier': 'with_impl_from_103', 'swarming': { @@ -647,10 +677,10 @@ { 'cipd_package': 'chromium/testing/weblayer-x86', 'location': 'weblayer_instrumentation_test_M103', - 'revision': 'version:103.0.5060.52', + 'revision': 'version:103.0.5060.53' } - ], - }, + ] + } }, 'WEBLAYER_IMPL_SKEW_TESTS_NTH_MINUS_TWO_MILESTONE': { 'args': [ @@ -750,16 +780,16 @@ }, 'WEBLAYER_CLIENT_SKEW_TESTS_NTH_MILESTONE': { 'args': [ - '--webview-apk-path=apks/SystemWebView.apk', '--test-runner-outdir', '.', - '--client-outdir', - '../../weblayer_instrumentation_test_M104/out/Release', '--implementation-outdir', '.', '--test-expectations', '../../weblayer/browser/android/javatests/skew/expectations.txt', - '--client-version=104', + '--webview-apk-path=apks/SystemWebView.apk', + '--client-outdir', + '../../weblayer_instrumentation_test_M104/out/Release', + '--client-version=104' ], 'identifier': 'with_client_from_104', 'swarming': { @@ -767,23 +797,23 @@ { 'cipd_package': 'chromium/testing/weblayer-x86', 'location': 'weblayer_instrumentation_test_M104', - 'revision': 'version:104.0.5112.8', + 'revision': 'version:104.0.5112.8' } - ], - }, + ] + } }, 'WEBLAYER_CLIENT_SKEW_TESTS_NTH_MINUS_ONE_MILESTONE': { 'args': [ - '--webview-apk-path=apks/SystemWebView.apk', '--test-runner-outdir', '.', - '--client-outdir', - '../../weblayer_instrumentation_test_M103/out/Release', '--implementation-outdir', '.', '--test-expectations', '../../weblayer/browser/android/javatests/skew/expectations.txt', - '--client-version=103', + '--webview-apk-path=apks/SystemWebView.apk', + '--client-outdir', + '../../weblayer_instrumentation_test_M103/out/Release', + '--client-version=103' ], 'identifier': 'with_client_from_103', 'swarming': { @@ -791,10 +821,10 @@ { 'cipd_package': 'chromium/testing/weblayer-x86', 'location': 'weblayer_instrumentation_test_M103', - 'revision': 'version:103.0.5060.52', + 'revision': 'version:103.0.5060.53' } - ], - }, + ] + } }, 'WEBLAYER_CLIENT_SKEW_TESTS_NTH_MINUS_TWO_MILESTONE': { 'args': [
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl index 89505c16..9b56e1a 100644 --- a/testing/buildbot/waterfalls.pyl +++ b/testing/buildbot/waterfalls.pyl
@@ -1104,7 +1104,7 @@ ], 'os_type': 'android', 'test_suites': { - 'gtest_tests': 'webview_trichrome_cts_tests_gtest', + 'gtest_tests': 'webview_trichrome_10_cts_tests_gtest', }, 'use_swarming': True, },
diff --git a/third_party/blink/renderer/core/html/forms/resources/calendar_picker.js b/third_party/blink/renderer/core/html/forms/resources/calendar_picker.js index 371591d..bc92bd5 100644 --- a/third_party/blink/renderer/core/html/forms/resources/calendar_picker.js +++ b/third_party/blink/renderer/core/html/forms/resources/calendar_picker.js
@@ -1525,6 +1525,8 @@ this._onWindowTouchMoveBound = this.onWindowTouchMove.bind(this); this._onWindowTouchEndBound = this.onWindowTouchEnd.bind(this); + this._onFlingGestureAnimatorStepBound = + this.onFlingGestureAnimatorStep.bind(this); this.element.addEventListener( 'mousewheel', this.onMouseWheel.bind(this), false); @@ -1580,7 +1582,7 @@ if (Math.abs(this._lastTouchVelocity) > 0.01) { this._scrollAnimator = new FlingGestureAnimator( this._lastTouchVelocity, this._contentOffset); - this._scrollAnimator.step = this.onFlingGestureAnimatorStep; + this._scrollAnimator.step = this._onFlingGestureAnimatorStepBound; this._scrollAnimator.start(); } window.removeEventListener('touchmove', this._onWindowTouchMoveBound);
diff --git a/third_party/blink/renderer/core/layout/list_marker.cc b/third_party/blink/renderer/core/layout/list_marker.cc index 7f2b47e..47b82da 100644 --- a/third_party/blink/renderer/core/layout/list_marker.cc +++ b/third_party/blink/renderer/core/layout/list_marker.cc
@@ -404,7 +404,7 @@ margin_start = -marker_inline_size; } } - DCHECK_EQ(margin_start + margin_end, -marker_inline_size); + DCHECK_EQ(-margin_start - margin_end, marker_inline_size); return {margin_start, margin_end}; }
diff --git a/third_party/blink/renderer/core/layout/list_marker_test.cc b/third_party/blink/renderer/core/layout/list_marker_test.cc index b2cf869..de9c4569 100644 --- a/third_party/blink/renderer/core/layout/list_marker_test.cc +++ b/third_party/blink/renderer/core/layout/list_marker_test.cc
@@ -321,4 +321,23 @@ ListMarker::WidthOfSymbol(target_layout_object.StyleRef())); } +// crbug.com/1310599 +TEST_F(ListMarkerTest, InlineMarginsForOutside) { + GetDocument().body()->setInnerHTML( + R"HTML(<details open><summary id="target" style=" + font-size: 536870912px; + zoom: 65536; + list-style-position: outside; + ">foo</summary></details>)HTML", + ASSERT_NO_EXCEPTION); + GetDocument().UpdateStyleAndLayoutTree(); + auto* item_object = GetLayoutObjectByElementId("target"); + auto* marker_object = ListMarker::MarkerFromListItem(item_object); + auto [start, end] = ListMarker::InlineMarginsForOutside( + GetDocument(), marker_object->StyleRef(), item_object->StyleRef(), + LayoutUnit::Max()); + EXPECT_EQ(LayoutUnit::Min(), start); + EXPECT_EQ(LayoutUnit(), end); +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/paint/paint_layer.cc b/third_party/blink/renderer/core/paint/paint_layer.cc index b1e066e2..8d20b85 100644 --- a/third_party/blink/renderer/core/paint/paint_layer.cc +++ b/third_party/blink/renderer/core/paint/paint_layer.cc
@@ -1211,21 +1211,6 @@ const auto& first_root_fragment_data = root_layer->GetLayoutObject().FirstFragment(); - // If both |this| and |root_layer| are fragmented and are inside the same - // pagination container, then try to match fragments from |root_layer| to - // |this|, so that any fragment clip for |root_layer|'s fragment matches - // |this|'s. Note we check both EnclosingPaginationLayer() and next - // fragment here because the former may return false even if |this| is - // fragmented, e.g. for fixed-position objects in paged media, and the next - // fragment can be null even if the first fragment is actually in a fragmented - // context when the current layer appears in only one of the multiple - // fragments of the pagination container. - bool is_fragmented = - EnclosingPaginationLayer() || first_fragment_data.NextFragment(); - bool should_match_fragments = - is_fragmented && - root_layer->EnclosingPaginationLayer() == EnclosingPaginationLayer(); - const LayoutBox* layout_box_with_fragments = GetLayoutBoxWithBlockFragments(); // The inherited offset_from_root does not include any pagination offsets. @@ -1245,24 +1230,10 @@ root_fragment_data = root_fragment_arg; } else if (root_layer == this) { root_fragment_data = fragment_data; - } else if (should_match_fragments) { - for (root_fragment_data = &first_root_fragment_data; root_fragment_data; - root_fragment_data = root_fragment_data->NextFragment()) { - if (root_fragment_data->FragmentID() == fragment_data->FragmentID()) - break; - } } else { root_fragment_data = &first_root_fragment_data; } - bool cant_find_fragment = !root_fragment_data; - if (cant_find_fragment) { - DCHECK(should_match_fragments); - // Fall back to the first fragment, in order to have - // PaintLayerClipper at least compute |fragment.layer_bounds|. - root_fragment_data = &first_root_fragment_data; - } - ClipRectsContext clip_rects_context( root_layer, root_fragment_data, kExcludeOverlayScrollbarSizeForHitTesting, respect_overflow_clip, @@ -1273,13 +1244,6 @@ fragment.layer_offset, fragment.background_rect, fragment.foreground_rect); - if (cant_find_fragment) { - // If we couldn't find a matching fragment when |should_match_fragments| - // was true, then fall back to no clip. - fragment.background_rect.Reset(); - fragment.foreground_rect.Reset(); - } - fragment.fragment_data = fragment_data; if (layout_box_with_fragments) {
diff --git a/third_party/blink/renderer/modules/mediastream/browser_capture_media_stream_track.cc b/third_party/blink/renderer/modules/mediastream/browser_capture_media_stream_track.cc index 5fb6a90c..4f0edb2 100644 --- a/third_party/blink/renderer/modules/mediastream/browser_capture_media_stream_track.cc +++ b/third_party/blink/renderer/modules/mediastream/browser_capture_media_stream_track.cc
@@ -183,54 +183,34 @@ return promise; } - MediaStreamComponent* const component = Component(); - DCHECK(component); - - MediaStreamSource* const source = component->Source(); - DCHECK(component->Source()); // We don't currently instantiate BrowserCaptureMediaStreamTrack for audio // tracks. If we do in the future, we'll have to raise an exception if // cropTo() is called on a non-video track. + DCHECK(Component()); + DCHECK(Component()->Source()); + MediaStreamSource* const source = Component()->Source(); DCHECK_EQ(source->GetType(), MediaStreamSource::kTypeVideo); - MediaStreamVideoSource* const native_source = MediaStreamVideoSource::GetVideoSource(source); - MediaStreamTrackPlatform* const native_track = - MediaStreamTrackPlatform::GetTrack(WebMediaStreamTrack(component)); - if (!native_source || !native_track) { - // TODO(crbug.com/1266378): Use dedicate UMA values. - RecordUma(CropToResult::kRejectedWithErrorGeneric); - resolver->Reject(MakeGarbageCollected<DOMException>( - DOMExceptionCode::kUnknownError, "Native/platform track missing.")); - return promise; - } + DCHECK(native_source); // TODO(crbug.com/1332628): Instead of using GetNextCropVersion(), move the // ownership of the Promises from this->pending_promises_ into native_source. - const absl::optional<uint32_t> optional_crop_version = + const absl::optional<uint32_t> crop_version = native_source->GetNextCropVersion(); - if (!optional_crop_version.has_value()) { + if (!crop_version.has_value()) { resolver->Reject(MakeGarbageCollected<DOMException>( DOMExceptionCode::kOperationError, "Can't change crop-target while clones exist.")); return promise; } - const uint32_t crop_version = optional_crop_version.value(); - pending_promises_.Set(crop_version, - MakeGarbageCollected<CropPromiseInfo>(resolver)); - - // Register for a one-off notification when the first frame cropped - // to the new crop-target is observed. - native_track->AddCropVersionCallback( - crop_version, - WTF::Bind(&BrowserCaptureMediaStreamTrack::OnCropVersionObserved, - WrapWeakPersistent(this), crop_version)); + pending_promises_.Set(crop_version.value(), resolver); native_source->Crop( - crop_id_token.value(), crop_version, - WTF::Bind(&BrowserCaptureMediaStreamTrack::OnResultFromBrowserProcess, - WrapWeakPersistent(this), crop_version)); + crop_id_token.value(), crop_version.value(), + WTF::Bind(&BrowserCaptureMediaStreamTrack::ResolveCropPromise, + WrapPersistent(this), crop_version.value())); return promise; #endif @@ -252,74 +232,15 @@ } #if !BUILDFLAG(IS_ANDROID) -void BrowserCaptureMediaStreamTrack::OnResultFromBrowserProcess( +void BrowserCaptureMediaStreamTrack::ResolveCropPromise( uint32_t crop_version, media::mojom::CropRequestResult result) { - DCHECK(IsMainThread()); - DCHECK_GT(crop_version, 0u); - - const auto iter = pending_promises_.find(crop_version); - if (iter == pending_promises_.end()) { + const auto promise_it = pending_promises_.find(crop_version); + if (promise_it == pending_promises_.end()) { return; } - CropPromiseInfo* const info = iter->value; - - DCHECK(!info->crop_result.has_value()) << "Invoked twice."; - info->crop_result = result; - - MaybeFinalizeCropPromise(iter); -} - -void BrowserCaptureMediaStreamTrack::OnCropVersionObserved( - uint32_t crop_version) { - DCHECK(IsMainThread()); - DCHECK_GT(crop_version, 0u); - - const auto iter = pending_promises_.find(crop_version); - if (iter == pending_promises_.end()) { - return; - } - CropPromiseInfo* const info = iter->value; - - DCHECK(!info->crop_version_observed) << "Invoked twice."; - info->crop_version_observed = true; - - MaybeFinalizeCropPromise(iter); -} - -void BrowserCaptureMediaStreamTrack::MaybeFinalizeCropPromise( - BrowserCaptureMediaStreamTrack::PromiseMapIterator iter) { - DCHECK(IsMainThread()); - DCHECK_NE(iter, pending_promises_.end()); - - CropPromiseInfo* const info = iter->value; - - if (!info->crop_result.has_value()) { - return; - } - - const media::mojom::CropRequestResult result = info->crop_result.value(); - - // Failure can be reported immediately, but success is only reported once - // the new crop-version is observed. - if (result == media::mojom::CropRequestResult::kSuccess && - !info->crop_version_observed) { - return; - } - - // When `result == kSuccess`, the callback will be removed by the track - // itself as it invokes it. For failure, we remove the callback immediately, - // since there's no need to wait. - if (result != media::mojom::CropRequestResult::kSuccess) { - MediaStreamTrackPlatform* const native_track = - MediaStreamTrackPlatform::GetTrack(WebMediaStreamTrack(Component())); - if (native_track) { - native_track->RemoveCropVersionCallback(iter->key); - } - } - - ScriptPromiseResolver* const resolver = info->promise_resolver; - pending_promises_.erase(iter); + ScriptPromiseResolver* const resolver = promise_it->value; + pending_promises_.erase(promise_it); ResolveCropPromiseHelper(resolver, result); } #endif // !BUILDFLAG(IS_ANDROID)
diff --git a/third_party/blink/renderer/modules/mediastream/browser_capture_media_stream_track.h b/third_party/blink/renderer/modules/mediastream/browser_capture_media_stream_track.h index 452d86a..05021fa 100644 --- a/third_party/blink/renderer/modules/mediastream/browser_capture_media_stream_track.h +++ b/third_party/blink/renderer/modules/mediastream/browser_capture_media_stream_track.h
@@ -5,7 +5,6 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASTREAM_BROWSER_CAPTURE_MEDIA_STREAM_TRACK_H_ #define THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASTREAM_BROWSER_CAPTURE_MEDIA_STREAM_TRACK_H_ -#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h" #include "third_party/blink/renderer/core/dom/dom_exception.h" #include "third_party/blink/renderer/modules/mediastream/crop_target.h" #include "third_party/blink/renderer/modules/mediastream/focusable_media_stream_track.h" @@ -32,16 +31,8 @@ const String& descriptor_id, bool is_clone = false); - ~BrowserCaptureMediaStreamTrack() override = default; - #if !BUILDFLAG(IS_ANDROID) void Trace(Visitor*) const override; - - // Allows tests to invoke OnCropVersionObserved() directly, since triggering - // it via mocks would be prohibitively difficult. - void OnCropVersionObservedForTesting(uint32_t crop_version) { - OnCropVersionObserved(crop_version); - } #endif ScriptPromise cropTo(ScriptState*, CropTarget*, ExceptionState&); @@ -50,48 +41,9 @@ private: #if !BUILDFLAG(IS_ANDROID) - struct CropPromiseInfo : GarbageCollected<CropPromiseInfo> { - explicit CropPromiseInfo(ScriptPromiseResolver* promise_resolver) - : promise_resolver(promise_resolver) {} - - void Trace(Visitor* visitor) const { visitor->Trace(promise_resolver); } - - const Member<ScriptPromiseResolver> promise_resolver; - absl::optional<media::mojom::CropRequestResult> crop_result; - bool crop_version_observed = false; - }; - - using CropVersionToPromiseInfoMap = - HeapHashMap<uint32_t, - Member<BrowserCaptureMediaStreamTrack::CropPromiseInfo>>; - using PromiseMapIterator = CropVersionToPromiseInfoMap::iterator; - - // Each cropTo() call is associated with a unique |crop_version| which - // identifies this specific cropTo() invocation. When the browser process - // responds with the result of the cropTo() invocation, it triggers - // a call to OnResultFromBrowserProcess() with that |crop_version|. - void OnResultFromBrowserProcess(uint32_t crop_version, - media::mojom::CropRequestResult result); - - // OnCropVersionObserved() is posted as a callback, bound to a unique - // |crop_version|. This callback be invoked when the first frame is observed - // which is associated with that |crop_version|. - // TODO(crbug.com/1266378): The Promise should also be resolved if a - // a barrier event is observed. (That is, although no frame is delivered, - // there is a guarantee that all future frames will be of this version - // or later. This would happen if cropping a muted track, for instance.) - void OnCropVersionObserved(uint32_t crop_version); - - // The Promise that cropTo() issued is resolved when both conditions - // are fulfulled: - // 1. OnResultFromBrowserProcess(kSuccess) called. - // 2. OnCropVersionObserved() called for the associated |crop_version|. - // - // The order of fulfillment does not matter. - // - // The Promise is rejected if OnResultFromBrowserProcess() is called with - // an error value. - void MaybeFinalizeCropPromise(PromiseMapIterator iter); + // Resolves the Promise associated with |crop_version|. + void ResolveCropPromise(uint32_t crop_version, + media::mojom::CropRequestResult result); // Each time cropTo() is called on a given track, its crop version increments. // Associate each Promise with its crop version, so that Viz can easily stamp @@ -102,7 +54,7 @@ // // Note that frames before the first call to cropTo() will be associated // with a version of 0, both here and in Viz. - HeapHashMap<uint32_t, Member<CropPromiseInfo>> pending_promises_; + HeapHashMap<uint32_t, Member<ScriptPromiseResolver>> pending_promises_; #endif // !BUILDFLAG(IS_ANDROID) };
diff --git a/third_party/blink/renderer/modules/mediastream/browser_capture_media_stream_track_test.cc b/third_party/blink/renderer/modules/mediastream/browser_capture_media_stream_track_test.cc index abb11de..1d49522 100644 --- a/third_party/blink/renderer/modules/mediastream/browser_capture_media_stream_track_test.cc +++ b/third_party/blink/renderer/modules/mediastream/browser_capture_media_stream_track_test.cc
@@ -8,22 +8,16 @@ #include "build/build_config.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/public/web/web_heap.h" -#include "third_party/blink/renderer/bindings/core/v8/script_promise_tester.h" #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h" #include "third_party/blink/renderer/modules/mediastream/crop_target.h" -#include "third_party/blink/renderer/modules/mediastream/media_stream_video_track.h" #include "third_party/blink/renderer/modules/mediastream/mock_media_stream_video_source.h" #include "third_party/blink/renderer/platform/region_capture_crop_id.h" -#include "third_party/blink/renderer/platform/testing/io_task_runner_testing_platform_support.h" namespace blink { namespace { using ::testing::_; -using ::testing::Args; -using ::testing::Invoke; -using ::testing::Mock; using ::testing::Return; std::unique_ptr<MockMediaStreamVideoSource> MakeMockMediaStreamVideoSource() { @@ -36,18 +30,12 @@ BrowserCaptureMediaStreamTrack* MakeTrack( V8TestingScope& v8_scope, std::unique_ptr<MockMediaStreamVideoSource> media_stream_video_source) { - auto media_stream_video_track = std::make_unique<MediaStreamVideoTrack>( - media_stream_video_source.get(), - WebPlatformMediaStreamSource::ConstraintsOnceCallback(), - /*enabled=*/true); - MediaStreamSource* const source = MakeGarbageCollected<MediaStreamSource>( "id", MediaStreamSource::StreamType::kTypeVideo, "name", /*remote=*/false, std::move(media_stream_video_source)); MediaStreamComponent* const component = - MakeGarbageCollected<MediaStreamComponent>( - "component_id", source, std::move(media_stream_video_track)); + MakeGarbageCollected<MediaStreamComponent>(source); return MakeGarbageCollected<BrowserCaptureMediaStreamTrack>( v8_scope.GetExecutionContext(), component, /*callback=*/base::DoNothing(), @@ -58,16 +46,13 @@ class BrowserCaptureMediaStreamTrackTest : public testing::Test { public: - ~BrowserCaptureMediaStreamTrackTest() override = default; - - void TearDown() override { WebHeap::CollectAllGarbageForTesting(); } - - protected: - ScopedTestingPlatformSupport<IOTaskRunnerTestingPlatformSupport> platform_; + ~BrowserCaptureMediaStreamTrackTest() override { + WebHeap::CollectAllGarbageForTesting(); + } }; #if !BUILDFLAG(IS_ANDROID) -TEST_F(BrowserCaptureMediaStreamTrackTest, CropToOnValidIdResultFirst) { +TEST_F(BrowserCaptureMediaStreamTrackTest, CropToOnValidId) { V8TestingScope v8_scope; const base::GUID valid_id = base::GUID::GenerateRandomV4(); @@ -80,11 +65,7 @@ .WillOnce(Return(absl::optional<uint32_t>(1))); EXPECT_CALL(*media_stream_video_source, Crop(GUIDToToken(valid_id), _, _)) - .Times(1) - .WillOnce(::testing::WithArg<2>(::testing::Invoke( - [](base::OnceCallback<void(media::mojom::CropRequestResult)> cb) { - std::move(cb).Run(media::mojom::CropRequestResult::kSuccess); - }))); + .Times(1); BrowserCaptureMediaStreamTrack* const track = MakeTrack(v8_scope, std::move(media_stream_video_source)); @@ -94,78 +75,6 @@ MakeGarbageCollected<CropTarget>( WTF::String(valid_id.AsLowercaseString())), v8_scope.GetExceptionState()); - - track->OnCropVersionObservedForTesting(/*crop_version=*/1); - - ScriptPromiseTester script_promise_tester(v8_scope.GetScriptState(), promise); - script_promise_tester.WaitUntilSettled(); - EXPECT_TRUE(script_promise_tester.IsFulfilled()); -} - -TEST_F(BrowserCaptureMediaStreamTrackTest, - CropToRejectsIfResultFromBrowserProcessIsNotSuccess) { - V8TestingScope v8_scope; - - const base::GUID valid_id = base::GUID::GenerateRandomV4(); - - std::unique_ptr<MockMediaStreamVideoSource> media_stream_video_source = - MakeMockMediaStreamVideoSource(); - - EXPECT_CALL(*media_stream_video_source, GetNextCropVersion) - .Times(1) - .WillOnce(Return(absl::optional<uint32_t>(1))); - - EXPECT_CALL(*media_stream_video_source, Crop(GUIDToToken(valid_id), _, _)) - .Times(1) - .WillOnce(::testing::WithArg<2>(::testing::Invoke( - [](base::OnceCallback<void(media::mojom::CropRequestResult)> cb) { - std::move(cb).Run(media::mojom::CropRequestResult::kErrorGeneric); - }))); - - BrowserCaptureMediaStreamTrack* const track = - MakeTrack(v8_scope, std::move(media_stream_video_source)); - - const ScriptPromise promise = - track->cropTo(v8_scope.GetScriptState(), - MakeGarbageCollected<CropTarget>( - WTF::String(valid_id.AsLowercaseString())), - v8_scope.GetExceptionState()); - - track->OnCropVersionObservedForTesting(/*crop_version=*/1); - - ScriptPromiseTester script_promise_tester(v8_scope.GetScriptState(), promise); - script_promise_tester.WaitUntilSettled(); - EXPECT_TRUE(script_promise_tester.IsRejected()); -} - -TEST_F(BrowserCaptureMediaStreamTrackTest, - CropToRejectsIfSourceReturnsNulloptForNextCropVersion) { - V8TestingScope v8_scope; - - const base::GUID valid_id = base::GUID::GenerateRandomV4(); - - std::unique_ptr<MockMediaStreamVideoSource> media_stream_video_source = - MakeMockMediaStreamVideoSource(); - - EXPECT_CALL(*media_stream_video_source, GetNextCropVersion) - .Times(1) - .WillOnce(Return(absl::nullopt)); - - EXPECT_CALL(*media_stream_video_source, Crop(GUIDToToken(valid_id), _, _)) - .Times(0); - - BrowserCaptureMediaStreamTrack* const track = - MakeTrack(v8_scope, std::move(media_stream_video_source)); - - const ScriptPromise promise = - track->cropTo(v8_scope.GetScriptState(), - MakeGarbageCollected<CropTarget>( - WTF::String(valid_id.AsLowercaseString())), - v8_scope.GetExceptionState()); - - ScriptPromiseTester script_promise_tester(v8_scope.GetScriptState(), promise); - script_promise_tester.WaitUntilSettled(); - EXPECT_TRUE(script_promise_tester.IsRejected()); } #else @@ -188,10 +97,7 @@ MakeGarbageCollected<CropTarget>( WTF::String(valid_id.AsLowercaseString())), v8_scope.GetExceptionState()); - - ScriptPromiseTester script_promise_tester(v8_scope.GetScriptState(), promise); - script_promise_tester.WaitUntilSettled(); - EXPECT_TRUE(script_promise_tester.IsRejected()); + EXPECT_EQ(promise.V8Promise()->State(), v8::Promise::kRejected); } #endif
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_video_track.cc b/third_party/blink/renderer/modules/mediastream/media_stream_video_track.cc index 61e5294e..a48c2c6 100644 --- a/third_party/blink/renderer/modules/mediastream/media_stream_video_track.cc +++ b/third_party/blink/renderer/modules/mediastream/media_stream_video_track.cc
@@ -124,10 +124,6 @@ void SetIsRefreshingForMinFrameRate(bool is_refreshing_for_min_frame_rate); - void AddCropVersionCallback(uint32_t crop_version, - base::OnceClosure callback); - void RemoveCropVersionCallback(uint32_t crop_version); - private: friend class WTF::ThreadSafeRefCounted<FrameDeliverer>; virtual ~FrameDeliverer(); @@ -148,12 +144,6 @@ void SetIsRefreshingForMinFrameRateOnIO( bool is_refreshing_for_min_frame_rate); - void AddCropVersionCallbackOnIO(uint32_t crop_version, - WTF::CrossThreadOnceClosure callback); - void RemoveCropVersionCallbackOnIO(uint32_t crop_version); - - void MaybeInvokeNewCropVersionCallbacksOnIO(uint32_t crop_version); - // Returns a black frame where the size and time stamp is set to the same as // as in |reference_frame|. scoped_refptr<media::VideoFrame> GetBlackFrame( @@ -175,13 +165,6 @@ std::pair<VideoSinkId, VideoCaptureDeliverFrameInternalCallback>; Vector<VideoIdCallbackPair> callbacks_; HashMap<VideoSinkId, EncodedVideoFrameInternalCallback> encoded_callbacks_; - - // Callbacks that will be invoked a single time when a crop-version - // is observed that is at least equal to the key. - // The map itself (crop_version_callbacks_) is bound to the IO thread. - // The callbacks are bound to their respective threads (BindPostTask). - HashMap<uint32_t, WTF::CrossThreadOnceClosure> crop_version_callbacks_; - bool await_next_key_frame_; // This should only be accessed on the IO thread. @@ -329,76 +312,18 @@ is_refreshing_for_min_frame_rate)); } -void MediaStreamVideoTrack::FrameDeliverer::AddCropVersionCallback( - uint32_t crop_version, - base::OnceClosure callback) { - DCHECK_CALLED_ON_VALID_THREAD(main_render_thread_checker_); - - PostCrossThreadTask( - *io_task_runner_, FROM_HERE, - CrossThreadBindOnce(&FrameDeliverer::AddCropVersionCallbackOnIO, - WrapRefCounted(this), crop_version, - CrossThreadBindOnce(std::move(callback)))); -} - -void MediaStreamVideoTrack::FrameDeliverer::RemoveCropVersionCallback( - uint32_t crop_version) { - DCHECK_CALLED_ON_VALID_THREAD(main_render_thread_checker_); - - PostCrossThreadTask( - *io_task_runner_, FROM_HERE, - CrossThreadBindOnce(&FrameDeliverer::RemoveCropVersionCallbackOnIO, - WrapRefCounted(this), crop_version)); -} - void MediaStreamVideoTrack::FrameDeliverer::SetIsRefreshingForMinFrameRateOnIO( bool is_refreshing_for_min_frame_rate) { DCHECK(io_task_runner_->BelongsToCurrentThread()); is_refreshing_for_min_frame_rate_ = is_refreshing_for_min_frame_rate; } -void MediaStreamVideoTrack::FrameDeliverer::AddCropVersionCallbackOnIO( - uint32_t crop_version, - WTF::CrossThreadOnceClosure callback) { - DCHECK(io_task_runner_->BelongsToCurrentThread()); - DCHECK(!base::Contains(crop_version_callbacks_, crop_version)); - - crop_version_callbacks_.Set(crop_version, std::move(callback)); -} - -void MediaStreamVideoTrack::FrameDeliverer::RemoveCropVersionCallbackOnIO( - uint32_t crop_version) { - DCHECK(io_task_runner_->BelongsToCurrentThread()); - - // Note: Might or might not be here, depending on whether a later crop - // version has already been observed or not. - crop_version_callbacks_.erase(crop_version); -} - -void MediaStreamVideoTrack::FrameDeliverer:: - MaybeInvokeNewCropVersionCallbacksOnIO(uint32_t crop_version) { - DCHECK(io_task_runner_->BelongsToCurrentThread()); - - Vector<uint32_t> to_be_removed_keys; - for (auto& iter : crop_version_callbacks_) { - if (iter.key > crop_version) { - continue; - } - std::move(iter.value).Run(); - to_be_removed_keys.push_back(iter.key); - } - crop_version_callbacks_.RemoveAll(to_be_removed_keys); -} - void MediaStreamVideoTrack::FrameDeliverer::DeliverFrameOnIO( scoped_refptr<media::VideoFrame> frame, std::vector<scoped_refptr<media::VideoFrame>> scaled_video_frames, base::TimeTicks estimated_capture_time) { DCHECK(io_task_runner_->BelongsToCurrentThread()); - - const uint32_t crop_version = frame->metadata().crop_version; - - if (!enabled_ && main_render_task_runner_ && emit_frame_drop_events_) { + if (!enabled_ && emit_frame_drop_events_) { emit_frame_drop_events_ = false; // TODO(crbug.com/964947): A weak ptr instance of MediaStreamVideoTrack is @@ -434,8 +359,6 @@ CrossThreadBindOnce(&MediaStreamVideoTrack::ResetRefreshTimer, media_stream_video_track_)); } - - MaybeInvokeNewCropVersionCallbacksOnIO(crop_version); } void MediaStreamVideoTrack::FrameDeliverer::DeliverEncodedVideoFrameOnIO( @@ -820,21 +743,6 @@ return capture_handle; } -void MediaStreamVideoTrack::AddCropVersionCallback(uint32_t crop_version, - base::OnceClosure callback) { - DCHECK_CALLED_ON_VALID_THREAD(main_render_thread_checker_); - - frame_deliverer_->AddCropVersionCallback( - crop_version, base::BindPostTask(base::ThreadTaskRunnerHandle::Get(), - std::move(callback))); -} - -void MediaStreamVideoTrack::RemoveCropVersionCallback(uint32_t crop_version) { - DCHECK_CALLED_ON_VALID_THREAD(main_render_thread_checker_); - - frame_deliverer_->RemoveCropVersionCallback(crop_version); -} - void MediaStreamVideoTrack::OnReadyStateChanged( WebMediaStreamSource::ReadyState state) { DCHECK_CALLED_ON_VALID_THREAD(main_render_thread_checker_);
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_video_track.h b/third_party/blink/renderer/modules/mediastream/media_stream_video_track.h index 414b90f..44b96b4 100644 --- a/third_party/blink/renderer/modules/mediastream/media_stream_video_track.h +++ b/third_party/blink/renderer/modules/mediastream/media_stream_video_track.h
@@ -88,9 +88,6 @@ void StopAndNotify(base::OnceClosure callback) override; void GetSettings(MediaStreamTrackPlatform::Settings& settings) override; MediaStreamTrackPlatform::CaptureHandle GetCaptureHandle() override; - void AddCropVersionCallback(uint32_t crop_version, - base::OnceClosure callback) override; - void RemoveCropVersionCallback(uint32_t crop_version) override; // Add |sink| to receive state changes on the main render thread and video // frames in the |callback| method on the IO-thread.
diff --git a/third_party/blink/renderer/modules/peerconnection/peer_connection_dependency_factory.cc b/third_party/blink/renderer/modules/peerconnection/peer_connection_dependency_factory.cc index 77a16802..cbbf6686 100644 --- a/third_party/blink/renderer/modules/peerconnection/peer_connection_dependency_factory.cc +++ b/third_party/blink/renderer/modules/peerconnection/peer_connection_dependency_factory.cc
@@ -74,7 +74,6 @@ #include "third_party/webrtc/rtc_base/ref_counted_object.h" #include "third_party/webrtc/rtc_base/ssl_adapter.h" #include "third_party/webrtc_overrides/metronome_task_queue_factory.h" -#include "third_party/webrtc_overrides/task_queue_factory.h" namespace WTF { template <> @@ -648,10 +647,7 @@ GetWorkerThread() ? GetWorkerThread() : GetSignalingThread(); pcf_deps.signaling_thread = GetSignalingThread(); pcf_deps.network_thread = GetNetworkThread(); - pcf_deps.task_queue_factory = - !base::FeatureList::IsEnabled(kWebRtcMetronomeTaskQueue) - ? CreateWebRtcTaskQueueFactory() - : CreateWebRtcMetronomeTaskQueueFactory(); + pcf_deps.task_queue_factory = CreateWebRtcMetronomeTaskQueueFactory(); DCHECK(metronome_source_); pcf_deps.metronome = metronome_source_->CreateWebRtcMetronome(); pcf_deps.call_factory = webrtc::CreateCallFactory();
diff --git a/third_party/blink/renderer/modules/peerconnection/webrtc_audio_renderer_test.cc b/third_party/blink/renderer/modules/peerconnection/webrtc_audio_renderer_test.cc index fef8283c..860bf95 100644 --- a/third_party/blink/renderer/modules/peerconnection/webrtc_audio_renderer_test.cc +++ b/third_party/blink/renderer/modules/peerconnection/webrtc_audio_renderer_test.cc
@@ -115,14 +115,7 @@ } // namespace -// Flaky on TSAN. See https://crbug.com/1127211 -// Flaky with CFI. See https://crbug.com/1294176 -#if defined(THREAD_SANITIZER) || BUILDFLAG(CFI_CAST_CHECK) -#define MAYBE_WebRtcAudioRendererTest DISABLED_WebRtcAudioRendererTest -#else -#define MAYBE_WebRtcAudioRendererTest WebRtcAudioRendererTest -#endif -class MAYBE_WebRtcAudioRendererTest : public testing::Test { +class WebRtcAudioRendererTest : public testing::Test { public: MOCK_METHOD1(MockSwitchDeviceCallback, void(media::OutputDeviceStatus)); void SwitchDeviceCallback(base::RunLoop* loop, @@ -132,7 +125,7 @@ } protected: - MAYBE_WebRtcAudioRendererTest() + WebRtcAudioRendererTest() : source_(new MockAudioRendererSource()) // Tests crash on Android if these are defined. https://crbug.com/1119689 #if !BUILDFLAG(IS_ANDROID) @@ -240,7 +233,7 @@ }; // Verify that the renderer will be stopped if the only proxy is stopped. -TEST_F(MAYBE_WebRtcAudioRendererTest, DISABLED_StopRenderer) { +TEST_F(WebRtcAudioRendererTest, DISABLED_StopRenderer) { SetupRenderer(kDefaultOutputDeviceId); renderer_proxy_->Start(); @@ -253,7 +246,7 @@ // Verify that the renderer will not be stopped unless the last proxy is // stopped. -TEST_F(MAYBE_WebRtcAudioRendererTest, DISABLED_MultipleRenderers) { +TEST_F(WebRtcAudioRendererTest, DISABLED_MultipleRenderers) { SetupRenderer(kDefaultOutputDeviceId); renderer_proxy_->Start(); @@ -287,7 +280,7 @@ // Verify that the sink of the renderer is using the expected sample rate and // buffer size. -TEST_F(MAYBE_WebRtcAudioRendererTest, DISABLED_VerifySinkParameters) { +TEST_F(WebRtcAudioRendererTest, DISABLED_VerifySinkParameters) { SetupRenderer(kDefaultOutputDeviceId); renderer_proxy_->Start(); #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_MAC) || \ @@ -309,7 +302,7 @@ renderer_proxy_->Stop(); } -TEST_F(MAYBE_WebRtcAudioRendererTest, NonDefaultDevice) { +TEST_F(WebRtcAudioRendererTest, NonDefaultDevice) { SetupRenderer(kDefaultOutputDeviceId); EXPECT_EQ(kDefaultOutputDeviceId, mock_sink()->GetOutputDeviceInfo().device_id()); @@ -329,7 +322,7 @@ renderer_proxy_->Stop(); } -TEST_F(MAYBE_WebRtcAudioRendererTest, SwitchOutputDevice) { +TEST_F(WebRtcAudioRendererTest, SwitchOutputDevice) { SetupRenderer(kDefaultOutputDeviceId); EXPECT_EQ(kDefaultOutputDeviceId, mock_sink()->GetOutputDeviceInfo().device_id()); @@ -349,7 +342,7 @@ base::RunLoop loop; renderer_proxy_->SwitchOutputDevice( kOtherOutputDeviceId, - base::BindOnce(&MAYBE_WebRtcAudioRendererTest::SwitchDeviceCallback, + base::BindOnce(&WebRtcAudioRendererTest::SwitchDeviceCallback, base::Unretained(this), &loop)); loop.Run(); EXPECT_EQ(kOtherOutputDeviceId, @@ -362,7 +355,7 @@ renderer_proxy_->Stop(); } -TEST_F(MAYBE_WebRtcAudioRendererTest, SwitchOutputDeviceInvalidDevice) { +TEST_F(WebRtcAudioRendererTest, SwitchOutputDeviceInvalidDevice) { SetupRenderer(kDefaultOutputDeviceId); EXPECT_EQ(kDefaultOutputDeviceId, mock_sink()->GetOutputDeviceInfo().device_id()); @@ -379,7 +372,7 @@ base::RunLoop loop; renderer_proxy_->SwitchOutputDevice( kInvalidOutputDeviceId, - base::BindOnce(&MAYBE_WebRtcAudioRendererTest::SwitchDeviceCallback, + base::BindOnce(&WebRtcAudioRendererTest::SwitchDeviceCallback, base::Unretained(this), &loop)); loop.Run(); EXPECT_EQ(kDefaultOutputDeviceId, @@ -392,7 +385,7 @@ renderer_proxy_->Stop(); } -TEST_F(MAYBE_WebRtcAudioRendererTest, InitializeWithInvalidDevice) { +TEST_F(WebRtcAudioRendererTest, InitializeWithInvalidDevice) { renderer_ = new blink::WebRtcAudioRenderer( scheduler::GetSingleThreadTaskRunnerForTesting(), stream_descriptor_, nullptr /*blink::WebLocalFrame*/, base::UnguessableToken::Create(), @@ -416,7 +409,7 @@ mock_sink()->GetOutputDeviceInfo().device_id()); } -TEST_F(MAYBE_WebRtcAudioRendererTest, SwitchOutputDeviceStoppedSource) { +TEST_F(WebRtcAudioRendererTest, SwitchOutputDeviceStoppedSource) { SetupRenderer(kDefaultOutputDeviceId); auto* original_sink = mock_sink(); renderer_proxy_->Start(); @@ -429,7 +422,7 @@ renderer_proxy_->Stop(); renderer_proxy_->SwitchOutputDevice( kInvalidOutputDeviceId, - base::BindOnce(&MAYBE_WebRtcAudioRendererTest::SwitchDeviceCallback, + base::BindOnce(&WebRtcAudioRendererTest::SwitchDeviceCallback, base::Unretained(this), &loop)); loop.Run(); }
diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn index 61f875dd..b034c83 100644 --- a/third_party/blink/renderer/platform/BUILD.gn +++ b/third_party/blink/renderer/platform/BUILD.gn
@@ -2117,7 +2117,6 @@ "peerconnection/stats_collecting_decoder_test.cc", "peerconnection/stats_collecting_encoder_test.cc", "peerconnection/stats_collector_test.cc", - "peerconnection/task_queue_factory_test.cc", "peerconnection/two_keys_adapter_map_unittest.cc", "peerconnection/webrtc_audio_sink_test.cc", "peerconnection/webrtc_decoding_info_handler_test.cc",
diff --git a/third_party/blink/renderer/platform/fonts/font_platform_data.cc b/third_party/blink/renderer/platform/fonts/font_platform_data.cc index c6b31da..8f4c979 100644 --- a/third_party/blink/renderer/platform/fonts/font_platform_data.cc +++ b/third_party/blink/renderer/platform/fonts/font_platform_data.cc
@@ -29,6 +29,8 @@ #include "third_party/blink/public/platform/platform.h" #include "third_party/blink/renderer/platform/fonts/font_cache.h" #include "third_party/blink/renderer/platform/fonts/shaping/harfbuzz_face.h" +#include "third_party/blink/renderer/platform/fonts/shaping/harfbuzz_font_cache.h" +#include "third_party/blink/renderer/platform/fonts/shaping/harfbuzz_font_data.h" #include "third_party/blink/renderer/platform/text/character.h" #include "third_party/blink/renderer/platform/web_test_support.h" #include "third_party/blink/renderer/platform/wtf/hash_map.h" @@ -200,10 +202,14 @@ } HarfBuzzFace* FontPlatformData::GetHarfBuzzFace() const { +#if defined(USE_PARALLEL_TEXT_SHAPING) + return &harfbuzz_face_.GetOrCreate(const_cast<FontPlatformData*>(this)); +#else if (!harfbuzz_face_) harfbuzz_face_ = HarfBuzzFace::Create(const_cast<FontPlatformData*>(this)); return harfbuzz_face_.get(); +#endif } bool FontPlatformData::HasSpaceInLigaturesOrKerning( @@ -344,4 +350,22 @@ return success ? postscript_name.c_str() : String(); } +#if defined(USE_PARALLEL_TEXT_SHAPING) +// -- + +FontPlatformData::ThreadSpecificHarfBuzzFace::ThreadSpecificHarfBuzzFace() = + default; +FontPlatformData::ThreadSpecificHarfBuzzFace::~ThreadSpecificHarfBuzzFace() = + default; + +HarfBuzzFace& FontPlatformData::ThreadSpecificHarfBuzzFace::GetOrCreate( + FontPlatformData* platform_data) { + base::AutoLock guard(lock_); + const auto result = map_.insert(CurrentThread(), nullptr); + if (result.is_new_entry) + result.stored_value->value = HarfBuzzFace::Create(platform_data); + return *result.stored_value->value; +} +#endif + } // namespace blink
diff --git a/third_party/blink/renderer/platform/fonts/font_platform_data.h b/third_party/blink/renderer/platform/fonts/font_platform_data.h index 6a20a8f..37627e9 100644 --- a/third_party/blink/renderer/platform/fonts/font_platform_data.h +++ b/third_party/blink/renderer/platform/fonts/font_platform_data.h
@@ -43,6 +43,7 @@ #include "third_party/blink/renderer/platform/wtf/forward.h" #include "third_party/blink/renderer/platform/wtf/hash_table_deleted_value_type.h" #include "third_party/blink/renderer/platform/wtf/text/string_impl.h" +#include "third_party/blink/renderer/platform/wtf/threading.h" #include "third_party/blink/renderer/platform/wtf/vector.h" #include "third_party/skia/include/core/SkFont.h" #include "third_party/skia/include/core/SkRefCnt.h" @@ -176,7 +177,38 @@ WebFontRenderStyle style_; #endif +#if defined(USE_PARALLEL_TEXT_SHAPING) + // The class maps from thread id to `HarfBuzzFace`. + // Note: We can not use `base::SequenceLocalStorageSlot` or + // `base::ThreadLocalStorage` here, because number of instances are limited, + // e.g. 255. + class ThreadSpecificHarfBuzzFace final { + public: + ThreadSpecificHarfBuzzFace(); + ~ThreadSpecificHarfBuzzFace(); + + ThreadSpecificHarfBuzzFace(const ThreadSpecificHarfBuzzFace&) = delete; + ThreadSpecificHarfBuzzFace(ThreadSpecificHarfBuzzFace&&) = delete; + + ThreadSpecificHarfBuzzFace operator=(const ThreadSpecificHarfBuzzFace&) = + delete; + ThreadSpecificHarfBuzzFace operator=(ThreadSpecificHarfBuzzFace&&) = delete; + + HarfBuzzFace& GetOrCreate(FontPlatformData* platform_data) + LOCKS_EXCLUDED(lock_); + + private: + // TODO(yosin): Once all platforms support parallel text shaping, we should + // use `std::unique_ptr<T>` for `HarfBuzzFace`. + using Map = HashMap<base::PlatformThreadId, scoped_refptr<HarfBuzzFace>>; + base::Lock lock_; + Map map_ GUARDED_BY(lock_); + }; + + mutable ThreadSpecificHarfBuzzFace harfbuzz_face_; +#else mutable std::unique_ptr<HarfBuzzFace> harfbuzz_face_; +#endif bool is_hash_table_deleted_value_ = false; };
diff --git a/third_party/blink/renderer/platform/fonts/opentype/open_type_caps_support.cc b/third_party/blink/renderer/platform/fonts/opentype/open_type_caps_support.cc index 3c34ffc..f29234e 100644 --- a/third_party/blink/renderer/platform/fonts/opentype/open_type_caps_support.cc +++ b/third_party/blink/renderer/platform/fonts/opentype/open_type_caps_support.cc
@@ -143,8 +143,8 @@ OpenTypeCapsSupport::FontFormat OpenTypeCapsSupport::GetFontFormat() const { if (font_format_ == FontFormat::kUndetermined) { - hb_face_t* hb_face = hb_font_get_face(harfbuzz_face_->GetScaledFont( - nullptr, HarfBuzzFace::kNoVerticalLayout)); + hb_face_t* const hb_face = + hb_font_get_face(harfbuzz_face_->GetScaledFont()); HbScoped<hb_blob_t> morx_blob( hb_face_reference_table(hb_face, HB_TAG('m', 'o', 'r', 'x'))); @@ -177,8 +177,7 @@ return false; } - hb_face_t* hb_face = hb_font_get_face( - harfbuzz_face_->GetScaledFont(nullptr, HarfBuzzFace::kNoVerticalLayout)); + hb_face_t* const hb_face = hb_font_get_face(harfbuzz_face_->GetScaledFont()); Vector<hb_aat_layout_feature_type_t> aat_features; unsigned feature_count =
diff --git a/third_party/blink/renderer/platform/fonts/opentype/open_type_caps_support_mpl.cc b/third_party/blink/renderer/platform/fonts/opentype/open_type_caps_support_mpl.cc index 83ed7cc..2bbd9731 100644 --- a/third_party/blink/renderer/platform/fonts/opentype/open_type_caps_support_mpl.cc +++ b/third_party/blink/renderer/platform/fonts/opentype/open_type_caps_support_mpl.cc
@@ -14,8 +14,7 @@ bool OpenTypeCapsSupport::SupportsOpenTypeFeature(hb_script_t script, uint32_t tag) const { - hb_face_t* face = hb_font_get_face( - harfbuzz_face_->GetScaledFont(nullptr, HarfBuzzFace::kNoVerticalLayout)); + hb_face_t* const face = hb_font_get_face(harfbuzz_face_->GetScaledFont()); DCHECK(face); DCHECK(
diff --git a/third_party/blink/renderer/platform/fonts/opentype/open_type_math_support.cc b/third_party/blink/renderer/platform/fonts/opentype/open_type_math_support.cc index a721a88..4660a18 100644 --- a/third_party/blink/renderer/platform/fonts/opentype/open_type_math_support.cc +++ b/third_party/blink/renderer/platform/fonts/opentype/open_type_math_support.cc
@@ -40,8 +40,7 @@ if (!harfbuzz_face) return false; - hb_font_t* font = - harfbuzz_face->GetScaledFont(nullptr, HarfBuzzFace::kNoVerticalLayout); + hb_font_t* font = harfbuzz_face->GetScaledFont(); DCHECK(font); hb_face_t* face = hb_font_get_face(font); DCHECK(face); @@ -55,8 +54,7 @@ if (!HasMathData(harfbuzz_face)) return absl::nullopt; - hb_font_t* font = - harfbuzz_face->GetScaledFont(nullptr, HarfBuzzFace::kNoVerticalLayout); + hb_font_t* const font = harfbuzz_face->GetScaledFont(); DCHECK(font); hb_position_t harfbuzz_value = hb_ot_math_get_constant( @@ -133,8 +131,7 @@ if (!harfbuzz_face) return absl::nullopt; - hb_font_t* font = - harfbuzz_face->GetScaledFont(nullptr, HarfBuzzFace::kNoVerticalLayout); + hb_font_t* const font = harfbuzz_face->GetScaledFont(); return absl::optional<float>(HarfBuzzUnitsToFloat( hb_ot_math_get_glyph_italics_correction(font, glyph))); @@ -161,8 +158,7 @@ GetHarfBuzzMathRecordGetter<HarfBuzzRecordType> getter, HarfBuzzMathRecordConverter<HarfBuzzRecordType, RecordType> converter, absl::optional<RecordType> prepended_record) { - hb_font_t* hb_font = - harfbuzz_face->GetScaledFont(nullptr, HarfBuzzFace::kNoVerticalLayout); + hb_font_t* const hb_font = harfbuzz_face->GetScaledFont(); DCHECK(hb_font); hb_direction_t hb_stretch_axis = HarfBuzzDirection(stretch_axis); @@ -241,8 +237,7 @@ std::move(converter), absl::optional<OpenTypeMathStretchData::GlyphPartRecord>()); if (italic_correction && !parts.IsEmpty()) { - hb_font_t* hb_font = - harfbuzz_face->GetScaledFont(nullptr, HarfBuzzFace::kNoVerticalLayout); + hb_font_t* const hb_font = harfbuzz_face->GetScaledFont(); // A GlyphAssembly subtable exists for the specified font, glyph and stretch // axis since it has been possible to retrieve the GlyphPartRecords. This // means that the following call is guaranteed to get an italic correction.
diff --git a/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_face.cc b/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_face.cc index 0385b908..d964d87 100644 --- a/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_face.cc +++ b/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_face.cc
@@ -485,6 +485,11 @@ return unscaled_font_; } +hb_font_t* HarfBuzzFace::GetScaledFont() const { + return GetScaledFont(nullptr, HarfBuzzFace::kNoVerticalLayout, + platform_data_->size()); +} + void HarfBuzzFace::Init() { DCHECK(IsMainThread()); HarfBuzzSkiaGetFontFuncs::Get();
diff --git a/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_face.h b/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_face.h index c6c88c3..cbfb1c15 100644 --- a/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_face.h +++ b/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_face.h
@@ -70,7 +70,12 @@ // object will be used. hb_font_t* GetScaledFont(scoped_refptr<UnicodeRangeSet>, VerticalLayoutCallbacks, - float specified_size = -1) const; + float specified_size) const; + + // Returns `hb_font_t` as same as `GetScaledFont()` with null + // `UnicodeRangeSet`, `HarfBuzzFace::kNoVerticalLayout`, and + // `platform_data_.size()`. + hb_font_t* GetScaledFont() const; bool HasSpaceInLigaturesOrKerning(TypesettingFeatures); unsigned UnitsPerEmFromHeadTable();
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_result_inline_headers.h b/third_party/blink/renderer/platform/fonts/shaping/shape_result_inline_headers.h index 33ccb0d..fe139f5 100644 --- a/third_party/blink/renderer/platform/fonts/shaping/shape_result_inline_headers.h +++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result_inline_headers.h
@@ -85,7 +85,6 @@ unsigned start_index, unsigned num_glyphs, unsigned num_characters) { - CHECK_GT(num_characters, 0u); return base::AdoptRef(new RunInfo(font, dir, canvas_rotation, script, start_index, num_glyphs, num_characters)); }
diff --git a/third_party/blink/renderer/platform/fonts/shaping/stretchy_operator_shaper.cc b/third_party/blink/renderer/platform/fonts/shaping/stretchy_operator_shaper.cc index 3bc8435..79a2626 100644 --- a/third_party/blink/renderer/platform/fonts/shaping/stretchy_operator_shaper.cc +++ b/third_party/blink/renderer/platform/fonts/shaping/stretchy_operator_shaper.cc
@@ -39,8 +39,7 @@ if (parts.IsEmpty()) return absl::nullopt; - hb_font_t* hb_font = - harfbuzz_face->GetScaledFont(nullptr, HarfBuzzFace::kNoVerticalLayout); + hb_font_t* const hb_font = harfbuzz_face->GetScaledFont(); auto hb_stretch_axis = stretch_axis == OpenTypeMathStretchData::StretchAxis::Horizontal
diff --git a/third_party/blink/renderer/platform/mediastream/media_stream_track_platform.h b/third_party/blink/renderer/platform/mediastream/media_stream_track_platform.h index 36d8156..cc9a4ec 100644 --- a/third_party/blink/renderer/platform/mediastream/media_stream_track_platform.h +++ b/third_party/blink/renderer/platform/mediastream/media_stream_track_platform.h
@@ -84,14 +84,6 @@ virtual void GetSettings(Settings& settings) {} virtual CaptureHandle GetCaptureHandle(); - // Adds a one off callback that will be invoked when observing the first frame - // where |metadata.crop_version >= crop_version|. - virtual void AddCropVersionCallback(uint32_t crop_version, - base::OnceClosure callback) {} - - // Removes the callback that was associated with this |crop_version|, if any. - virtual void RemoveCropVersionCallback(uint32_t crop_version) {} - bool is_local_track() const { return is_local_track_; } enum class StreamType { kAudio, kVideo };
diff --git a/third_party/blink/renderer/platform/peerconnection/task_queue_factory_test.cc b/third_party/blink/renderer/platform/peerconnection/task_queue_factory_test.cc deleted file mode 100644 index 8a34a046..0000000 --- a/third_party/blink/renderer/platform/peerconnection/task_queue_factory_test.cc +++ /dev/null
@@ -1,36 +0,0 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "third_party/webrtc_overrides/task_queue_factory.h" - -#include "base/task/task_traits.h" -#include "base/test/task_environment.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "third_party/webrtc/api/task_queue/task_queue_test.h" - -namespace { - -using ::webrtc::TaskQueueTest; - -// Wrapper around WebrtcTaskQueueFactory to set up required testing environment. -class TestTaskQueueFactory final : public webrtc::TaskQueueFactory { - public: - TestTaskQueueFactory() : factory_(CreateWebRtcTaskQueueFactory()) {} - - std::unique_ptr<webrtc::TaskQueueBase, webrtc::TaskQueueDeleter> - CreateTaskQueue(absl::string_view name, Priority priority) const override { - return factory_->CreateTaskQueue(name, priority); - } - - private: - base::test::TaskEnvironment task_environment_; - std::unique_ptr<webrtc::TaskQueueFactory> factory_; -}; - -} // namespace - -INSTANTIATE_TEST_SUITE_P( - WebRtc, - TaskQueueTest, - ::testing::Values(std::make_unique<TestTaskQueueFactory>));
diff --git a/third_party/blink/renderer/platform/peerconnection/webrtc_timer_test.cc b/third_party/blink/renderer/platform/peerconnection/webrtc_timer_test.cc index 3355e145..807e1463 100644 --- a/third_party/blink/renderer/platform/peerconnection/webrtc_timer_test.cc +++ b/third_party/blink/renderer/platform/peerconnection/webrtc_timer_test.cc
@@ -5,7 +5,6 @@ #include "third_party/webrtc_overrides/webrtc_timer.h" #include "base/task/thread_pool.h" -#include "base/test/scoped_feature_list.h" #include "base/test/task_environment.h" #include "base/time/time.h" #include "testing/gtest/include/gtest/gtest.h" @@ -129,42 +128,7 @@ } // namespace -TEST_F(WebRtcTimerTest, StartOneShotWithoutMetronome) { - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndDisableFeature(kWebRtcTimerUsesMetronome); - - CallbackListener listener; - WebRtcTimer timer(listener.task_runner(), - base::BindRepeating(&CallbackListener::Callback, - base::Unretained(&listener))); - - // Ensure the timer fires on the target millisecond. - timer.StartOneShot(base::Milliseconds(10)); - task_environment_.FastForwardBy(base::Milliseconds(9)); - EXPECT_EQ(listener.callback_count(), 0u); - task_environment_.FastForwardBy(base::Milliseconds(1)); - EXPECT_EQ(listener.callback_count(), 1u); - - // The task does not repeat automatically. - task_environment_.FastForwardBy(base::Milliseconds(10)); - EXPECT_EQ(listener.callback_count(), 1u); - - // The task can be manually scheduled to fire again. - timer.StartOneShot(base::Milliseconds(5)); - task_environment_.FastForwardBy(base::Milliseconds(5)); - EXPECT_EQ(listener.callback_count(), 2u); - - // Schedule to fire but shutdown the timer before it has time to fire. - timer.StartOneShot(base::Milliseconds(5)); - timer.Shutdown(); - - task_environment_.FastForwardBy(base::Milliseconds(5)); - EXPECT_EQ(listener.callback_count(), 2u); -} - -TEST_F(WebRtcTimerTest, StartOneShotWithMetronome) { - base::test::ScopedFeatureList scoped_feature_list(kWebRtcTimerUsesMetronome); - +TEST_F(WebRtcTimerTest, StartOneShot) { CallbackListener listener; WebRtcTimer timer(listener.task_runner(), base::BindRepeating(&CallbackListener::Callback, @@ -205,27 +169,7 @@ EXPECT_EQ(listener.callback_count(), 3u); } -TEST_F(WebRtcTimerTest, RecursiveStartOneShotWithoutMetronome) { - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndDisableFeature(kWebRtcTimerUsesMetronome); - - base::TimeDelta delay = base::Milliseconds(1); - RecursiveStartOneShotter recursive_shotter(/*repeat_count=*/2, delay); - - // Ensure the callback is repeated twice. - EXPECT_EQ(recursive_shotter.callback_count(), 0u); - task_environment_.FastForwardBy(delay); - EXPECT_EQ(recursive_shotter.callback_count(), 1u); - task_environment_.FastForwardBy(delay); - EXPECT_EQ(recursive_shotter.callback_count(), 2u); - // It is not repeated a third time. - task_environment_.FastForwardBy(delay); - EXPECT_EQ(recursive_shotter.callback_count(), 2u); -} - -TEST_F(WebRtcTimerTest, RecursiveStartOneShotWithMetronome) { - base::test::ScopedFeatureList scoped_feature_list(kWebRtcTimerUsesMetronome); - +TEST_F(WebRtcTimerTest, RecursiveStartOneShot) { base::TimeDelta delay = base::Milliseconds(1); RecursiveStartOneShotter recursive_shotter(/*repeat_count=*/2, delay); @@ -249,36 +193,7 @@ EXPECT_EQ(recursive_shotter.callback_count(), 2u); } -TEST_F(WebRtcTimerTest, MoveToNewTaskRunnerWithoutMetronome) { - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndDisableFeature(kWebRtcTimerUsesMetronome); - - CallbackListener listener; - WebRtcTimer timer(listener.task_runner(), - base::BindRepeating(&CallbackListener::Callback, - base::Unretained(&listener))); - - // Schedule in less than a tick, and advance time half-way there. - timer.StartOneShot(base::Milliseconds(6)); - task_environment_.FastForwardBy(base::Milliseconds(3)); - EXPECT_EQ(listener.callback_count(), 0u); - - // Move to a new task runner. The CallbackListener will EXPECT_TRUE that the - // correct task runner is used. - listener.set_task_runner(base::ThreadPool::CreateSequencedTaskRunner({})); - timer.MoveToNewTaskRunner(listener.task_runner()); - - // Advance to scheduled time. - task_environment_.FastForwardBy(base::Milliseconds(3)); - EXPECT_EQ(listener.callback_count(), 1u); - - // Cleanup. - timer.Shutdown(); -} - -TEST_F(WebRtcTimerTest, MoveToNewTaskRunnerWithMetronome) { - base::test::ScopedFeatureList scoped_feature_list(kWebRtcTimerUsesMetronome); - +TEST_F(WebRtcTimerTest, MoveToNewTaskRunner) { CallbackListener listener; WebRtcTimer timer(listener.task_runner(), base::BindRepeating(&CallbackListener::Callback, @@ -303,33 +218,7 @@ timer.Shutdown(); } -TEST_F(WebRtcTimerTest, StartRepeatingWithoutMetronome) { - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndDisableFeature(kWebRtcTimerUsesMetronome); - - CallbackListener listener; - WebRtcTimer timer(listener.task_runner(), - base::BindRepeating(&CallbackListener::Callback, - base::Unretained(&listener))); - - // Ensure the timer repeats every 10 milliseconds. - timer.StartRepeating(base::Milliseconds(10)); - task_environment_.FastForwardBy(base::Milliseconds(10)); - EXPECT_EQ(listener.callback_count(), 1u); - task_environment_.FastForwardBy(base::Milliseconds(10)); - EXPECT_EQ(listener.callback_count(), 2u); - task_environment_.FastForwardBy(base::Milliseconds(10)); - EXPECT_EQ(listener.callback_count(), 3u); - timer.Shutdown(); - - // The timer stops on shutdown. - task_environment_.FastForwardBy(base::Milliseconds(10)); - EXPECT_EQ(listener.callback_count(), 3u); -} - -TEST_F(WebRtcTimerTest, StartRepeatingWithMetronome) { - base::test::ScopedFeatureList scoped_feature_list(kWebRtcTimerUsesMetronome); - +TEST_F(WebRtcTimerTest, StartRepeating) { CallbackListener listener; WebRtcTimer timer(listener.task_runner(), base::BindRepeating(&CallbackListener::Callback, @@ -355,58 +244,39 @@ } TEST_F(WebRtcTimerTest, StopRepeatingTimer) { - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndDisableFeature(kWebRtcTimerUsesMetronome); - CallbackListener listener; WebRtcTimer timer(listener.task_runner(), base::BindRepeating(&CallbackListener::Callback, base::Unretained(&listener))); - // Repeat every 10 ms. - timer.StartRepeating(base::Milliseconds(10)); - task_environment_.FastForwardBy(base::Milliseconds(10)); + // Repeat every tick. + timer.StartRepeating(MetronomeSource::Tick()); + task_environment_.FastForwardBy(MetronomeSource::Tick()); EXPECT_EQ(listener.callback_count(), 1u); - task_environment_.FastForwardBy(base::Milliseconds(10)); + task_environment_.FastForwardBy(MetronomeSource::Tick()); EXPECT_EQ(listener.callback_count(), 2u); // Stop the timer and ensure it stops repeating. timer.Stop(); - task_environment_.FastForwardBy(base::Milliseconds(10)); + task_environment_.FastForwardBy(MetronomeSource::Tick()); EXPECT_EQ(listener.callback_count(), 2u); // The timer is reusable - can start and stop again. - timer.StartRepeating(base::Milliseconds(10)); - task_environment_.FastForwardBy(base::Milliseconds(10)); + timer.StartRepeating(MetronomeSource::Tick()); + task_environment_.FastForwardBy(MetronomeSource::Tick()); EXPECT_EQ(listener.callback_count(), 3u); - task_environment_.FastForwardBy(base::Milliseconds(10)); + task_environment_.FastForwardBy(MetronomeSource::Tick()); EXPECT_EQ(listener.callback_count(), 4u); timer.Stop(); - task_environment_.FastForwardBy(base::Milliseconds(10)); + task_environment_.FastForwardBy(MetronomeSource::Tick()); EXPECT_EQ(listener.callback_count(), 4u); // Cleanup. timer.Shutdown(); } -TEST_F(WebRtcTimerTest, StopTimerFromInsideCallbackWithoutMetronome) { - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndDisableFeature(kWebRtcTimerUsesMetronome); - - // Stops its own timer from inside the callback after 10 ms. - RecursiveStopper recursive_stopper(base::Milliseconds(10)); - task_environment_.FastForwardBy(base::Milliseconds(10)); - EXPECT_EQ(recursive_stopper.callback_count(), 1u); - - // Ensure we are stopped, the callback count does not increase. - task_environment_.FastForwardBy(base::Milliseconds(10)); - EXPECT_EQ(recursive_stopper.callback_count(), 1u); -} - // Ensures stopping inside the timer callback does not deadlock. -TEST_F(WebRtcTimerTest, StopTimerFromInsideCallbackWithMetronome) { - base::test::ScopedFeatureList scoped_feature_list(kWebRtcTimerUsesMetronome); - +TEST_F(WebRtcTimerTest, StopTimerFromInsideCallback) { // Stops its own timer from inside the callback after a tick. RecursiveStopper recursive_stopper(MetronomeSource::Tick()); task_environment_.FastForwardBy(MetronomeSource::Tick()); @@ -420,9 +290,6 @@ // Ensures in-parallel stopping while the task may be running does not // deadlock in race condition. Coverage for https://crbug.com/1281399. TEST(WebRtcTimerRealThreadsTest, StopTimerWithRaceCondition) { - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndDisableFeature(kWebRtcTimerUsesMetronome); - base::test::TaskEnvironment task_environment( base::test::TaskEnvironment::ThreadingMode::MULTIPLE_THREADS, base::test::TaskEnvironment::TimeSource::SYSTEM_TIME); @@ -453,26 +320,22 @@ } TEST_F(WebRtcTimerTest, IsActive) { - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndDisableFeature(kWebRtcTimerUsesMetronome); - - constexpr base::TimeDelta kDelay = base::Milliseconds(10); IsActiveChecker is_active_checker; // StartOneShot() makes the timer temporarily active. EXPECT_FALSE(is_active_checker.timer().IsActive()); - is_active_checker.timer().StartOneShot(kDelay); + is_active_checker.timer().StartOneShot(MetronomeSource::Tick()); EXPECT_TRUE(is_active_checker.timer().IsActive()); - task_environment_.FastForwardBy(kDelay); + task_environment_.FastForwardBy(MetronomeSource::Tick()); EXPECT_FALSE(is_active_checker.timer().IsActive()); // The timer is said to be inactive inside the one-shot callback. EXPECT_FALSE(is_active_checker.was_active_in_last_callback()); // StartRepeating() makes the timer active until stopped. EXPECT_FALSE(is_active_checker.timer().IsActive()); - is_active_checker.timer().StartRepeating(kDelay); + is_active_checker.timer().StartRepeating(MetronomeSource::Tick()); EXPECT_TRUE(is_active_checker.timer().IsActive()); - task_environment_.FastForwardBy(kDelay); + task_environment_.FastForwardBy(MetronomeSource::Tick()); EXPECT_TRUE(is_active_checker.timer().IsActive()); // The timer is said to be active inside the repeating callback. EXPECT_TRUE(is_active_checker.was_active_in_last_callback());
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index f566f22..4df80546 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -1611,6 +1611,9 @@ virtual/layout_ng_table_frag/external/wpt/css/css-break/table/repeated-section/header-after-break.tentative.html [ Pass ] virtual/layout_ng_table_frag/external/wpt/css/css-break/table/repeated-section/header-footer.tentative.html [ Pass ] virtual/layout_ng_table_frag/external/wpt/css/css-break/table/repeated-section/header.tentative.html [ Pass ] +virtual/layout_ng_table_frag/external/wpt/css/css-break/table/repeated-section/hit-test-relative-in-transform.tentative.html [ Pass ] +virtual/layout_ng_table_frag/external/wpt/css/css-break/table/repeated-section/hit-test-relative.tentative.html [ Pass ] +virtual/layout_ng_table_frag/external/wpt/css/css-break/table/repeated-section/hit-test.tentative.html [ Pass ] virtual/layout_ng_table_frag/external/wpt/css/css-break/table/repeated-section/inline-block.tentative.html [ Pass ] virtual/layout_ng_table_frag/external/wpt/css/css-break/table/repeated-section/multicol.tentative.html [ Pass ] virtual/layout_ng_table_frag/external/wpt/css/css-break/table/table-border-005.html [ Pass ] @@ -3981,6 +3984,9 @@ crbug.com/1078927 external/wpt/css/css-break/table/repeated-section/header-after-break.tentative.html [ Failure ] crbug.com/1078927 external/wpt/css/css-break/table/repeated-section/header-footer.tentative.html [ Failure ] crbug.com/1078927 external/wpt/css/css-break/table/repeated-section/header.tentative.html [ Failure ] +crbug.com/1078927 external/wpt/css/css-break/table/repeated-section/hit-test-relative-in-transform.tentative.html [ Failure ] +crbug.com/1078927 external/wpt/css/css-break/table/repeated-section/hit-test-relative.tentative.html [ Failure ] +crbug.com/1078927 external/wpt/css/css-break/table/repeated-section/hit-test.tentative.html [ Failure ] crbug.com/1078927 external/wpt/css/css-break/table/repeated-section/inline-block.tentative.html [ Failure ] crbug.com/1078927 external/wpt/css/css-break/table/repeated-section/multicol.tentative.html [ Failure ] crbug.com/1078927 external/wpt/css/css-break/table/table-border-005.html [ Failure ] @@ -6853,7 +6859,6 @@ crbug.com/1312164 webaudio/internals/audiocontext-gc.html [ Skip ] # Sheriff 2022-03-21: More flaky tests. -crbug.com/1277696 [ Mac ] fast/loader/reload-zero-byte-plugin.html [ Failure Pass ] crbug.com/1272376 [ Mac ] plugins/plugin-document-back-forward.html [ Failure Pass ] # Tests that need updates due to rounding math in layout @@ -7070,3 +7075,6 @@ # Sheriff 2022-06-09 crbug.com/1335002 [ Linux ] external/wpt/event-timing/first-input-interactionid-tap.html [ Skip ] + +# Flaky on multiple platforms +crbug.com/1277696 fast/loader/reload-zero-byte-plugin.html [ Failure Pass ]
diff --git a/third_party/blink/web_tests/external/Version b/third_party/blink/web_tests/external/Version index 432e7f12..20af476 100644 --- a/third_party/blink/web_tests/external/Version +++ b/third_party/blink/web_tests/external/Version
@@ -1 +1 @@ -Version: edca84af42bd7e84da94e63b322fe343191842d2 +Version: 9894fff50b438d61b269e559ac004ba515f72637
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json index a349398..122bbc4 100644 --- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json +++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
@@ -237146,6 +237146,45 @@ } }, "popups": { + "popup-animated-hide-display.tentative.html": [ + "410639e67152c895d2ad09bcef33224333a8ce08", + [ + null, + [ + [ + "/html/semantics/popups/popup-animated-display-ref.tentative.html", + "==" + ] + ], + {} + ] + ], + "popup-animated-hide-finishes.tentative.html": [ + "88e37cb4e3bd7d18fb983c1c04d012ec9f6fde98", + [ + null, + [ + [ + "/html/semantics/popups/popup-animated-hide-finishes-ref.tentative.html", + "==" + ] + ], + {} + ] + ], + "popup-animated-show-display.tentative.html": [ + "deb7550926422983b684b01609c4e68a67a08b97", + [ + null, + [ + [ + "/html/semantics/popups/popup-animated-display-ref.tentative.html", + "==" + ] + ], + {} + ] + ], "popup-backdrop-appearance.tentative.html": [ "0b348f85d0103c36ea71e6c7f420df3709c0bb9b", [ @@ -313274,6 +313313,14 @@ } }, "popups": { + "popup-animated-display-ref.tentative.html": [ + "77f15441ae95dfd719065d47499866e68fa540e7", + [] + ], + "popup-animated-hide-finishes-ref.tentative.html": [ + "d8334f985ed51f3277d069838132876d8aad2ffc", + [] + ], "popup-backdrop-appearance-ref.tentative.html": [ "0327f3886fbceec18f21e2146a91a59053bfc954", [] @@ -379324,34 +379371,6 @@ {} ] ], - "grid-template-columns-neutral-keyframe-001.html": [ - "070539e2c0eda9cbc8585f8bd1fc4217485d97e4", - [ - null, - {} - ] - ], - "grid-template-columns-neutral-keyframe-002.html": [ - "6cd163711ee599366280b352dcb808e83ea2899f", - [ - null, - {} - ] - ], - "grid-template-columns-neutral-keyframe-003.html": [ - "80187cf68487bf3af4d39a0799b30886600e61f3", - [ - null, - {} - ] - ], - "grid-template-columns-neutral-keyframe-004.html": [ - "a207aa713c971cda94052dc8abf810f1e1cb29fd", - [ - null, - {} - ] - ], "grid-template-rows-composition.html": [ "42f9c92e9ad6d2042553e7e4b440adeeddf09bab", [ @@ -379365,34 +379384,6 @@ null, {} ] - ], - "grid-template-rows-neutral-keyframe-001.html": [ - "ecbe0481eded5ede38ab482b9175555258f82861", - [ - null, - {} - ] - ], - "grid-template-rows-neutral-keyframe-002.html": [ - "f63d45b4a71929ae703bd1dc51b875c0c843b12e", - [ - null, - {} - ] - ], - "grid-template-rows-neutral-keyframe-003.html": [ - "5ffd67528ca91f27ae801fe8930745a27c61df0b", - [ - null, - {} - ] - ], - "grid-template-rows-neutral-keyframe-004.html": [ - "941e843624837b16506b9900cc0736f3ca8a5a5f", - [ - null, - {} - ] ] }, "chrome-crash-001.html": [ @@ -427799,6 +427790,69 @@ } ] ], + "response-stream-bad-chunk.any.js": [ + "d3d92e16772d10a8c91ee42d4c6bcaf0d4cc4fa0", + [ + "fetch/api/response/response-stream-bad-chunk.any.html", + { + "script_metadata": [ + [ + "global", + "window,worker" + ], + [ + "title", + "Response causes TypeError from bad chunk type" + ] + ] + } + ], + [ + "fetch/api/response/response-stream-bad-chunk.any.serviceworker.html", + { + "script_metadata": [ + [ + "global", + "window,worker" + ], + [ + "title", + "Response causes TypeError from bad chunk type" + ] + ] + } + ], + [ + "fetch/api/response/response-stream-bad-chunk.any.sharedworker.html", + { + "script_metadata": [ + [ + "global", + "window,worker" + ], + [ + "title", + "Response causes TypeError from bad chunk type" + ] + ] + } + ], + [ + "fetch/api/response/response-stream-bad-chunk.any.worker.html", + { + "script_metadata": [ + [ + "global", + "window,worker" + ], + [ + "title", + "Response causes TypeError from bad chunk type" + ] + ] + } + ] + ], "response-stream-disturbed-1.any.js": [ "64f65f16f23e7d797451c634a2f472a51d6955c0", [ @@ -473847,6 +473901,15 @@ } ] ], + "popup-animated-hide-cleanup.tentative.html": [ + "762458ea669dda88b9f725c7d4dabf8179cf2b44", + [ + null, + { + "testdriver": true + } + ] + ], "popup-attribute-basic.tentative.html": [ "8ca5195a435016a81b1cef988560a1f503968e12", [ @@ -545521,15 +545584,6 @@ } ] ], - "createcredential-badargs-attestation.https.html": [ - "1bdebbbf2b286f69eecd0774ac9bdfb96c20a50b", - [ - null, - { - "testdriver": true - } - ] - ], "createcredential-badargs-authnrselection.https.html": [ "85b0f9053866a878185b0a2aaf6bab068bd65b86", [ @@ -545631,7 +545685,7 @@ ] ], "createcredential-passing.https.html": [ - "2d8fb14fc796991291fd68d862f2aad9299d1646", + "2c744b25585552188253720882e919718ac5c1a3", [ null, {
diff --git a/third_party/blink/web_tests/external/wpt/cookies/attributes/expires.html b/third_party/blink/web_tests/external/wpt/cookies/attributes/expires.html index f61c405..a6bacfd 100644 --- a/third_party/blink/web_tests/external/wpt/cookies/attributes/expires.html +++ b/third_party/blink/web_tests/external/wpt/cookies/attributes/expires.html
@@ -14,9 +14,6 @@ <body> <div id=log></div> <script> - // TODO: there is more to test here, these tests capture the old - // ported http-state tests. Feel free to delete this comment when more - // are added. const expiresTests = [ { cookie: "test=1; Expires=Fri, 01 Jan 2038 00:00:00 GMT", @@ -45,8 +42,14 @@ }, ]; + // These tests evaluate setting cookies with expiration via HTTP headers. for (const test of expiresTests) { - httpCookieTest(test.cookie, test.expected, test.name); + httpCookieTest(test.cookie, test.expected, test.name + " via HTTP headers"); + } + + // These tests evaluate setting cookies with expiration via document.cookie. + for (const test of expiresTests) { + domCookieTest(test.cookie, test.expected, test.name + " via document.cookie"); } </script> </body>
diff --git a/third_party/blink/web_tests/external/wpt/cookies/resources/cookie-test.js b/third_party/blink/web_tests/external/wpt/cookies/resources/cookie-test.js index 7c3b861..c73d4d75 100644 --- a/third_party/blink/web_tests/external/wpt/cookies/resources/cookie-test.js +++ b/third_party/blink/web_tests/external/wpt/cookies/resources/cookie-test.js
@@ -119,7 +119,15 @@ await test_driver.delete_all_cookies(); t.add_cleanup(test_driver.delete_all_cookies); - document.cookie = cookie; + if (typeof cookie === "string") { + document.cookie = cookie; + } else if (Array.isArray(cookie)) { + for (const singlecookie of cookie) { + document.cookie = singlecookie; + } + } else { + throw new Error('Unexpected type passed into domCookieTest as cookie: ' + typeof cookie); + } let cookies = document.cookie; assert_equals(cookies, expectedValue, Boolean(expectedValue) ? 'The cookie was set as expected.' :
diff --git a/third_party/blink/web_tests/external/wpt/css/css-break/hit-test-hidden-overflow.html b/third_party/blink/web_tests/external/wpt/css/css-break/hit-test-hidden-overflow.html new file mode 100644 index 0000000..ec766e0 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-break/hit-test-hidden-overflow.html
@@ -0,0 +1,23 @@ +<!DOCTYPE html> +<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org"> +<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1330515"> +<style> + body { margin: 0; } +</style> +<div id="first" style="margin-top:20px; height:20px;"> + <div style="overflow:hidden; width:500px; margin-left:-100px; height:0;"> + <div style="columns:2; gap:0; width:200%;"> + <div style="position:relative; margin-left:-100%; height:800px;"></div> + </div> + </div> +</div> +<div id="second" style="height:20px;"></div> +<div id="log" style="margin-top:200px;"></div> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + test(()=> { assert_equals(document.elementFromPoint(50, 10), document.documentElement); }, "above first block"); + test(()=> { assert_equals(document.elementFromPoint(50, 30), first); }, "first block"); + test(()=> { assert_equals(document.elementFromPoint(50, 50), second); }, "second block"); + test(()=> { assert_equals(document.elementFromPoint(50, 70), document.documentElement); }, "below first block"); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-break/table/repeated-section/hit-test-relative-in-transform.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-break/table/repeated-section/hit-test-relative-in-transform.tentative.html new file mode 100644 index 0000000..43a36f185 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-break/table/repeated-section/hit-test-relative-in-transform.tentative.html
@@ -0,0 +1,29 @@ +<!DOCTYPE html> +<style> + body { margin: 0; } +</style> +<div style="columns:2; width:200px; gap:0; column-fill:auto; height:100px;"> + <div style="transform:translateX(30px);"> + <div id="table" style="display:table; width:100%;"> + <div id="header" style="display:table-header-group; break-inside:avoid;"> + <div id="hitme" style="position:relative; left:30px; width:20px; height:20px;"></div> + </div> + <div style="display:table-row; break-inside:avoid;"> + <div style="height:60px; background:blue;"></div> + </div> + <div style="display:table-row; break-inside:avoid;"> + <div style="height:60px; background:blue;"></div> + </div> + </div> + </div> +</div> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + test(()=> { assert_equals(document.elementFromPoint(59, 10), header); }, "before first"); + test(()=> { assert_equals(document.elementFromPoint(70, 10), hitme); }, "first"); + test(()=> { assert_equals(document.elementFromPoint(91, 10), header); }, "after first"); + test(()=> { assert_equals(document.elementFromPoint(159, 10), header); }, "before second"); + test(()=> { assert_equals(document.elementFromPoint(170, 10), hitme); }, "second"); + test(()=> { assert_equals(document.elementFromPoint(181, 10), header); }, "after second"); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-break/table/repeated-section/hit-test-relative.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-break/table/repeated-section/hit-test-relative.tentative.html new file mode 100644 index 0000000..348bb0d --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-break/table/repeated-section/hit-test-relative.tentative.html
@@ -0,0 +1,27 @@ +<!DOCTYPE html> +<style> + body { margin: 0; } +</style> +<div style="columns:2; width:200px; gap:0; column-fill:auto; height:100px;"> + <div id="table" style="display:table; width:100%;"> + <div id="header" style="display:table-header-group; break-inside:avoid;"> + <div id="hitme" style="position:relative; left:30px; width:20px; height:20px;"></div> + </div> + <div style="display:table-row; break-inside:avoid;"> + <div style="height:60px; background:blue;"></div> + </div> + <div style="display:table-row; break-inside:avoid;"> + <div style="height:60px; background:blue;"></div> + </div> + </div> +</div> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + test(()=> { assert_equals(document.elementFromPoint(29, 10), header); }, "before first"); + test(()=> { assert_equals(document.elementFromPoint(40, 10), hitme); }, "first"); + test(()=> { assert_equals(document.elementFromPoint(61, 10), header); }, "after first"); + test(()=> { assert_equals(document.elementFromPoint(129, 10), header); }, "before second"); + test(()=> { assert_equals(document.elementFromPoint(140, 10), hitme); }, "second"); + test(()=> { assert_equals(document.elementFromPoint(151, 10), header); }, "after second"); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-break/table/repeated-section/hit-test.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-break/table/repeated-section/hit-test.tentative.html new file mode 100644 index 0000000..9b462887c --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-break/table/repeated-section/hit-test.tentative.html
@@ -0,0 +1,26 @@ +<!DOCTYPE html> +<style> + body { margin: 0; } +</style> +<div style="columns:2; width:200px; gap:0; column-fill:auto; height:100px;"> + <div id="table" style="display:table; width:100%;"> + <div id="header" style="display:table-header-group; break-inside:avoid;"> + <div id="hitme" style="width:20px; height:20px;"></div> + </div> + <div style="display:table-row; break-inside:avoid;"> + <div style="height:60px; background:blue;"></div> + </div> + <div style="display:table-row; break-inside:avoid;"> + <div style="height:60px; background:blue;"></div> + </div> + </div> +</div> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + test(()=> { assert_equals(document.elementFromPoint(10, 10), hitme); }, "first"); + test(()=> { assert_equals(document.elementFromPoint(21, 10), header); }, "after first"); + test(()=> { assert_equals(document.elementFromPoint(99, 10), header); }, "before second"); + test(()=> { assert_equals(document.elementFromPoint(110, 10), hitme); }, "second"); + test(()=> { assert_equals(document.elementFromPoint(121, 10), header); }, "after second"); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/response/response-stream-bad-chunk.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-stream-bad-chunk.any.js new file mode 100644 index 0000000..d3d92e1 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/fetch/api/response/response-stream-bad-chunk.any.js
@@ -0,0 +1,24 @@ +// META: global=window,worker +// META: title=Response causes TypeError from bad chunk type + +function runChunkTest(responseReaderMethod, testDescription) { + promise_test(test => { + let stream = new ReadableStream({ + start(controller) { + controller.enqueue("not Uint8Array"); + controller.close(); + } + }); + + return promise_rejects_js(test, TypeError, + new Response(stream)[responseReaderMethod](), + 'TypeError should propagate' + ) + }, testDescription) +} + +runChunkTest('arrayBuffer', 'ReadableStream with non-Uint8Array chunk passed to Response.arrayBuffer() causes TypeError'); +runChunkTest('blob', 'ReadableStream with non-Uint8Array chunk passed to Response.blob() causes TypeError'); +runChunkTest('formData', 'ReadableStream with non-Uint8Array chunk passed to Response.formData() causes TypeError'); +runChunkTest('json', 'ReadableStream with non-Uint8Array chunk passed to Response.json() causes TypeError'); +runChunkTest('text', 'ReadableStream with non-Uint8Array chunk passed to Response.text() causes TypeError');
diff --git a/third_party/blink/web_tests/fast/forms/calendar-picker/month-picker-touch-operations.html b/third_party/blink/web_tests/fast/forms/calendar-picker/month-picker-touch-operations.html new file mode 100644 index 0000000..b9a4ab8 --- /dev/null +++ b/third_party/blink/web_tests/fast/forms/calendar-picker/month-picker-touch-operations.html
@@ -0,0 +1,37 @@ +<!DOCTYPE html> +<link rel=help href="https://bugs.chromium.org/p/chromium/issues/detail?id=1321616"> +<script src="../../../resources/testharness.js"></script> +<script src="../../../resources/testharnessreport.js"></script> +<script src="../../../resources/testdriver.js"></script> +<script src="../../../resources/testdriver-vendor.js"></script> +<script src="../resources/common.js"></script> +<script src="../resources/picker-common.js"></script> +<script src="resources/calendar-picker-common.js"></script> + +<input type=month id=picker> + +<script> +const forceRunAnimation = () => { + internals.pagePopupWindow.AnimationManager.shared._animationFrameCallback(0); +} + +promise_test(async () => { + await openPicker(picker); + + const scrollView = internals.pagePopupWindow.global.picker.yearListView_.scrollView; + const scrollViewOffset = cumulativeOffset(scrollView.element); + + eventSender.clearTouchPoints(); + eventSender.addTouchPoint(scrollViewOffset[0] + 1, scrollViewOffset[1] + 1); + eventSender.touchStart(); + eventSender.updateTouchPoint(0, scrollViewOffset[0] + 1, scrollViewOffset[1] + 50); + eventSender.touchMove(); + eventSender.releaseTouchPoint(0); + eventSender.touchEnd(); + forceRunAnimation(); + + const firstYearCell = internals.pagePopupWindow.global.picker.yearListView_.firstVisibleRow(); + assert_not_equals(firstYearCell, null); +}, `Verifies that the month picker should show year list`); + +</script>
diff --git a/third_party/blink/web_tests/printing/fixed-positioned-composited.html b/third_party/blink/web_tests/printing/fixed-positioned-composited.html index b9230a5..70ce43e 100644 --- a/third_party/blink/web_tests/printing/fixed-positioned-composited.html +++ b/third_party/blink/web_tests/printing/fixed-positioned-composited.html
@@ -3,7 +3,7 @@ if (window.testRunner) testRunner.setPrinting(); </script> -<div style="position: fixed; top: 0; will-change-transform"> +<div style="position: fixed; top: 0; will-change: transform"> crbug.com/848839: Composited fixed-position should repeat on every page. </div> <div style="height:10px;"></div>
diff --git a/third_party/closure_compiler/externs/file_manager_private.js b/third_party/closure_compiler/externs/file_manager_private.js index c659a4c..3f60dc7 100644 --- a/third_party/closure_compiler/externs/file_manager_private.js +++ b/third_party/closure_compiler/externs/file_manager_private.js
@@ -325,6 +325,16 @@ ZIP: 'zip', }; +/** @enum {string} */ +chrome.fileManagerPrivate.RecentDateBucket = { + TODAY: 'today', + YESTERDAY: 'yesterday', + EARLIER_THIS_WEEK: 'earlier_this_week', + EARLIER_THIS_MONTH: 'earlier_this_month', + EARLIER_THIS_YEAR: 'earlier_this_year', + OLDER: 'older', +}; + /** * @typedef {{ * appId: string, @@ -703,11 +713,20 @@ * taskId: number, * remainingSeconds: number, * errorName: string, + * outputs: (Array<Entry>|undefined), * }} */ chrome.fileManagerPrivate.ProgressStatus; /** + * @typedef {{ + * sourceUrl: string, + * isDlpRestricted: boolean, + * }} + */ +chrome.fileManagerPrivate.DlpMetadata; + +/** * Logout the current user for navigating to the re-authentication screen for * the Google account. */ @@ -925,10 +944,11 @@ * Returns a list of files that are restricted by any Data Leak Prevention * (DLP) rule. |entries| list of source entries to be checked. * @param {!Array<!Entry>} entries - * @param {!Array<!Entry>} callback Entries of files that are restricted - * by at least one DLP rule. + * @param {function((!Array<!chrome.fileManagerPrivate.DlpMetadata>|undefined))} + * callback Callback with the list of chrome.fileManagerPrivate.DlpMetadata + * containing DLP information about the entries. */ -chrome.fileManagerPrivate.getFilesRestrictedByDlp = function(entries, callback) {}; +chrome.fileManagerPrivate.getDlpMetadata = function(entries, callback) {}; /** * Starts to copy an entry. If the source is a directory, the copy is done
diff --git a/third_party/webrtc_overrides/BUILD.gn b/third_party/webrtc_overrides/BUILD.gn index 330d0bcc..7ed3fd91 100644 --- a/third_party/webrtc_overrides/BUILD.gn +++ b/third_party/webrtc_overrides/BUILD.gn
@@ -213,11 +213,6 @@ "metronome_task_queue_factory.h", # Tested in - # third_party/blink/renderer/platform/peerconnection/task_queue_factory_test.cc - "task_queue_factory.cc", - "task_queue_factory.h", - - # Tested in # third_party/blink/renderer/platform/peerconnection/webrtc_timer_test.cc "webrtc_timer.cc", "webrtc_timer.h", @@ -256,18 +251,3 @@ sources = [ "rtc_base/system_time.cc" ] deps = [ "//base" ] } - -if (is_android) { - java_cpp_features("java_features_srcjar") { - # External code should depend on ":webrtc_overrides_java" instead. - visibility = [ ":*" ] - sources = [ - "//third_party/webrtc_overrides/metronome_task_queue_factory.cc", - "//third_party/webrtc_overrides/webrtc_timer.cc", - ] - template = "//third_party/webrtc_overrides/java_templates/WebRtcOverridesFeatures.java.tmpl" - } - android_library("webrtc_overrides_java") { - srcjar_deps = [ ":java_features_srcjar" ] - } -}
diff --git a/third_party/webrtc_overrides/java_templates/WebRtcOverridesFeatures.java.tmpl b/third_party/webrtc_overrides/java_templates/WebRtcOverridesFeatures.java.tmpl deleted file mode 100644 index f053669..0000000 --- a/third_party/webrtc_overrides/java_templates/WebRtcOverridesFeatures.java.tmpl +++ /dev/null
@@ -1,16 +0,0 @@ -// Copyright 2022 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.webrtc_overrides; - -/** - * Contains features that are specific to third_party/webrtc_overrides/. - */ -public final class WebRtcOverridesFeatures {{ - -{NATIVE_FEATURES} - - // Prevents instantiation. - private WebRtcOverridesFeatures() {{}} -}}
diff --git a/third_party/webrtc_overrides/metronome_source.cc b/third_party/webrtc_overrides/metronome_source.cc index c04d2c3a..c064801 100644 --- a/third_party/webrtc_overrides/metronome_source.cc +++ b/third_party/webrtc_overrides/metronome_source.cc
@@ -21,7 +21,6 @@ #include "base/trace_event/typed_macros.h" #include "third_party/webrtc/api/metronome/metronome.h" #include "third_party/webrtc/rtc_base/task_utils/to_queued_task.h" -#include "third_party/webrtc_overrides/task_queue_factory.h" namespace blink {
diff --git a/third_party/webrtc_overrides/metronome_task_queue_factory.cc b/third_party/webrtc_overrides/metronome_task_queue_factory.cc index 84e09e2f..79bb617 100644 --- a/third_party/webrtc_overrides/metronome_task_queue_factory.cc +++ b/third_party/webrtc_overrides/metronome_task_queue_factory.cc
@@ -17,13 +17,9 @@ #include "third_party/webrtc/api/task_queue/task_queue_factory.h" #include "third_party/webrtc_overrides/coalesced_tasks.h" #include "third_party/webrtc_overrides/metronome_source.h" -#include "third_party/webrtc_overrides/task_queue_factory.h" namespace blink { -const base::Feature kWebRtcMetronomeTaskQueue{"WebRtcMetronomeTaskQueue", - base::FEATURE_ENABLED_BY_DEFAULT}; - class WebRtcMetronomeTaskQueue : public webrtc::TaskQueueBase { public: explicit WebRtcMetronomeTaskQueue(base::TaskTraits traits); @@ -154,6 +150,31 @@ namespace { +base::TaskTraits TaskQueuePriority2Traits( + webrtc::TaskQueueFactory::Priority priority) { + // The content/renderer/media/webrtc/rtc_video_encoder.* code + // employs a PostTask/Wait pattern that uses TQ in a way that makes it + // blocking and synchronous, which is why we allow WithBaseSyncPrimitives() + // for OS_ANDROID. + switch (priority) { + case webrtc::TaskQueueFactory::Priority::HIGH: +#if defined(OS_ANDROID) + return {base::WithBaseSyncPrimitives(), base::TaskPriority::HIGHEST}; +#else + return {base::TaskPriority::HIGHEST}; +#endif + case webrtc::TaskQueueFactory::Priority::LOW: + return {base::MayBlock(), base::TaskPriority::BEST_EFFORT}; + case webrtc::TaskQueueFactory::Priority::NORMAL: + default: +#if defined(OS_ANDROID) + return {base::WithBaseSyncPrimitives()}; +#else + return {}; +#endif + } +} + class WebrtcMetronomeTaskQueueFactory final : public webrtc::TaskQueueFactory { public: std::unique_ptr<webrtc::TaskQueueBase, webrtc::TaskQueueDeleter> @@ -172,3 +193,10 @@ return std::unique_ptr<webrtc::TaskQueueFactory>( new blink::WebrtcMetronomeTaskQueueFactory()); } + +std::unique_ptr<webrtc::TaskQueueBase, webrtc::TaskQueueDeleter> +CreateWebRtcTaskQueue(webrtc::TaskQueueFactory::Priority priority) { + return std::unique_ptr<webrtc::TaskQueueBase, webrtc::TaskQueueDeleter>( + new blink::WebRtcMetronomeTaskQueue( + blink::TaskQueuePriority2Traits(priority))); +}
diff --git a/third_party/webrtc_overrides/metronome_task_queue_factory.h b/third_party/webrtc_overrides/metronome_task_queue_factory.h index bca8a5a..40bc4a97 100644 --- a/third_party/webrtc_overrides/metronome_task_queue_factory.h +++ b/third_party/webrtc_overrides/metronome_task_queue_factory.h
@@ -12,17 +12,13 @@ #include "third_party/webrtc/api/task_queue/task_queue_factory.h" #include "third_party/webrtc/rtc_base/system/rtc_export.h" -namespace blink { - -// Whether WebRTC should use a metronome-backed task queue. Default: disabled. -RTC_EXPORT extern const base::Feature kWebRtcMetronomeTaskQueue; - -} // namespace blink - // Creates a factory for webrtc::TaskQueueBase that is backed by a // blink::MetronomeSource. Tested by // /third_party/blink/renderer/platform/peerconnection/metronome_task_queue_factory_test.cc RTC_EXPORT std::unique_ptr<webrtc::TaskQueueFactory> CreateWebRtcMetronomeTaskQueueFactory(); +RTC_EXPORT std::unique_ptr<webrtc::TaskQueueBase, webrtc::TaskQueueDeleter> +CreateWebRtcTaskQueue(webrtc::TaskQueueFactory::Priority priority); + #endif // THIRD_PARTY_WEBRTC_OVERRIDES_METRONOME_TASK_QUEUE_FACTORY_H_
diff --git a/third_party/webrtc_overrides/task_queue_factory.cc b/third_party/webrtc_overrides/task_queue_factory.cc deleted file mode 100644 index 3490768..0000000 --- a/third_party/webrtc_overrides/task_queue_factory.cc +++ /dev/null
@@ -1,146 +0,0 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "third_party/webrtc_overrides/task_queue_factory.h" - -#include "base/bind.h" -#include "base/memory/ref_counted.h" -#include "base/memory/scoped_refptr.h" -#include "base/synchronization/waitable_event.h" -#include "base/task/task_traits.h" -#include "base/task/thread_pool.h" -#include "build/build_config.h" -#include "third_party/webrtc/api/task_queue/task_queue_base.h" -#include "third_party/webrtc/api/task_queue/task_queue_factory.h" - -namespace blink { - -class WebrtcTaskQueue final : public webrtc::TaskQueueBase { - public: - explicit WebrtcTaskQueue(const base::TaskTraits& traits) - : task_runner_(base::ThreadPool::CreateSequencedTaskRunner(traits)), - is_active_(new base::RefCountedData<bool>(true)) { - DCHECK(task_runner_); - } - - void Delete() override; - void PostTask(std::unique_ptr<webrtc::QueuedTask> task) override; - void PostDelayedTask(std::unique_ptr<webrtc::QueuedTask> task, - uint32_t milliseconds) override; - - private: - ~WebrtcTaskQueue() override = default; - - static void RunTask(WebrtcTaskQueue* task_queue, - scoped_refptr<base::RefCountedData<bool>> is_active, - std::unique_ptr<webrtc::QueuedTask> task); - - const scoped_refptr<base::SequencedTaskRunner> task_runner_; - // Value of |is_active_| is checked and set on |task_runner_|. - const scoped_refptr<base::RefCountedData<bool>> is_active_; -}; - -void Deactivate(scoped_refptr<base::RefCountedData<bool>> is_active, - base::WaitableEvent* event) { - is_active->data = false; - event->Signal(); -} - -void WebrtcTaskQueue::Delete() { - DCHECK(!IsCurrent()); - base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL, - base::WaitableEvent::InitialState::NOT_SIGNALED); - task_runner_->PostTask(FROM_HERE, - base::BindOnce(&Deactivate, is_active_, &event)); - event.Wait(); - delete this; -} - -void WebrtcTaskQueue::RunTask( - WebrtcTaskQueue* task_queue, - scoped_refptr<base::RefCountedData<bool>> is_active, - std::unique_ptr<webrtc::QueuedTask> task) { - if (!is_active->data) - return; - - CurrentTaskQueueSetter set_current(task_queue); - webrtc::QueuedTask* task_ptr = task.release(); - if (task_ptr->Run()) { - // Delete task_ptr before CurrentTaskQueueSetter clears state that this code - // is running on the task queue. - delete task_ptr; - } -} - -void WebrtcTaskQueue::PostTask(std::unique_ptr<webrtc::QueuedTask> task) { - // Posted Task might outlive this, but access to this is guarded by - // ref-counted |is_active_| flag. - task_runner_->PostTask( - FROM_HERE, - base::BindOnce(&WebrtcTaskQueue::RunTask, base::Unretained(this), - is_active_, std::move(task))); -} - -void WebrtcTaskQueue::PostDelayedTask(std::unique_ptr<webrtc::QueuedTask> task, - uint32_t milliseconds) { - task_runner_->PostDelayedTaskAt( - base::subtle::PostDelayedTaskPassKey(), FROM_HERE, - base::BindOnce(&WebrtcTaskQueue::RunTask, base::Unretained(this), - is_active_, std::move(task)), - base::TimeTicks::Now() + base::Milliseconds(milliseconds), - base::subtle::DelayPolicy::kPrecise); -} - -base::TaskTraits TaskQueuePriority2Traits( - webrtc::TaskQueueFactory::Priority priority) { - // The content/renderer/media/webrtc/rtc_video_encoder.* code - // employs a PostTask/Wait pattern that uses TQ in a way that makes it - // blocking and synchronous, which is why we allow WithBaseSyncPrimitives() - // for OS_ANDROID. - switch (priority) { - case webrtc::TaskQueueFactory::Priority::HIGH: -#if defined(OS_ANDROID) - return {base::WithBaseSyncPrimitives(), base::TaskPriority::HIGHEST}; -#else - return {base::TaskPriority::HIGHEST}; -#endif - case webrtc::TaskQueueFactory::Priority::LOW: - return {base::MayBlock(), base::TaskPriority::BEST_EFFORT}; - case webrtc::TaskQueueFactory::Priority::NORMAL: - default: -#if defined(OS_ANDROID) - return {base::WithBaseSyncPrimitives()}; -#else - return {}; -#endif - } -} - -namespace { - -class WebrtcTaskQueueFactory final : public webrtc::TaskQueueFactory { - public: - WebrtcTaskQueueFactory() = default; - - std::unique_ptr<webrtc::TaskQueueBase, webrtc::TaskQueueDeleter> - CreateTaskQueue(absl::string_view /*name*/, - Priority priority) const override { - return std::unique_ptr<webrtc::TaskQueueBase, webrtc::TaskQueueDeleter>( - new WebrtcTaskQueue(TaskQueuePriority2Traits(priority))); - } -}; - -} // namespace - -} // namespace blink - -std::unique_ptr<webrtc::TaskQueueFactory> CreateWebRtcTaskQueueFactory() { - return std::make_unique<blink::WebrtcTaskQueueFactory>(); -} - -std::unique_ptr<webrtc::TaskQueueBase, webrtc::TaskQueueDeleter> -CreateWebRtcTaskQueue(webrtc::TaskQueueFactory::Priority priority) { - return std::unique_ptr<webrtc::TaskQueueBase, webrtc::TaskQueueDeleter>( - new blink::WebrtcTaskQueue(blink::TaskQueuePriority2Traits(priority))); -}
diff --git a/third_party/webrtc_overrides/task_queue_factory.h b/third_party/webrtc_overrides/task_queue_factory.h deleted file mode 100644 index 27dcd07..0000000 --- a/third_party/webrtc_overrides/task_queue_factory.h +++ /dev/null
@@ -1,31 +0,0 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef THIRD_PARTY_WEBRTC_OVERRIDES_TASK_QUEUE_FACTORY_H_ -#define THIRD_PARTY_WEBRTC_OVERRIDES_TASK_QUEUE_FACTORY_H_ - -#include <memory> - -#include "base/task/task_traits.h" -#include "third_party/webrtc/api/task_queue/task_queue_base.h" -#include "third_party/webrtc/api/task_queue/task_queue_factory.h" -#include "third_party/webrtc/rtc_base/system/rtc_export.h" - -namespace blink { - -RTC_EXPORT base::TaskTraits TaskQueuePriority2Traits( - webrtc::TaskQueueFactory::Priority priority); - -} // namespace blink - -// Creates factory for webrtc::TaskQueueBase backed by base::SequencedTaskRunner -// Tested by -// /third_party/blink/renderer/platform/peerconnection/task_queue_factory_test.cc -RTC_EXPORT std::unique_ptr<webrtc::TaskQueueFactory> -CreateWebRtcTaskQueueFactory(); - -RTC_EXPORT std::unique_ptr<webrtc::TaskQueueBase, webrtc::TaskQueueDeleter> -CreateWebRtcTaskQueue(webrtc::TaskQueueFactory::Priority priority); - -#endif // THIRD_PARTY_WEBRTC_OVERRIDES_TASK_QUEUE_FACTORY_H_
diff --git a/third_party/webrtc_overrides/webrtc_timer.cc b/third_party/webrtc_overrides/webrtc_timer.cc index 534ec6f4..b0999add 100644 --- a/third_party/webrtc_overrides/webrtc_timer.cc +++ b/third_party/webrtc_overrides/webrtc_timer.cc
@@ -9,17 +9,12 @@ namespace blink { -const base::Feature kWebRtcTimerUsesMetronome{"WebRtcTimerUsesMetronome", - base::FEATURE_ENABLED_BY_DEFAULT}; - WebRtcTimer::SchedulableCallback::SchedulableCallback( scoped_refptr<base::SequencedTaskRunner> task_runner, base::RepeatingCallback<void()> callback, - bool use_metronome, base::TimeDelta repeated_delay) : task_runner_(std::move(task_runner)), callback_(std::move(callback)), - use_metronome_(use_metronome), repeated_delay_(std::move(repeated_delay)) {} WebRtcTimer::SchedulableCallback::~SchedulableCallback() { @@ -32,11 +27,9 @@ DCHECK_EQ(scheduled_time_, base::TimeTicks::Max()) << "The callback has already been scheduled."; scheduled_time_ = scheduled_time; - base::TimeTicks target_time = scheduled_time_; - if (use_metronome_) { - // Snap target time to metronome tick! - target_time = MetronomeSource::TimeSnappedToNextTick(target_time); - } + // Snap target time to metronome tick! + base::TimeTicks target_time = + MetronomeSource::TimeSnappedToNextTick(scheduled_time_); task_runner_->PostDelayedTaskAt( base::subtle::PostDelayedTaskPassKey(), FROM_HERE, base::BindOnce(&WebRtcTimer::SchedulableCallback::MaybeRun, this), @@ -88,9 +81,7 @@ WebRtcTimer::WebRtcTimer(scoped_refptr<base::SequencedTaskRunner> task_runner, base::RepeatingCallback<void()> callback) - : callback_(std::move(callback)), - use_metronome_(base::FeatureList::IsEnabled(kWebRtcTimerUsesMetronome)), - task_runner_(std::move(task_runner)) {} + : callback_(std::move(callback)), task_runner_(std::move(task_runner)) {} WebRtcTimer::~WebRtcTimer() { DCHECK(is_shutdown_); @@ -150,7 +141,7 @@ void WebRtcTimer::ScheduleCallback(base::TimeTicks scheduled_time) { if (!schedulable_callback_) { schedulable_callback_ = base::MakeRefCounted<SchedulableCallback>( - task_runner_, callback_, use_metronome_, repeated_delay_); + task_runner_, callback_, repeated_delay_); } schedulable_callback_->Schedule(scheduled_time); }
diff --git a/third_party/webrtc_overrides/webrtc_timer.h b/third_party/webrtc_overrides/webrtc_timer.h index 04c2a55..62fdc1b6 100644 --- a/third_party/webrtc_overrides/webrtc_timer.h +++ b/third_party/webrtc_overrides/webrtc_timer.h
@@ -18,18 +18,14 @@ namespace blink { -// Whether WebRtcTimer should use the metronome source. Default: false. -RTC_EXPORT extern const base::Feature kWebRtcTimerUsesMetronome; - -// Implements a timer that is NOT guaranteed to have high precision. +// Implements a low precision timer, expect it to fire up to ~16 ms late (plus +// any OS or workload related delays). // -// When a metronome source is available and kWebRtcTimerUsesMetronome is -// enabled, the timer will fire on metronome ticks. This allows running the -// timer without increasing Idle Wake Ups at the cost of reducing the timer -// precision to the metronome tick frequency. When a metronome source isn't -// available, the timer has high precision. -// -// Prefer this timer for WebRTC use cases that does not require high precision. +// This timer only fires on metronome ticks as specified by +// MetronomeSource::TimeSnappedToNextTick(). This allows running numerous timers +// without increasing the Idle Wake Ups frequency beyond the metronome tick +// frequency, i.e. when each tick is already scheduled adding a WebRtcTimer +// should not add any Idle Wake Ups. class RTC_EXPORT WebRtcTimer final { public: WebRtcTimer(scoped_refptr<base::SequencedTaskRunner> task_runner, @@ -64,7 +60,6 @@ public: SchedulableCallback(scoped_refptr<base::SequencedTaskRunner> task_runner, base::RepeatingCallback<void()> callback, - bool use_metronome, base::TimeDelta repeated_delay); ~SchedulableCallback(); @@ -81,7 +76,6 @@ const scoped_refptr<base::SequencedTaskRunner> task_runner_; const base::RepeatingCallback<void()> callback_; - const bool use_metronome_; // Only accessed on |task_runner_|. bool is_currently_running_ = false; @@ -106,7 +100,6 @@ void RescheduleCallback() EXCLUSIVE_LOCKS_REQUIRED(lock_); const base::RepeatingCallback<void()> callback_; - const bool use_metronome_; base::Lock lock_; bool is_shutdown_ GUARDED_BY(lock_) = false; scoped_refptr<base::SequencedTaskRunner> task_runner_ GUARDED_BY(lock_);
diff --git a/tools/gritsettings/resource_ids.spec b/tools/gritsettings/resource_ids.spec index f239150..626187e 100644 --- a/tools/gritsettings/resource_ids.spec +++ b/tools/gritsettings/resource_ids.spec
@@ -451,7 +451,7 @@ "structures": [2800], }, "<(SHARED_INTERMEDIATE_DIR)/chrome/test/data/webui/resources.grd": { - "META": {"sizes": {"includes": [600],}}, + "META": {"sizes": {"includes": [900],}}, "includes": [2810], }, "chrome/test/data/webui_test_resources.grd": {
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index a866f7c..ad464dd4 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -34740,7 +34740,7 @@ <int value="1660" label="SHAREDSTORAGEPRIVATE_GET"/> <int value="1661" label="SHAREDSTORAGEPRIVATE_SET"/> <int value="1662" label="SHAREDSTORAGEPRIVATE_REMOVE"/> - <int value="1663" label="FILEMANAGERPRIVATEINTERNAL_GETFILESRESTRICTEDBYDLP"/> + <int value="1663" label="FILEMANAGERPRIVATEINTERNAL_GETDLPMETADATA"/> <int value="1664" label="WMDESKSPRIVATE_GETALLDESKS"/> <int value="1665" label="AUTOTESTPRIVATE_FORCEAUTOTHEMEMODE"/> <int value="1666" label="OS_TELEMETRY_GETSTATEFULPARTITIONINFO"/>
diff --git a/tools/metrics/histograms/metadata/net/histograms.xml b/tools/metrics/histograms/metadata/net/histograms.xml index 3aa5600..ab810fae 100644 --- a/tools/metrics/histograms/metadata/net/histograms.xml +++ b/tools/metrics/histograms/metadata/net/histograms.xml
@@ -324,6 +324,25 @@ </summary> </histogram> +<histogram name="Net.CertVerifier.MacTrustDomainCertCount.{Domain}" + units="certificates" expires_after="2023-02-01"> + <owner>mattm@chromium.org</owner> + <owner>hchao@chromium.org</owner> + <summary> + When the builtin certificate verifier is used on Mac and the platform + trusted certificates cache is initialized (or re-initialized if keychain + trust settings changed), records the number of certificates read from the + {Domain} trust domain. Only counts certificates that were successfully + parsed. Only recorded by the DomainCacheFullCerts implementation, which may + or may not be used depending on Finch trial parameters. + </summary> + <token key="Domain"> + <variant name="Admin"/> + <variant name="System"/> + <variant name="User"/> + </token> +</histogram> + <histogram base="true" name="Net.CertVerifier.NameNormalizationPrivateRoots" enum="NetCertificateNameNormalization" expires_after="2022-11-13"> <owner>mattm@chromium.org</owner>
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json index 17f81de4..7bd91ec7 100644 --- a/tools/perf/core/perfetto_binary_roller/binary_deps.json +++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -5,24 +5,24 @@ "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux_arm64/49b4b5dcbc312d8d2c3751cf29238b8efeb4e494/trace_processor_shell" }, "win": { - "hash": "9c03bc914458eff778dc222763c10570b342fb97", - "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/aee702e883cb0fd9a087a71b467746f54d68ca53/trace_processor_shell.exe" + "hash": "5c26236044a135f11d8afc32a4e512aab2e8bb16", + "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/ddc88694c41b71562428bd08b168666c8d42eaf3/trace_processor_shell.exe" }, "linux_arm": { "hash": "58893933be305d3bfe0a72ebebcacde2ac3ca893", "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux_arm/49b4b5dcbc312d8d2c3751cf29238b8efeb4e494/trace_processor_shell" }, "mac": { - "hash": "1c9ca8c85a340fdd3998ac85a68cfdbb78aa07d3", - "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/mac/aee702e883cb0fd9a087a71b467746f54d68ca53/trace_processor_shell" + "hash": "a5c7698f7767316fcaf1731d44ec2901f235b719", + "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/mac/29c99a813c0b03800cc2b06f521d9dfbf590194b/trace_processor_shell" }, "mac_arm64": { "hash": "e1ad4861384b06d911a65f035317914b8cc975c6", "full_remote_path": "perfetto-luci-artifacts/v25.0/mac-arm64/trace_processor_shell" }, "linux": { - "hash": "9a7e89dd21b196a0486e1f1a0e4fb5a028f0e75e", - "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/aee702e883cb0fd9a087a71b467746f54d68ca53/trace_processor_shell" + "hash": "8d7b1bfa3e5c905d2286b2379534d9c48f4bc5f8", + "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/ddc88694c41b71562428bd08b168666c8d42eaf3/trace_processor_shell" } }, "power_profile.sql": {
diff --git a/ui/file_manager/BUILD.gn b/ui/file_manager/BUILD.gn index 944dd4e8..3fa34577 100644 --- a/ui/file_manager/BUILD.gn +++ b/ui/file_manager/BUILD.gn
@@ -213,16 +213,7 @@ "//ui/file_manager/file_manager/foreground/js:build_worker", ] } else { - manifest_files = [ - "$target_gen_dir/manifest_preprocess_generated_image_loader.json", - "$target_gen_dir/manifest_preprocess_static_image_loader.json", - "$target_gen_dir/tsconfig.manifest", - ] - - deps += [ - ":preprocess_generated_image_loader", - ":preprocess_static_image_loader", - ] + manifest_files = [ "$target_gen_dir/tsconfig.manifest" ] } } @@ -258,10 +249,44 @@ extra_deps = [ ":copy_ts", ":preprocess_generated", + ":preprocess_generated_image_loader", ":preprocess_static", + ":preprocess_static_image_loader", ] deps = [ "//ui/webui/resources:library" ] - in_files = static_js_files + generated_js_files + ts_files + in_files = static_js_files + generated_js_files + ts_files + + image_loader_static_js_files + image_loader_generated_js_files + + definitions = [ + "//ui/file_manager/file_manager/definitions/file_manager.d.ts", + "//ui/file_manager/file_manager/definitions/volume_manager.d.ts", + ] +} + +# GRD for test files. +generate_grd("build_tests_grdp") { + testonly = true + grd_prefix = "file_manager_test" + out_grd = "$target_gen_dir/tests_resources.grdp" + + input_files_base_dir = rebase_path(".", "//") + input_files = unittest_files + deps = [ ":unit_test_data" ] +} + +# GRD for the actual application files that are processed by TS compiler. +generate_grd("build_tests_gen_grdp") { + testonly = true + grd_prefix = "file_manager_test" + out_grd = "$target_gen_dir/tests_gen_resources.grdp" + + input_files_base_dir = rebase_path(target_gen_dir, root_build_dir) + input_files = generated_test_htmls + manifest_files = [ "$target_gen_dir/tsconfig.manifest" ] + deps = [ + ":build_ts", + ":unit_test_data", + ] }
diff --git a/ui/file_manager/base/gn/js_test_gen_html.py b/ui/file_manager/base/gn/js_test_gen_html.py index 761a57be..0454e2d0 100644 --- a/ui/file_manager/base/gn/js_test_gen_html.py +++ b/ui/file_manager/base/gn/js_test_gen_html.py
@@ -24,53 +24,55 @@ def _process_js_module(input_file, output_filename): - """Generates the HTML for a unittest based on JS Modules. + """Generates the HTML for a unittest based on JS Modules. Args: input_file: The path for the unittest JS module. output_filename: The path/filename for HTML to be generated. """ - # Map //ui/file_manager files to test URL: - js_module_url = input_file.replace( - 'ui/file_manager/', 'chrome://file_manager_test/ui/file_manager/', 1) + # Map //ui/file_manager files to test URL: + js_module_url = input_file.replace('ui/file_manager/', + 'chrome://webui-test/', 1) - with open(output_filename, 'w') as out: - out.write(_HTML_FILE_START + '\n') + with open(output_filename, 'w') as out: + out.write(_HTML_FILE_START + '\n') - line = _JS_MODULE % (js_module_url) - out.write(line + '\n') + line = _JS_MODULE % (js_module_url) + out.write(line + '\n') - line = _JS_MODULE_REGISTER_TESTS % (js_module_url) - out.write(line + '\n') + line = _JS_MODULE_REGISTER_TESTS % (js_module_url) + out.write(line + '\n') def main(): - parser = ArgumentParser() - parser.add_argument( - '-s', '--src_path', help='Path to //src/ directory', required=True) - parser.add_argument( - '-i', - '--input', - help='Input dependency file generated by js_library.py', - required=True) - parser.add_argument( - '-o', - '--output', - help='Generated html output with flattened dependencies', - required=True) - parser.add_argument('-t', '--target_name', help='Test target name') - args = parser.parse_args() + parser = ArgumentParser() + parser.add_argument('-s', + '--src_path', + help='Path to //src/ directory', + required=True) + parser.add_argument( + '-i', + '--input', + help='Input dependency file generated by js_library.py', + required=True) + parser.add_argument( + '-o', + '--output', + help='Generated html output with flattened dependencies', + required=True) + parser.add_argument('-t', '--target_name', help='Test target name') + args = parser.parse_args() - # Convert from: - # gen/ui/file_manager/file_manager/common/js/example_unittest.m.js_library - # To: - # ui/file_manager/file_manager/common/js/example_unittest.m.js - path_test_file = args.input.replace('gen/', '', 1) - path_test_file = path_test_file.replace('.js_library', '.js') - _process_js_module(path_test_file, args.output) - return + # Convert from: + # gen/ui/file_manager/file_manager/common/js/example_unittest.m.js_library + # To: + # ui/file_manager/file_manager/common/js/example_unittest.m.js + path_test_file = args.input.replace('gen/', '', 1) + path_test_file = path_test_file.replace('.js_library', '.js') + _process_js_module(path_test_file, args.output) + return if __name__ == '__main__': - main() + main()
diff --git a/ui/file_manager/file_manager/common/js/BUILD.gn b/ui/file_manager/file_manager/common/js/BUILD.gn index d2681715..aa762f3 100644 --- a/ui/file_manager/file_manager/common/js/BUILD.gn +++ b/ui/file_manager/file_manager/common/js/BUILD.gn
@@ -42,6 +42,7 @@ ":notifications_browser_proxy", ":power", ":progress_center_common", + ":recent_date_bucket", ":storage_adapter", ":trash", ":url_constants", @@ -72,6 +73,7 @@ ":notifications_browser_proxy", ":power", ":progress_center_common", + ":recent_date_bucket", ":storage_adapter", ":trash", ":url_constants", @@ -297,6 +299,22 @@ js_library("power") { } +js_library("recent_date_bucket") { + deps = [ + "//ui/file_manager/file_manager/externs:file_manager_private", + "//ui/webui/resources/js:load_time_data.m", + ] +} + +js_unittest("recent_date_bucket_unittest.m") { + deps = [ + ":mock_chrome", + ":recent_date_bucket", + "//ui/webui/resources/js:assert.m", + "//ui/webui/resources/js:load_time_data.m", + ] +} + js_library("storage_adapter") { externs_list = [ "$externs_path/chrome_extensions.js" ] } @@ -389,6 +407,7 @@ ":filtered_volume_manager_unittest.m", ":importer_common_unittest.m", ":lru_cache_unittest.m", + ":recent_date_bucket_unittest.m", ":storage_adapter_unittest.m", ":util_unittest.m", ":volume_manager_types_unittest.m",
diff --git a/ui/file_manager/file_manager/common/js/api.js b/ui/file_manager/file_manager/common/js/api.js index 675ddfea..8dadd0b 100644 --- a/ui/file_manager/file_manager/common/js/api.js +++ b/ui/file_manager/file_manager/common/js/api.js
@@ -101,6 +101,17 @@ } /** + * Wrap the chrome.fileManagerPrivate.getDlpMetadata function in an async/await + * compatible style. + * @param {!Array<!Entry>} entries entries to be checked + * @return {!Promise<!Array<!chrome.fileManagerPrivate.DlpMetadata>>} list of + * DlpMetadata + */ +export async function getDlpMetadata(entries) { + return promisify(chrome.fileManagerPrivate.getDlpMetadata, entries); +} + +/** * Lists Guest OSs which support having their files mounted. * @return {!Promise<!Array<!chrome.fileManagerPrivate.MountableGuest>>} */
diff --git a/ui/file_manager/file_manager/common/js/recent_date_bucket.js b/ui/file_manager/file_manager/common/js/recent_date_bucket.js new file mode 100644 index 0000000..c45b800 --- /dev/null +++ b/ui/file_manager/file_manager/common/js/recent_date_bucket.js
@@ -0,0 +1,48 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview Recent date bucket definition and util functions. + */ + +import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js'; + +/** + * Given a date and now date, return the date bucket it belongs to. + * + * @param {!Date|undefined} date + * @param {!Date} now + * @return {!chrome.fileManagerPrivate.RecentDateBucket} + */ +export function getRecentDateBucket(date, now) { + if (!date) { + return chrome.fileManagerPrivate.RecentDateBucket.OLDER; + } + const startOfToday = new Date(now); + startOfToday.setHours(0, 0, 0); + if (date >= startOfToday) { + return chrome.fileManagerPrivate.RecentDateBucket.TODAY; + } + const startOfYesterday = new Date(startOfToday); + startOfYesterday.setDate(startOfToday.getDate() - 1); + if (date >= startOfYesterday) { + return chrome.fileManagerPrivate.RecentDateBucket.YESTERDAY; + } + const startOfThisWeek = new Date(startOfToday); + const localeBasedWeekStart = loadTimeData.getInteger('WEEK_START_FROM') || 0; + const daysDiff = (startOfToday.getDay() - localeBasedWeekStart + 7) % 7; + startOfThisWeek.setDate(startOfToday.getDate() - daysDiff); + if (date >= startOfThisWeek) { + return chrome.fileManagerPrivate.RecentDateBucket.EARLIER_THIS_WEEK; + } + const startOfThisMonth = new Date(now.getFullYear(), now.getMonth(), 1); + if (date >= startOfThisMonth) { + return chrome.fileManagerPrivate.RecentDateBucket.EARLIER_THIS_MONTH; + } + const startOfThisYear = new Date(now.getFullYear(), 0, 1); + if (date >= startOfThisYear) { + return chrome.fileManagerPrivate.RecentDateBucket.EARLIER_THIS_YEAR; + } + return chrome.fileManagerPrivate.RecentDateBucket.OLDER; +}
diff --git a/ui/file_manager/file_manager/common/js/recent_date_bucket_unittest.m.js b/ui/file_manager/file_manager/common/js/recent_date_bucket_unittest.m.js new file mode 100644 index 0000000..c11f153 --- /dev/null +++ b/ui/file_manager/file_manager/common/js/recent_date_bucket_unittest.m.js
@@ -0,0 +1,157 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js'; +import {assertEquals} from 'chrome://test/chai_assert.js'; + +import {installMockChrome} from '../../common/js/mock_chrome.js'; + +import {getRecentDateBucket} from './recent_date_bucket.js'; + +export function setUp() { + loadTimeData.resetForTesting({ + WEEK_START_FROM: 1, + }); + + const mockChrome = { + fileManagerPrivate: { + RecentDateBucket: { + TODAY: 'today', + YESTERDAY: 'yesterday', + EARLIER_THIS_WEEK: 'earlier_this_week', + EARLIER_THIS_MONTH: 'earlier_this_month', + EARLIER_THIS_YEAR: 'earlier_this_year', + OLDER: 'older', + }, + } + }; + installMockChrome(mockChrome); +} + +export function testGetRecentDateBucket() { + assertEquals( + getRecentDateBucket(undefined, new Date()), + chrome.fileManagerPrivate.RecentDateBucket.OLDER); + + // May 9, 2022, Monday, 12:00pm Local time. + const middleOfMonth = new Date(2022, 4, 9, 12, 0, 0); + // Mar 1, 2022, Tuesday, 8:00am Local time. + const startOfMonth = new Date(2022, 2, 1, 8, 0, 0); + // Jan 1, 2022, Saturday, 4:00pm Local time. + const startOfYear = new Date(2022, 0, 1, 16, 0, 0); + + const testSamples = [ + { + today: middleOfMonth, + tests: [ + { + // Future date: June 1, 2022, Wednesday, 12:00pm Local time. + date: new Date(2022, 5, 1, 12, 0, 0), + bucket: chrome.fileManagerPrivate.RecentDateBucket.TODAY, + }, + { + // May 9, 2022, Monday, 08:30am Local time. + date: new Date(2022, 4, 9, 8, 30, 0), + bucket: chrome.fileManagerPrivate.RecentDateBucket.TODAY + }, + { + // May 8, 2022, Sunday, 10:30am Local time. + date: new Date(2022, 4, 8, 10, 30, 0), + bucket: chrome.fileManagerPrivate.RecentDateBucket.YESTERDAY, + }, + { + // May 7, 2022, Saturday, 07:30am Local time. + date: new Date(2022, 4, 7, 7, 30, 0), + bucket: chrome.fileManagerPrivate.RecentDateBucket.EARLIER_THIS_MONTH, + }, + { + // May 1, 2022, Monday, 10:30am Local time. + date: new Date(2022, 4, 1, 10, 30, 0), + bucket: chrome.fileManagerPrivate.RecentDateBucket.EARLIER_THIS_MONTH, + }, + { + // April 28, 2022, Thursday, 10:30am Local time. + date: new Date(2022, 3, 28, 10, 30, 0), + bucket: chrome.fileManagerPrivate.RecentDateBucket.EARLIER_THIS_YEAR, + }, + ] + }, + + { + today: startOfMonth, + tests: [ + { + // Future date: Mar 1, 2022, Tuesday, 12:00pm Local time. + date: new Date(2022, 2, 1, 12, 0, 0), + bucket: chrome.fileManagerPrivate.RecentDateBucket.TODAY, + }, + { + // Mar 1, 2022, Tuesday, 3:00am Local time. + date: new Date(2022, 2, 1, 3, 0, 0), + bucket: chrome.fileManagerPrivate.RecentDateBucket.TODAY, + }, + { + // Feb 28, 2022, Monday, 08:30am Local time. + date: new Date(2022, 1, 28, 8, 30, 0), + bucket: chrome.fileManagerPrivate.RecentDateBucket.YESTERDAY, + }, + { + // Feb 27, 2022, Sunday, 10:30am Local time. + date: new Date(2022, 1, 27, 10, 30, 0), + bucket: chrome.fileManagerPrivate.RecentDateBucket.EARLIER_THIS_YEAR, + }, + { + // Feb 10, 2022, Thursday, 10:30am Local time. + date: new Date(2022, 1, 10, 10, 30, 0), + bucket: chrome.fileManagerPrivate.RecentDateBucket.EARLIER_THIS_YEAR, + } + ] + }, + + { + today: startOfYear, + tests: [ + { + + // Future date: Jan 2, 2022, Sunday, 12:00pm Local time. + date: new Date(2022, 0, 2, 12, 0, 0), + bucket: chrome.fileManagerPrivate.RecentDateBucket.TODAY, + }, + { + // Jan 1, 2022, Saturday, 08:30am Local time. + date: new Date(2022, 0, 1, 8, 30, 0), + bucket: chrome.fileManagerPrivate.RecentDateBucket.TODAY, + }, + { + // Dec 31, 2021, Friday, 10:30am Local time. + date: new Date(2021, 11, 31, 10, 30, 0), + bucket: chrome.fileManagerPrivate.RecentDateBucket.YESTERDAY, + }, + { + // Dec 27, 2021, Monday, 07:30am Local time. + date: new Date(2021, 11, 27, 7, 30, 0), + bucket: chrome.fileManagerPrivate.RecentDateBucket.EARLIER_THIS_WEEK, + }, + { + // Dec 2, 2021, Thursday, 10:30am Local time. + date: new Date(2021, 11, 2, 10, 30, 0), + bucket: chrome.fileManagerPrivate.RecentDateBucket.OLDER, + }, + { + // Nov 28, 2021, Sunday, 10:30am Local time. + date: new Date(2021, 10, 28, 10, 30, 0), + bucket: chrome.fileManagerPrivate.RecentDateBucket.OLDER, + } + ] + } + + ]; + + for (const testSample of testSamples) { + for (const test of testSample.tests) { + assertEquals( + getRecentDateBucket(test.date, testSample.today), test.bucket); + } + } +}
diff --git a/ui/file_manager/file_manager/definitions/file_manager.d.ts b/ui/file_manager/file_manager/definitions/file_manager.d.ts new file mode 100644 index 0000000..8d7f6df1 --- /dev/null +++ b/ui/file_manager/file_manager/definitions/file_manager.d.ts
@@ -0,0 +1,25 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/// <reference types="./volume_manager" /> + +/** + * Type definition for foreground/js/file_manager.js:FileManager. + * + * For now only defining the bare minimum. + */ +interface FileManager { + volumeManager: VolumeManager; +} + +/** + * The singleton instance for FileManager is available in the Window object. + */ +declare global { + interface Window { + fileManager: FileManager; + } +} + +export {};
diff --git a/ui/file_manager/file_manager/definitions/volume_manager.d.ts b/ui/file_manager/file_manager/definitions/volume_manager.d.ts new file mode 100644 index 0000000..928f334 --- /dev/null +++ b/ui/file_manager/file_manager/definitions/volume_manager.d.ts
@@ -0,0 +1,10 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * Type definition for file_manager/externs/volume_manager.js:VolumeManager. + * + * For now only defining the bare minimum. + */ +interface VolumeManager {}
diff --git a/ui/file_manager/file_manager/externs/ts/store.js b/ui/file_manager/file_manager/externs/ts/store.js new file mode 100644 index 0000000..a4dfa22 --- /dev/null +++ b/ui/file_manager/file_manager/externs/ts/store.js
@@ -0,0 +1,34 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview Simplified interfaces of the Store used by Files app. Used to + * be able to type check the JS files using Closure compiler. + * See lib/base_store.ts and state/store.ts for the implementation. + */ + +/** @record */ +class Store { + /** @param {!Object} action */ + dispatch(action) {} + + /** + * @param {!StoreObserver} observer + * @returns {function()} the function to unsubscribe. + */ + subscribe(observer) {} + + /** @param {!StoreObserver} observer */ + usubscribe(observer) {} +} + +/** + * Interface marked as `record` so it doesn't have to mark implements + * explicitly. + * @record + */ +class StoreObserver { + /** @param {!Object} newState */ + onStateChanged(newState) {} +}
diff --git a/ui/file_manager/file_manager/foreground/js/BUILD.gn b/ui/file_manager/file_manager/foreground/js/BUILD.gn index 43a0255..b17f217 100644 --- a/ui/file_manager/file_manager/foreground/js/BUILD.gn +++ b/ui/file_manager/file_manager/foreground/js/BUILD.gn
@@ -444,6 +444,8 @@ "//ui/webui/resources/js/cr/ui:list_selection_model.m", "//ui/webui/resources/js/cr/ui:list_single_selection_model.m", ] + + externs_list = [ "//ui/file_manager/file_manager/externs/ts/store.js" ] } js_unittest("directory_model_unittest.m") {
diff --git a/ui/file_manager/file_manager/foreground/js/directory_model.js b/ui/file_manager/file_manager/foreground/js/directory_model.js index a23fda5..71543c64 100644 --- a/ui/file_manager/file_manager/foreground/js/directory_model.js +++ b/ui/file_manager/file_manager/foreground/js/directory_model.js
@@ -18,6 +18,8 @@ import {FakeEntry, FilesAppDirEntry, FilesAppEntry} from '../../externs/files_app_entry_interfaces.js'; import {VolumeInfo} from '../../externs/volume_info.js'; import {VolumeManager} from '../../externs/volume_manager.js'; +import {changeDirectory} from '../../state/actions.js'; +import {getStore} from '../../state/store.js'; import {constants} from './constants.js'; import {ContentScanner, CrostiniMounter, DirectoryContents, DirectoryContentScanner, DriveMetadataSearchContentScanner, DriveSearchContentScanner, FileFilter, FileListContext, GuestOsMounter, LocalSearchContentScanner, MediaViewContentScanner, RecentContentScanner} from './directory_contents.js'; @@ -129,6 +131,9 @@ /** @private {FilesAppDirEntry} */ this.myFilesEntry_ = null; + + /** @private {!Store} */ + this.store_ = getStore(); } /** @@ -1174,6 +1179,9 @@ event.newDirEntry = dirEntry; event.volumeChanged = previousVolumeInfo !== currentVolumeInfo; this.dispatchEvent(event); + if (util.isFilesAppExperimental()) { + this.store_.dispatch(changeDirectory({to: dirEntry})); + } }); }
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/BUILD.gn b/ui/file_manager/file_manager/foreground/js/metadata/BUILD.gn index 7a32d2e6..6ce18d3 100644 --- a/ui/file_manager/file_manager/foreground/js/metadata/BUILD.gn +++ b/ui/file_manager/file_manager/foreground/js/metadata/BUILD.gn
@@ -112,6 +112,7 @@ deps = [ ":metadata_item", ":metadata_provider", + "//ui/file_manager/file_manager/common/js:api", ] } @@ -314,6 +315,7 @@ js_library("multi_metadata_provider") { deps = [ ":content_metadata_provider", + ":dlp_metadata_provider", ":external_metadata_provider", ":file_system_metadata_provider", ":metadata_item", @@ -328,6 +330,7 @@ js_unittest("multi_metadata_provider_unittest.m") { deps = [ ":content_metadata_provider", + ":dlp_metadata_provider", ":external_metadata_provider", ":file_system_metadata_provider", ":metadata_request",
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/dlp_metadata_provider.js b/ui/file_manager/file_manager/foreground/js/metadata/dlp_metadata_provider.js index bdbc67a..6d22d9c 100644 --- a/ui/file_manager/file_manager/foreground/js/metadata/dlp_metadata_provider.js +++ b/ui/file_manager/file_manager/foreground/js/metadata/dlp_metadata_provider.js
@@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import {getDlpMetadata} from '../../../common/js/api.js'; + import {MetadataItem} from './metadata_item.js'; import {MetadataProvider} from './metadata_provider.js'; @@ -23,14 +25,30 @@ } // TODO(crbug.com/1297603): Early return if DLP isn't enabled. - // TODO(crbug.com/1326932): Call chrome.fileManagerPrivate to check if the - // file is managed. - return Promise.all(requests.map(_request => new MetadataItem())); + const entries = requests.map(_request => { + return _request.entry; + }); + try { + const dlpMetadataList = await getDlpMetadata(entries); + const results = []; + for (let i = 0; i < dlpMetadataList.length; i++) { + const item = new MetadataItem(); + item.isDlpRestricted = dlpMetadataList[i].isDlpRestricted; + item.sourceUrl = dlpMetadataList[i].sourceUrl; + results.push(item); + } + return results; + } catch (error) { + console.warn(error); + return requests.map(() => { + return new MetadataItem(); + }); + } } } /** @const {!Array<string>} */ DlpMetadataProvider.PROPERTY_NAMES = [ // TODO(crbug.com/1329770): Consider using an enum for this property. - 'isDlpRestricted', + 'isDlpRestricted', 'sourceUrl' ]; \ No newline at end of file
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/metadata_item.js b/ui/file_manager/file_manager/foreground/js/metadata/metadata_item.js index 3c8d9080..4c7138c 100644 --- a/ui/file_manager/file_manager/foreground/js/metadata/metadata_item.js +++ b/ui/file_manager/file_manager/foreground/js/metadata/metadata_item.js
@@ -280,5 +280,17 @@ * @public {boolean|undefined} */ this.isExternalMedia; + + /** + * Whether the entry is under any DataLeakPrevention policy. + * @public {boolean|undefined} + */ + this.isDlpRestricted; + + /** + * Source URL that can be used to check DataLeakPrevention policy. + * @public {string|undefined} + */ + this.sourceUrl; } }
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/metadata_model.js b/ui/file_manager/file_manager/foreground/js/metadata/metadata_model.js index cdfb8550..bb41b60 100644 --- a/ui/file_manager/file_manager/foreground/js/metadata/metadata_model.js +++ b/ui/file_manager/file_manager/foreground/js/metadata/metadata_model.js
@@ -6,6 +6,7 @@ import {VolumeManager} from '../../../externs/volume_manager.js'; import {ContentMetadataProvider} from './content_metadata_provider.js'; +import {DlpMetadataProvider} from './dlp_metadata_provider.js'; import {ExternalMetadataProvider} from './external_metadata_provider.js'; import {FileSystemMetadataProvider} from './file_system_metadata_provider.js'; import {MetadataCacheSet, MetadataCacheSetStorageForObject} from './metadata_cache_set.js'; @@ -64,7 +65,8 @@ static create(volumeManager) { return new MetadataModel(new MultiMetadataProvider( new FileSystemMetadataProvider(), new ExternalMetadataProvider(), - new ContentMetadataProvider(), volumeManager)); + new ContentMetadataProvider(), new DlpMetadataProvider(), + volumeManager)); } /**
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/multi_metadata_provider.js b/ui/file_manager/file_manager/foreground/js/metadata/multi_metadata_provider.js index 929d11d5..3abdef6 100644 --- a/ui/file_manager/file_manager/foreground/js/metadata/multi_metadata_provider.js +++ b/ui/file_manager/file_manager/foreground/js/metadata/multi_metadata_provider.js
@@ -9,6 +9,7 @@ import {VolumeManager} from '../../../externs/volume_manager.js'; import {ContentMetadataProvider} from './content_metadata_provider.js'; +import {DlpMetadataProvider} from './dlp_metadata_provider.js'; import {ExternalMetadataProvider} from './external_metadata_provider.js'; import {FileSystemMetadataProvider} from './file_system_metadata_provider.js'; import {MetadataItem} from './metadata_item.js'; @@ -21,14 +22,16 @@ * @param {!FileSystemMetadataProvider} fileSystemMetadataProvider * @param {!ExternalMetadataProvider} externalMetadataProvider * @param {!ContentMetadataProvider} contentMetadataProvider + * @param {!DlpMetadataProvider} dlpMetadataProvider * @param {!VolumeManager} volumeManager */ constructor( fileSystemMetadataProvider, externalMetadataProvider, - contentMetadataProvider, volumeManager) { + contentMetadataProvider, dlpMetadataProvider, volumeManager) { super(FileSystemMetadataProvider.PROPERTY_NAMES .concat(ExternalMetadataProvider.PROPERTY_NAMES) - .concat(ContentMetadataProvider.PROPERTY_NAMES)); + .concat(ContentMetadataProvider.PROPERTY_NAMES) + .concat(DlpMetadataProvider.PROPERTY_NAMES)); /** @private @const {!FileSystemMetadataProvider} */ this.fileSystemMetadataProvider_ = fileSystemMetadataProvider; @@ -39,6 +42,9 @@ /** @private @const {!ContentMetadataProvider} */ this.contentMetadataProvider_ = contentMetadataProvider; + /** @private @const {!DlpMetadataProvider} */ + this.dlpMetadataProvider_ = dlpMetadataProvider; + /** @private @const {!VolumeManager} */ this.volumeManager_ = volumeManager; } @@ -53,12 +59,14 @@ const externalRequests = []; const contentRequests = []; const fallbackContentRequests = []; + const dlpRequests = []; requests.forEach(request => { // Group property names. const fileSystemPropertyNames = []; const externalPropertyNames = []; const contentPropertyNames = []; const fallbackContentPropertyNames = []; + const dlpPropertyNames = []; for (let i = 0; i < request.names.length; i++) { const name = request.names[i]; const isFileSystemProperty = @@ -67,7 +75,11 @@ ExternalMetadataProvider.PROPERTY_NAMES.indexOf(name) !== -1; const isContentProperty = ContentMetadataProvider.PROPERTY_NAMES.indexOf(name) !== -1; - assert(isFileSystemProperty || isExternalProperty || isContentProperty); + const isDlpProperty = + DlpMetadataProvider.PROPERTY_NAMES.indexOf(name) !== -1; + assert( + isFileSystemProperty || isExternalProperty || isContentProperty || + isDlpProperty); assert(!(isFileSystemProperty && isContentProperty)); // If the property can be obtained both from ExternalProvider and from // ContentProvider, we can obtain the property from ExternalProvider @@ -88,6 +100,9 @@ if (isContentProperty) { contentPropertyNames.push(name); } + if (isDlpProperty) { + dlpPropertyNames.push(name); + } } const volumeInfo = this.volumeManager_.getVolumeInfo(request.entry); const addRequests = (list, names) => { @@ -128,6 +143,7 @@ contentRequests, contentPropertyNames.concat(fallbackContentPropertyNames)); } + addRequests(dlpRequests, dlpPropertyNames); }); const get = (provider, inRequests) => { @@ -156,14 +172,13 @@ return dirtyMap[request.entry.toURL()]; })); }); + const dlpPromise = get(this.dlpMetadataProvider_, dlpRequests); // Merge results. return Promise .all([ - fileSystemPromise, - externalPromise, - contentPromise, - fallbackContentPromise, + fileSystemPromise, externalPromise, contentPromise, + fallbackContentPromise, dlpPromise ]) .then(resultsList => { const integratedResults = {};
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/multi_metadata_provider_unittest.m.js b/ui/file_manager/file_manager/foreground/js/metadata/multi_metadata_provider_unittest.m.js index 89f9b6a..f1d4b50a 100644 --- a/ui/file_manager/file_manager/foreground/js/metadata/multi_metadata_provider_unittest.m.js +++ b/ui/file_manager/file_manager/foreground/js/metadata/multi_metadata_provider_unittest.m.js
@@ -9,6 +9,7 @@ import {VolumeManager} from '../../../externs/volume_manager.js'; import {ContentMetadataProvider} from './content_metadata_provider.js'; +import {DlpMetadataProvider} from './dlp_metadata_provider.js'; import {ExternalMetadataProvider} from './external_metadata_provider.js'; import {FileSystemMetadataProvider} from './file_system_metadata_provider.js'; import {MetadataRequest} from './metadata_request.js'; @@ -97,6 +98,12 @@ ]); } }), + /** @type {!DlpMetadataProvider} */ ({ + get: function(requests) { + assertEquals(0, requests.length); + return Promise.resolve([]); + } + }), volumeManager); reportPromise( @@ -155,6 +162,12 @@ return Promise.resolve([results[requests[0].entry.toURL()]]); }, }), + /** @type {!DlpMetadataProvider} */ ({ + get: function(requests) { + assertEquals(0, requests.length); + return Promise.resolve([]); + } + }), volumeManager); reportPromise( @@ -212,6 +225,12 @@ return Promise.resolve([]); }, }), + /** @type {!DlpMetadataProvider} */ ({ + get: function(requests) { + assertEquals(0, requests.length); + return Promise.resolve([]); + } + }), volumeManager); reportPromise( @@ -236,3 +255,47 @@ }), callback); } + +export function testDlpMetadataProvider(callback) { + const model = new MultiMetadataProvider( + /** @type {!FileSystemMetadataProvider} */ ({ + get: function(requests) { + assertEquals(0, requests.length); + return Promise.resolve([]); + } + }), + /** @type {!ExternalMetadataProvider} */ ({ + get: function(requests) { + assertEquals(0, requests.length); + return Promise.resolve([]); + } + }), + /** @type {!ContentMetadataProvider} */ ({ + get: function(requests) { + assertEquals(0, requests.length); + return Promise.resolve([]); + }, + }), + /** @type {!DlpMetadataProvider} */ ({ + get: function(requests) { + assertEquals(1, requests.length); + return Promise.resolve([{ + sourceUrl: 'url', + isDlpRestricted: true, + }]); + } + }), + volumeManager); + + reportPromise( + model + .get([ + new MetadataRequest(entryA, ['sourceUrl', 'isDlpRestricted']), + ]) + .then(results => { + assertEquals(1, results.length); + assertEquals('url', results[0].sourceUrl); + assertEquals(true, results[0].isDlpRestricted); + }), + callback); +}
diff --git a/ui/file_manager/file_manager/lib/base_store.ts b/ui/file_manager/file_manager/lib/base_store.ts index fe700a2..618ffe8 100644 --- a/ui/file_manager/file_manager/lib/base_store.ts +++ b/ui/file_manager/file_manager/lib/base_store.ts
@@ -87,7 +87,7 @@ /** * Subscribe to Store changes/updates. * @param observer Callback called whenever the Store is updated. - * @returns callback to unsusbscribe the obserer. + * @returns callback to unsusbscribe the observer. */ subscribe(observer: StoreObserver<StateType>): (observer: StoreObserver<StateType>) => void {
diff --git a/ui/file_manager/file_manager/state/actions.ts b/ui/file_manager/file_manager/state/actions.ts new file mode 100644 index 0000000..2cf33a5 --- /dev/null +++ b/ui/file_manager/file_manager/state/actions.ts
@@ -0,0 +1,36 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import {BaseAction} from '../lib/base_store.js'; + +import {FileKey} from './file_key.js'; + +/** + * Base class for all Actions in Files app. + * + * It enforces the type/enum for the `type` attribute. + */ +export interface Action extends BaseAction { + type: Actions; +} + +/** Enum to identify every Action in Files app. */ +export const enum Actions { + CHANGE_DIRECTORY = 'change-directory', +} + +/** Action to request to change the Current Directory. */ +export interface ChangeDirectoryAction extends Action { + newDirectory: Entry; + key: FileKey; +} + +/** Factory for the ChangeDirectoryAction. */ +export function changeDirectory({to}: {to: Entry}): ChangeDirectoryAction { + return { + type: Actions.CHANGE_DIRECTORY, + newDirectory: to, + key: to.toURL(), + }; +}
diff --git a/ui/file_manager/file_manager/state/file_key.ts b/ui/file_manager/file_manager/state/file_key.ts new file mode 100644 index 0000000..280da3ac --- /dev/null +++ b/ui/file_manager/file_manager/state/file_key.ts
@@ -0,0 +1,10 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * Key to identify a file/entry. + * + * Type to distinguish it from a regular string. + */ +export type FileKey = string;
diff --git a/ui/file_manager/file_manager/state/reducers.ts b/ui/file_manager/file_manager/state/reducers.ts index 0ed20d6..94d70063 100644 --- a/ui/file_manager/file_manager/state/reducers.ts +++ b/ui/file_manager/file_manager/state/reducers.ts
@@ -2,16 +2,77 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import {BaseAction} from '../lib/base_store.js'; +import {PathComponent} from '../foreground/js/path_component.js'; -import {State} from './state.js'; +import {Action, Actions, ChangeDirectoryAction} from './actions.js'; +import {CurrentDirectory, State} from './state.js'; -/** TODO(lucmult): Document this. */ -export function rootReducer(currentState: State, action: BaseAction): State { - if (action.type) { - return Object.assign(currentState, {}); +/** + * Root reducer for Files app. + * It dispatches to other reducers to update different parts of the State. + */ +export function rootReducer(currentState: State, action: Action): State { + // Before any actual Reducer, we cache the entries, so the reducers can just + // use any entry from `allEntries`. + const state = cacheEntries(currentState, action); + + switch (action.type) { + case Actions.CHANGE_DIRECTORY: + return Object.assign(state, { + currentDirectory: + changeDirectory(state, action as ChangeDirectoryAction) + }); + + default: + console.error(`invalid action: ${action.type}`); + return state; + } +} + +/** Caches the Action's entry in the `allEntries` attribute. */ +export function cacheEntries(currentState: State, action: Action): State { + if (action.type === Actions.CHANGE_DIRECTORY) { + const {newDirectory, key} = (action as ChangeDirectoryAction); + + const allEntries = currentState.allEntries || {}; + const entryData = allEntries[key] || {}; + allEntries[key] = Object.assign(entryData, { + entry: newDirectory, + }); + + currentState.allEntries = allEntries; } - console.error('invalid action'); return currentState; } + +/** Reducer that updates the `currentDirectory` attributes. */ +export function changeDirectory( + currentState: State, action: ChangeDirectoryAction): CurrentDirectory|null { + const fileData = currentState.allEntries[action.key]; + if (!fileData) { + console.debug(`Can't find the entry with ${action.key}`); + return currentState.currentDirectory || null; + } + + // TODO(lucmult): Find a correct way to grab the VolumeManager. + const volumeManager = window.fileManager.volumeManager; + if (!volumeManager) { + console.debug(`VolumeManager not available yet.`); + return currentState.currentDirectory || null; + } + + const components = + PathComponent.computeComponentsFromEntry(fileData.entry, volumeManager); + + return Object.assign(currentState.currentDirectory || {}, { + key: (action as ChangeDirectoryAction).key, + pathComponents: components.map(c => { + return { + name: c.name, + label: c.name, + key: c.url_, + }; + }) + }); +}
diff --git a/ui/file_manager/file_manager/state/state.ts b/ui/file_manager/file_manager/state/state.ts index 7b60eed..21596cf 100644 --- a/ui/file_manager/file_manager/state/state.ts +++ b/ui/file_manager/file_manager/state/state.ts
@@ -2,5 +2,49 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -/** TODO(lucmult): Document this. */ -export interface State {} +import {FilesAppDirEntry, FilesAppEntry} from '../externs/files_app_entry_interfaces.js'; + +import {FileKey} from './file_key.js'; + +export type AnyEntry = Entry|FilesAppEntry; +export type OnlyDirEntry = DirectoryEntry|FilesAppDirEntry; + +/** The data for each individual file/entry. */ +export interface FileData { + entry: AnyEntry; +} + +/** + * Describes each part of the path, as in each parent folder and/or root volume. + */ +export interface PathComponent { + // The actual name for folder/volume. + name: string; + + // Label to display to the user, it might differ from the name when the folder + // or volume has a translation or comercial name. + label: string; + + // The key to the actual folder or root, it might be a key for a fake entry. + key: FileKey; +} + +/** The Current Directory. */ +export interface CurrentDirectory { + // Key to the current directory. + key: FileKey; + + // Elements for the user facing path, e.g. the breadcrumbs. + pathComponents: PathComponent[]; +} + +/** Files app's state. */ +export interface State { + // A big bucket with all entries managed by the app. + allEntries: { + [key: FileKey]: FileData, + }; + + // The currently selected directory. + currentDirectory?: CurrentDirectory; +}
diff --git a/ui/file_manager/file_manager/state/store.ts b/ui/file_manager/file_manager/state/store.ts index 769e428..ad017739 100644 --- a/ui/file_manager/file_manager/state/store.ts +++ b/ui/file_manager/file_manager/state/store.ts
@@ -2,8 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import {BaseAction, BaseStore} from '../lib/base_store.js'; +import {BaseStore} from '../lib/base_store.js'; +import {Action} from './actions.js'; import {rootReducer} from './reducers.js'; import {State} from './state.js'; @@ -12,7 +13,7 @@ * * It enforces the types for the State and the Actions managed by Files app. */ -export type Store = BaseStore<State, BaseAction>; +export type Store = BaseStore<State, Action>; /** * Store singleton instance. @@ -28,7 +29,7 @@ */ export function getStore(): Store { if (!store) { - store = new BaseStore<State, BaseAction>({}, rootReducer); + store = new BaseStore<State, Action>({allEntries: {}}, rootReducer); } return store;
diff --git a/ui/file_manager/file_names.gni b/ui/file_manager/file_names.gni index febc286..a22a24fb 100644 --- a/ui/file_manager/file_names.gni +++ b/ui/file_manager/file_names.gni
@@ -42,7 +42,10 @@ "file_manager/background/js/media_scanner.js", "file_manager/background/js/metadata_proxy.js", "file_manager/background/js/metrics_start.js", + + # TODO(lucmult): Check if we can move those mocks to the test files section. "file_manager/background/js/mock_crostini.js", + "file_manager/background/js/mock_drive_sync_handler.js", "file_manager/background/js/mock_file_operation_manager.js", "file_manager/background/js/mock_media_scanner.js", "file_manager/background/js/mock_progress_center.js", @@ -83,6 +86,7 @@ "file_manager/common/js/notifications_browser_proxy.js", "file_manager/common/js/power.js", "file_manager/common/js/progress_center_common.js", + "file_manager/common/js/recent_date_bucket.js", "file_manager/common/js/storage_adapter.js", "file_manager/common/js/test_error_reporting.js", "file_manager/common/js/test_importer_common.js", @@ -259,6 +263,8 @@ "file_manager/state/store.ts", "file_manager/state/state.ts", "file_manager/state/reducers.ts", + "file_manager/state/actions.ts", + "file_manager/state/file_key.ts", ] # Generated files are built from the repository and the final JS files is only @@ -312,4 +318,90 @@ "file_manager/foreground/js/ui/banners/warning_banner.js", "file_manager/foreground/js/ui/breadcrumb.js", ] + # END: generated_js_files. + +# Test files: +unittest_files = [ + "file_manager/common/js/util_unittest.m.js", + "file_manager/common/js/filtered_volume_manager_unittest.m.js", + "file_manager/common/js/file_type_unittest.m.js", + "file_manager/common/js/lru_cache_unittest.m.js", + "file_manager/common/js/importer_common_unittest.m.js", + "file_manager/common/js/files_app_entry_types_unittest.m.js", + "file_manager/common/js/recent_date_bucket_unittest.m.js", + "file_manager/common/js/storage_adapter_unittest.m.js", + "file_manager/common/js/volume_manager_types_unittest.m.js", + "file_manager/background/js/mount_metrics_unittest.m.js", + "file_manager/background/js/drive_sync_handler_unittest.m.js", + "file_manager/background/js/media_import_handler_unittest.m.js", + "file_manager/background/js/task_queue_unittest.m.js", + "file_manager/background/js/file_operation_handler_unittest.m.js", + "file_manager/background/js/file_operation_manager_unittest.m.js", + "file_manager/background/js/trash_unittest.m.js", + "file_manager/background/js/duplicate_finder_unittest.m.js", + "file_manager/background/js/volume_manager_unittest.m.js", + "file_manager/background/js/media_scanner_unittest.m.js", + "file_manager/background/js/import_history_unittest.m.js", + "file_manager/background/js/metadata_proxy_unittest.m.js", + "file_manager/background/js/crostini_unittest.m.js", + "file_manager/background/js/device_handler_unittest.m.js", + "file_manager/foreground/elements/files_password_dialog_unittest.m.js", + "file_manager/foreground/elements/files_xf_elements_unittest.m.js", + "file_manager/foreground/elements/files_toast_unittest.m.js", + "file_manager/foreground/elements/files_tooltip_unittest.m.js", + "file_manager/foreground/js/metadata/image_orientation_unittest.m.js", + "file_manager/foreground/js/metadata/metadata_cache_item_unittest.m.js", + "file_manager/foreground/js/metadata/exif_parser_unittest.m.js", + "file_manager/foreground/js/metadata/thumbnail_model_unittest.m.js", + "file_manager/foreground/js/metadata/metadata_model_unittest.m.js", + "file_manager/foreground/js/metadata/content_metadata_provider_unittest.m.js", + "file_manager/foreground/js/metadata/external_metadata_provider_unittest.m.js", + "file_manager/foreground/js/metadata/file_system_metadata_provider_unittest.m.js", + "file_manager/foreground/js/metadata/metadata_cache_set_unittest.m.js", + "file_manager/foreground/js/metadata/multi_metadata_provider_unittest.m.js", + "file_manager/foreground/js/file_manager_commands_unittest.m.js", + "file_manager/foreground/js/task_controller_unittest.m.js", + "file_manager/foreground/js/thumbnail_loader_unittest.m.js", + "file_manager/foreground/js/directory_contents_unittest.m.js", + "file_manager/foreground/js/file_list_model_unittest.m.js", + "file_manager/foreground/js/banner_controller_unittest.m.js", + "file_manager/foreground/js/providers_model_unittest.m.js", + "file_manager/foreground/js/spinner_controller_unittest.m.js", + "file_manager/foreground/js/banner_util_unittest.m.js", + "file_manager/foreground/js/list_thumbnail_loader_unittest.m.js", + "file_manager/foreground/js/file_type_filters_controller_unittest.m.js", + "file_manager/foreground/js/path_component_unittest.m.js", + "file_manager/foreground/js/actions_model_unittest.m.js", + "file_manager/foreground/js/ui/file_manager_dialog_base_unittest.m.js", + "file_manager/foreground/js/ui/actions_submenu_unittest.m.js", + "file_manager/foreground/js/ui/file_table_unittest.m.js", + "file_manager/foreground/js/ui/file_tap_handler_unittest.m.js", + "file_manager/foreground/js/ui/install_linux_package_dialog_unittest.m.js", + "file_manager/foreground/js/ui/file_table_list_unittest.m.js", + "file_manager/foreground/js/ui/multi_menu_unittest.m.js", + "file_manager/foreground/js/ui/banners/state_banner_unittest.m.js", + "file_manager/foreground/js/ui/banners/educational_banner_unittest.m.js", + "file_manager/foreground/js/ui/banners/warning_banner_unittest.m.js", + "file_manager/foreground/js/ui/breadcrumb_unittest.m.js", + "file_manager/foreground/js/ui/file_list_selection_model_unittest.m.js", + "file_manager/foreground/js/ui/directory_tree_unittest.m.js", + "file_manager/foreground/js/navigation_list_model_unittest.m.js", + "file_manager/foreground/js/directory_model_unittest.m.js", + "file_manager/foreground/js/file_tasks_unittest.m.js", + "file_manager/foreground/js/file_transfer_controller_unittest.m.js", + "file_manager/foreground/js/import_controller_unittest.m.js", + "image_loader/scheduler_unittest.m.js", + "image_loader/image_loader_unittest.m.js", + "image_loader/cache_unittest.m.js", + "image_loader/image_loader_client_unittest.m.js", +] + +generated_test_htmls = [] +foreach(_t, unittest_files) { + generated_test_htmls += [ string_replace(_t, ".js", "_gen.html") ] +} + +# Files that don't have the generated HTML, but are used for tests. +unittest_files += [ "file_manager/common/js/mock_util.js" ] +# END: Test files.
diff --git a/ui/file_manager/tsconfig_base.json b/ui/file_manager/tsconfig_base.json index f79e3053..024050e 100644 --- a/ui/file_manager/tsconfig_base.json +++ b/ui/file_manager/tsconfig_base.json
@@ -2,6 +2,13 @@ "extends": "../../tools/typescript/tsconfig_base.json", "compilerOptions": { "allowJs": true, - "importsNotUsedAsValues": "preserve" + "importsNotUsedAsValues": "preserve", + "typeRoots": [ + "../../third_party/node/node_modules/@types" + ], + "types": [ + "filesystem", + "filewriter" + ] } }
diff --git a/ui/gl/direct_composition_surface_win.cc b/ui/gl/direct_composition_surface_win.cc index cab0de03..480c380 100644 --- a/ui/gl/direct_composition_surface_win.cc +++ b/ui/gl/direct_composition_surface_win.cc
@@ -431,7 +431,7 @@ // EGL_KHR_no_config_context surface compatibility is required to be able to // MakeCurrent with the default pbuffer surface. - if (!display->ext->b_EGL_KHR_no_config_context) { + if (!display->IsEGLNoConfigContextSupported()) { DLOG(ERROR) << "EGL_KHR_no_config_context not supported"; return; }
diff --git a/ui/gl/generate_bindings.py b/ui/gl/generate_bindings.py index 9970647..dfd2196 100755 --- a/ui/gl/generate_bindings.py +++ b/ui/gl/generate_bindings.py
@@ -2814,23 +2814,18 @@ 'EGL_ANGLE_display_semaphore_share_group', 'EGL_ANGLE_display_texture_share_group', 'EGL_ANGLE_context_virtualization', - 'EGL_ANGLE_create_context_backwards_compatible', 'EGL_ANGLE_create_context_client_arrays', 'EGL_ANGLE_create_context_webgl_compatibility', 'EGL_ANGLE_external_context_and_surface', 'EGL_ANGLE_keyed_mutex', - 'EGL_ANGLE_robust_resource_initialization', 'EGL_ANGLE_surface_orientation', 'EGL_ANGLE_window_fixed_size', - 'EGL_ARM_implicit_external_sync', 'EGL_CHROMIUM_create_context_bind_generates_resource', 'EGL_EXT_create_context_robustness', 'EGL_EXT_gl_colorspace_display_p3', 'EGL_EXT_gl_colorspace_display_p3_passthrough', - 'EGL_EXT_image_dma_buf_import', 'EGL_EXT_pixel_format_float', 'EGL_IMG_context_priority', - 'EGL_KHR_create_context', 'EGL_KHR_gl_colorspace', 'EGL_KHR_no_config_context', 'EGL_KHR_surfaceless_context',
diff --git a/ui/gl/gl_angle_util_vulkan.cc b/ui/gl/gl_angle_util_vulkan.cc index 847e477..c0099aa 100644 --- a/ui/gl/gl_angle_util_vulkan.cc +++ b/ui/gl/gl_angle_util_vulkan.cc
@@ -19,7 +19,7 @@ return nullptr; } - if (!gl::g_driver_egl.client_ext.b_EGL_EXT_device_query) { + if (!gl::GLSurfaceEGL::GetGLDisplayEGL()->IsEGLQueryDeviceSupported()) { LOG(ERROR) << "EGL_EXT_device_query not supported"; return nullptr; }
diff --git a/ui/gl/gl_angle_util_win.cc b/ui/gl/gl_angle_util_win.cc index 69f460e..3427df23 100644 --- a/ui/gl/gl_angle_util_win.cc +++ b/ui/gl/gl_angle_util_win.cc
@@ -24,7 +24,7 @@ return nullptr; } - if (!gl::g_driver_egl.client_ext.b_EGL_EXT_device_query) { + if (!gl::GLSurfaceEGL::GetGLDisplayEGL()->IsEGLQueryDeviceSupported()) { DVLOG(1) << "EGL_EXT_device_query not supported"; return nullptr; }
diff --git a/ui/gl/gl_bindings_autogen_egl.cc b/ui/gl/gl_bindings_autogen_egl.cc index 33bb5b2..8cbbadd99 100644 --- a/ui/gl/gl_bindings_autogen_egl.cc +++ b/ui/gl/gl_bindings_autogen_egl.cc
@@ -285,8 +285,6 @@ gfx::HasExtension(extensions, "EGL_ANDROID_native_fence_sync"); b_EGL_ANGLE_context_virtualization = gfx::HasExtension(extensions, "EGL_ANGLE_context_virtualization"); - b_EGL_ANGLE_create_context_backwards_compatible = gfx::HasExtension( - extensions, "EGL_ANGLE_create_context_backwards_compatible"); b_EGL_ANGLE_create_context_client_arrays = gfx::HasExtension(extensions, "EGL_ANGLE_create_context_client_arrays"); b_EGL_ANGLE_create_context_webgl_compatibility = gfx::HasExtension( @@ -305,8 +303,6 @@ gfx::HasExtension(extensions, "EGL_ANGLE_power_preference"); b_EGL_ANGLE_query_surface_pointer = gfx::HasExtension(extensions, "EGL_ANGLE_query_surface_pointer"); - b_EGL_ANGLE_robust_resource_initialization = - gfx::HasExtension(extensions, "EGL_ANGLE_robust_resource_initialization"); b_EGL_ANGLE_stream_producer_d3d_texture = gfx::HasExtension(extensions, "EGL_ANGLE_stream_producer_d3d_texture"); b_EGL_ANGLE_surface_d3d_texture_2d_share_handle = gfx::HasExtension( @@ -319,8 +315,6 @@ gfx::HasExtension(extensions, "EGL_ANGLE_vulkan_image"); b_EGL_ANGLE_window_fixed_size = gfx::HasExtension(extensions, "EGL_ANGLE_window_fixed_size"); - b_EGL_ARM_implicit_external_sync = - gfx::HasExtension(extensions, "EGL_ARM_implicit_external_sync"); b_EGL_CHROMIUM_create_context_bind_generates_resource = gfx::HasExtension( extensions, "EGL_CHROMIUM_create_context_bind_generates_resource"); b_EGL_CHROMIUM_sync_control = @@ -331,8 +325,6 @@ gfx::HasExtension(extensions, "EGL_EXT_gl_colorspace_display_p3"); b_EGL_EXT_gl_colorspace_display_p3_passthrough = gfx::HasExtension( extensions, "EGL_EXT_gl_colorspace_display_p3_passthrough"); - b_EGL_EXT_image_dma_buf_import = - gfx::HasExtension(extensions, "EGL_EXT_image_dma_buf_import"); b_EGL_EXT_image_dma_buf_import_modifiers = gfx::HasExtension(extensions, "EGL_EXT_image_dma_buf_import_modifiers"); b_EGL_EXT_image_flush_external = @@ -341,8 +333,6 @@ gfx::HasExtension(extensions, "EGL_EXT_pixel_format_float"); b_EGL_IMG_context_priority = gfx::HasExtension(extensions, "EGL_IMG_context_priority"); - b_EGL_KHR_create_context = - gfx::HasExtension(extensions, "EGL_KHR_create_context"); b_EGL_KHR_fence_sync = gfx::HasExtension(extensions, "EGL_KHR_fence_sync"); b_EGL_KHR_gl_colorspace = gfx::HasExtension(extensions, "EGL_KHR_gl_colorspace");
diff --git a/ui/gl/gl_bindings_autogen_egl.h b/ui/gl/gl_bindings_autogen_egl.h index 985e75a..5819b20 100644 --- a/ui/gl/gl_bindings_autogen_egl.h +++ b/ui/gl/gl_bindings_autogen_egl.h
@@ -347,7 +347,6 @@ bool b_EGL_ANDROID_get_native_client_buffer; bool b_EGL_ANDROID_native_fence_sync; bool b_EGL_ANGLE_context_virtualization; - bool b_EGL_ANGLE_create_context_backwards_compatible; bool b_EGL_ANGLE_create_context_client_arrays; bool b_EGL_ANGLE_create_context_webgl_compatibility; bool b_EGL_ANGLE_d3d_share_handle_client_buffer; @@ -357,25 +356,21 @@ bool b_EGL_ANGLE_keyed_mutex; bool b_EGL_ANGLE_power_preference; bool b_EGL_ANGLE_query_surface_pointer; - bool b_EGL_ANGLE_robust_resource_initialization; bool b_EGL_ANGLE_stream_producer_d3d_texture; bool b_EGL_ANGLE_surface_d3d_texture_2d_share_handle; bool b_EGL_ANGLE_surface_orientation; bool b_EGL_ANGLE_sync_control_rate; bool b_EGL_ANGLE_vulkan_image; bool b_EGL_ANGLE_window_fixed_size; - bool b_EGL_ARM_implicit_external_sync; bool b_EGL_CHROMIUM_create_context_bind_generates_resource; bool b_EGL_CHROMIUM_sync_control; bool b_EGL_EXT_create_context_robustness; bool b_EGL_EXT_gl_colorspace_display_p3; bool b_EGL_EXT_gl_colorspace_display_p3_passthrough; - bool b_EGL_EXT_image_dma_buf_import; bool b_EGL_EXT_image_dma_buf_import_modifiers; bool b_EGL_EXT_image_flush_external; bool b_EGL_EXT_pixel_format_float; bool b_EGL_IMG_context_priority; - bool b_EGL_KHR_create_context; bool b_EGL_KHR_fence_sync; bool b_EGL_KHR_gl_colorspace; bool b_EGL_KHR_gl_texture_2D_image;
diff --git a/ui/gl/gl_context_egl.cc b/ui/gl/gl_context_egl.cc index d210618..ef7207b 100644 --- a/ui/gl/gl_context_egl.cc +++ b/ui/gl/gl_context_egl.cc
@@ -130,7 +130,7 @@ // Always prefer to use EGL_KHR_no_config_context so that all surfaces and // contexts are compatible - if (!gl_display_->ext->b_EGL_KHR_no_config_context) { + if (!gl_display_->IsEGLNoConfigContextSupported()) { config_ = compatible_surface->GetConfig(); EGLint config_renderable_type = 0; if (!eglGetConfigAttrib(gl_display_->GetDisplay(), config_, @@ -158,7 +158,7 @@ // EGL_KHR_create_context allows requesting both a major and minor context // version - if (gl_display_->ext->b_EGL_KHR_create_context) { + if (gl_display_->HasEGLExtension("EGL_KHR_create_context")) { context_attributes.push_back(EGL_CONTEXT_MAJOR_VERSION); context_attributes.push_back(context_client_major_version); @@ -176,7 +176,7 @@ bool is_swangle = IsSoftwareGLImplementation(GetGLImplementationParts()); - if (gl_display_->ext->b_EGL_EXT_create_context_robustness || is_swangle) { + if (gl_display_->IsCreateContextRobustnessSupported() || is_swangle) { DVLOG(1) << "EGL_EXT_create_context_robustness supported."; context_attributes.push_back(EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT); context_attributes.push_back( @@ -186,7 +186,7 @@ EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT); context_attributes.push_back(EGL_LOSE_CONTEXT_ON_RESET_EXT); - if (gl_display_->ext->b_EGL_NV_robustness_video_memory_purge) { + if (gl_display_->IsRobustnessVideoMemoryPurgeSupported()) { context_attributes.push_back( EGL_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV); context_attributes.push_back(EGL_TRUE); @@ -204,7 +204,7 @@ return false; } - if (gl_display_->ext->b_EGL_CHROMIUM_create_context_bind_generates_resource) { + if (gl_display_->IsCreateContextBindGeneratesResourceSupported()) { context_attributes.push_back(EGL_CONTEXT_BIND_GENERATES_RESOURCE_CHROMIUM); context_attributes.push_back(attribs.bind_generates_resource ? EGL_TRUE : EGL_FALSE); @@ -212,7 +212,7 @@ DCHECK(attribs.bind_generates_resource); } - if (gl_display_->ext->b_EGL_ANGLE_create_context_webgl_compatibility) { + if (gl_display_->IsCreateContextWebGLCompatabilitySupported()) { context_attributes.push_back(EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE); context_attributes.push_back( attribs.webgl_compatibility_context ? EGL_TRUE : EGL_FALSE); @@ -234,7 +234,7 @@ } } - if (gl_display_->ext->b_EGL_ANGLE_display_texture_share_group) { + if (gl_display_->IsDisplayTextureShareGroupSupported()) { context_attributes.push_back(EGL_DISPLAY_TEXTURE_SHARE_GROUP_ANGLE); context_attributes.push_back( attribs.global_texture_share_group ? EGL_TRUE : EGL_FALSE); @@ -242,7 +242,7 @@ DCHECK(!attribs.global_texture_share_group); } - if (gl_display_->ext->b_EGL_ANGLE_display_semaphore_share_group) { + if (gl_display_->IsDisplaySemaphoreShareGroupSupported()) { context_attributes.push_back(EGL_DISPLAY_SEMAPHORE_SHARE_GROUP_ANGLE); context_attributes.push_back( attribs.global_semaphore_share_group ? EGL_TRUE : EGL_FALSE); @@ -250,14 +250,13 @@ DCHECK(!attribs.global_semaphore_share_group); } - if (gl_display_->ext->b_EGL_ANGLE_create_context_client_arrays) { + if (gl_display_->IsCreateContextClientArraysSupported()) { // Disable client arrays if the context supports it context_attributes.push_back(EGL_CONTEXT_CLIENT_ARRAYS_ENABLED_ANGLE); context_attributes.push_back(EGL_FALSE); } - if (gl_display_->ext->b_EGL_ANGLE_robust_resource_initialization || - is_swangle) { + if (gl_display_->IsRobustResourceInitSupported() || is_swangle) { context_attributes.push_back(EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE); context_attributes.push_back( (attribs.robust_resource_initialization || is_swangle) ? EGL_TRUE @@ -266,14 +265,15 @@ DCHECK(!attribs.robust_resource_initialization); } - if (gl_display_->ext->b_EGL_ANGLE_create_context_backwards_compatible) { + if (gl_display_->HasEGLExtension( + "EGL_ANGLE_create_context_backwards_compatible")) { // Request a specific context version. The Passthrough command decoder // relies on the returned context being the exact version it requested. context_attributes.push_back(EGL_CONTEXT_OPENGL_BACKWARDS_COMPATIBLE_ANGLE); context_attributes.push_back(EGL_FALSE); } - if (gl_display_->ext->b_EGL_ANGLE_power_preference) { + if (gl_display_->IsANGLEPowerPreferenceSupported()) { GpuPreference pref = attribs.gpu_preference; pref = GLSurface::AdjustGpuPreference(pref); switch (pref) { @@ -293,7 +293,7 @@ } } - if (gl_display_->ext->b_EGL_ANGLE_external_context_and_surface) { + if (gl_display_->IsANGLEExternalContextAndSurfaceSupported()) { if (attribs.angle_create_from_external_context) { context_attributes.push_back(EGL_EXTERNAL_CONTEXT_ANGLE); context_attributes.push_back(EGL_TRUE); @@ -304,7 +304,7 @@ } } - if (gl_display_->ext->b_EGL_ANGLE_context_virtualization) { + if (gl_display_->IsANGLEContextVirtualizationSupported()) { context_attributes.push_back(EGL_CONTEXT_VIRTUALIZATION_GROUP_ANGLE); context_attributes.push_back( static_cast<EGLint>(attribs.angle_context_virtualization_group_number)); @@ -322,7 +322,7 @@ // If EGL_KHR_no_config_context is in use and context creation failed, // it might indicate that an unsupported ES version was requested. Try // falling back to a lower version. - if (!context_ && gl_display_->ext->b_EGL_KHR_no_config_context && + if (!context_ && gl_display_->IsEGLNoConfigContextSupported() && eglGetError() == EGL_BAD_MATCH) { // Set up the list of versions to try: 3.1 -> 3.0 -> 2.0 std::vector<std::pair<EGLint, EGLint>> candidate_versions; @@ -395,7 +395,7 @@ } void GLContextEGL::SetVisibility(bool visibility) { - if (gl_display_->ext->b_EGL_ANGLE_power_preference) { + if (gl_display_->IsANGLEPowerPreferenceSupported()) { // It doesn't matter whether this context was explicitly allocated // with a power preference - ANGLE will take care of any default behavior. if (visibility) { @@ -555,7 +555,7 @@ DCHECK(g_current_gl_driver); const ExtensionsGL& ext = g_current_gl_driver->ext; if ((graphics_reset_status_ == GL_NO_ERROR) && - gl_display_->ext->b_EGL_EXT_create_context_robustness && + gl_display_->IsCreateContextRobustnessSupported() && (ext.b_GL_KHR_robustness || ext.b_GL_EXT_robustness || ext.b_GL_ARB_robustness)) { graphics_reset_status_ = glGetGraphicsResetStatusARB();
diff --git a/ui/gl/gl_display.cc b/ui/gl/gl_display.cc index 92dfb472..7ee36c2 100644 --- a/ui/gl/gl_display.cc +++ b/ui/gl/gl_display.cc
@@ -55,6 +55,32 @@ return context ? context->GetGLDisplayEGL() : nullptr; } +bool GLDisplayEGL::HasEGLClientExtension(const char* name) { + if (!egl_client_extensions) + return false; + return GLSurface::ExtensionsContain(egl_client_extensions, name); +} + +bool GLDisplayEGL::HasEGLExtension(const char* name) { + return GLSurface::ExtensionsContain(egl_extensions, name); +} + +bool GLDisplayEGL::IsCreateContextRobustnessSupported() { + return egl_create_context_robustness_supported; +} + +bool GLDisplayEGL::IsRobustnessVideoMemoryPurgeSupported() { + return egl_robustness_video_memory_purge_supported; +} + +bool GLDisplayEGL::IsCreateContextBindGeneratesResourceSupported() { + return egl_create_context_bind_generates_resource_supported; +} + +bool GLDisplayEGL::IsCreateContextWebGLCompatabilitySupported() { + return egl_create_context_webgl_compatability_supported; +} + bool GLDisplayEGL::IsEGLSurfacelessContextSupported() { return egl_surfaceless_context_supported; } @@ -63,13 +89,66 @@ return egl_context_priority_supported; } +bool GLDisplayEGL::IsEGLNoConfigContextSupported() { + return egl_no_config_context_supported; +} + +bool GLDisplayEGL::IsRobustResourceInitSupported() { + return egl_robust_resource_init_supported; +} + +bool GLDisplayEGL::IsDisplayTextureShareGroupSupported() { + return egl_display_texture_share_group_supported; +} + +bool GLDisplayEGL::IsDisplaySemaphoreShareGroupSupported() { + return egl_display_semaphore_share_group_supported; +} + +bool GLDisplayEGL::IsCreateContextClientArraysSupported() { + return egl_create_context_client_arrays_supported; +} + bool GLDisplayEGL::IsAndroidNativeFenceSyncSupported() { return egl_android_native_fence_sync_supported; } -bool GLDisplayEGL::IsANGLEExternalContextAndSurfaceSupported() { - return this->ext->b_EGL_ANGLE_external_context_and_surface; +bool GLDisplayEGL::IsPixelFormatFloatSupported() { + return egl_ext_pixel_format_float_supported; } + +bool GLDisplayEGL::IsANGLEFeatureControlSupported() { + return egl_angle_feature_control_supported; +} + +bool GLDisplayEGL::IsANGLEPowerPreferenceSupported() { + return egl_angle_power_preference_supported; +} + +bool GLDisplayEGL::IsANGLEDisplayPowerPreferenceSupported() { + return egl_angle_display_power_preference_supported; +} + +bool GLDisplayEGL::IsANGLEPlatformANGLEDeviceIdSupported() { + return egl_angle_platform_angle_device_id_supported; +} + +bool GLDisplayEGL::IsANGLEExternalContextAndSurfaceSupported() { + return egl_angle_external_context_and_surface_supported; +} + +bool GLDisplayEGL::IsANGLEContextVirtualizationSupported() { + return egl_angle_context_virtualization_supported; +} + +bool GLDisplayEGL::IsANGLEVulkanImageSupported() { + return egl_angle_vulkan_image_supported; +} + +bool GLDisplayEGL::IsEGLQueryDeviceSupported() { + return egl_ext_query_device_supported; +} + #endif // defined(USE_EGL) #if defined(USE_GLX)
diff --git a/ui/gl/gl_display.h b/ui/gl/gl_display.h index ef4f069..7ce5bec 100644 --- a/ui/gl/gl_display.h +++ b/ui/gl/gl_display.h
@@ -99,18 +99,64 @@ EGLNativeDisplayType GetNativeDisplay(); DisplayType GetDisplayType(); + bool HasEGLClientExtension(const char* name); + bool HasEGLExtension(const char* name); + bool IsCreateContextRobustnessSupported(); + bool IsRobustnessVideoMemoryPurgeSupported(); + bool IsCreateContextBindGeneratesResourceSupported(); + bool IsCreateContextWebGLCompatabilitySupported(); bool IsEGLSurfacelessContextSupported(); bool IsEGLContextPrioritySupported(); + bool IsEGLNoConfigContextSupported(); + bool IsRobustResourceInitSupported(); + bool IsDisplayTextureShareGroupSupported(); + bool IsDisplaySemaphoreShareGroupSupported(); + bool IsCreateContextClientArraysSupported(); bool IsAndroidNativeFenceSyncSupported(); + bool IsPixelFormatFloatSupported(); + bool IsANGLEFeatureControlSupported(); + bool IsANGLEPowerPreferenceSupported(); + bool IsANGLEDisplayPowerPreferenceSupported(); + bool IsANGLEPlatformANGLEDeviceIdSupported(); bool IsANGLEExternalContextAndSurfaceSupported(); + bool IsANGLEContextVirtualizationSupported(); + bool IsANGLEVulkanImageSupported(); + bool IsEGLQueryDeviceSupported(); EGLDisplayPlatform native_display = EGLDisplayPlatform(EGL_DEFAULT_DISPLAY); DisplayType display_type = DisplayType::DEFAULT; + const char* egl_client_extensions = nullptr; + const char* egl_extensions = nullptr; + bool egl_create_context_robustness_supported = false; + bool egl_robustness_video_memory_purge_supported = false; + bool egl_create_context_bind_generates_resource_supported = false; + bool egl_create_context_webgl_compatability_supported = false; + bool egl_sync_control_supported = false; + bool egl_sync_control_rate_supported = false; + bool egl_window_fixed_size_supported = false; bool egl_surfaceless_context_supported = false; + bool egl_surface_orientation_supported = false; bool egl_context_priority_supported = false; + bool egl_khr_colorspace = false; + bool egl_ext_colorspace_display_p3 = false; + bool egl_ext_colorspace_display_p3_passthrough = false; + bool egl_no_config_context_supported = false; + bool egl_robust_resource_init_supported = false; + bool egl_display_texture_share_group_supported = false; + bool egl_display_semaphore_share_group_supported = false; + bool egl_create_context_client_arrays_supported = false; bool egl_android_native_fence_sync_supported = false; + bool egl_ext_pixel_format_float_supported = false; + bool egl_angle_feature_control_supported = false; + bool egl_angle_power_preference_supported = false; + bool egl_angle_display_power_preference_supported = false; + bool egl_angle_platform_angle_device_id_supported = false; + bool egl_angle_external_context_and_surface_supported = false; + bool egl_ext_query_device_supported = false; + bool egl_angle_context_virtualization_supported = false; + bool egl_angle_vulkan_image_supported = false; std::unique_ptr<DisplayExtensionsEGL> ext;
diff --git a/ui/gl/gl_image_native_pixmap.cc b/ui/gl/gl_image_native_pixmap.cc index 299eb9e3..effe6136 100644 --- a/ui/gl/gl_image_native_pixmap.cc +++ b/ui/gl/gl_image_native_pixmap.cc
@@ -131,10 +131,12 @@ : GLImageEGL(size), format_(format), plane_(plane), - has_image_flush_external_(gl::GLSurfaceEGL::GetGLDisplayEGL() - ->ext->b_EGL_EXT_image_flush_external), - has_image_dma_buf_export_(gl::GLSurfaceEGL::GetGLDisplayEGL() - ->ext->b_EGL_MESA_image_dma_buf_export) {} + has_image_flush_external_( + gl::GLSurfaceEGL::GetGLDisplayEGL()->HasEGLExtension( + "EGL_EXT_image_flush_external")), + has_image_dma_buf_export_( + gl::GLSurfaceEGL::GetGLDisplayEGL()->HasEGLExtension( + "EGL_MESA_image_dma_buf_export")) {} GLImageNativePixmap::~GLImageNativePixmap() {} @@ -172,8 +174,8 @@ EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT, EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT}; bool has_dma_buf_import_modifier = - gl::GLSurfaceEGL::GetGLDisplayEGL() - ->ext->b_EGL_EXT_image_dma_buf_import_modifiers; + gl::GLSurfaceEGL::GetGLDisplayEGL()->HasEGLExtension( + "EGL_EXT_image_dma_buf_import_modifiers"); for (size_t attrs_plane = 0; attrs_plane < pixmap->GetNumberOfPlanes(); ++attrs_plane) {
diff --git a/ui/gl/gl_surface_egl.cc b/ui/gl/gl_surface_egl.cc index 7a8f3ee..9906e709 100644 --- a/ui/gl/gl_surface_egl.cc +++ b/ui/gl/gl_surface_egl.cc
@@ -228,7 +228,7 @@ static bool IsSupported(GLDisplayEGL* display) { DCHECK(display); return SyncControlVSyncProvider::IsSupported() && - display->ext->b_EGL_CHROMIUM_sync_control; + display->egl_sync_control_supported; } protected: @@ -249,7 +249,7 @@ } bool GetMscRate(int32_t* numerator, int32_t* denominator) override { - if (!display_->ext->b_EGL_ANGLE_sync_control_rate) { + if (!display_->egl_sync_control_rate_supported) { return false; } @@ -272,7 +272,7 @@ } void OnGpuSwitched(gl::GpuPreference active_gpu_heuristic) override { - DCHECK(display_->ext->b_EGL_ANGLE_power_preference); + DCHECK(display_->IsANGLEPowerPreferenceSupported()); eglHandleGPUSwitchANGLE(display_->GetDisplay()); } @@ -340,7 +340,7 @@ GetAttribArrayFromStringVector(enabled_features); std::vector<const char*> disabled_features_attribs = GetAttribArrayFromStringVector(disabled_features); - if (g_driver_egl.client_ext.b_EGL_ANGLE_feature_control) { + if (gl_display->egl_angle_feature_control_supported) { if (!enabled_features_attribs.empty()) { display_attribs.push_back(EGL_FEATURE_OVERRIDES_ENABLED_ANGLE); display_attribs.push_back( @@ -354,7 +354,7 @@ } // TODO(dbehr) Add an attrib to Angle to pass EGL platform. - if (g_driver_egl.client_ext.b_EGL_ANGLE_display_power_preference) { + if (gl_display->IsANGLEDisplayPowerPreferenceSupported()) { GpuPreference pref = GLSurface::AdjustGpuPreference(GpuPreference::kDefault); switch (pref) { @@ -398,7 +398,7 @@ extra_display_attribs.push_back(EGL_TRUE); } if (system_device_id != 0 && - g_driver_egl.client_ext.b_EGL_ANGLE_platform_angle_device_id) { + gl_display->IsANGLEPlatformANGLEDeviceIdSupported()) { uint32_t low_part = system_device_id & 0xffffffff; extra_display_attribs.push_back(EGL_PLATFORM_ANGLE_DEVICE_ID_LOW_ANGLE); extra_display_attribs.push_back(low_part); @@ -1030,6 +1030,34 @@ // static void GLSurfaceEGL::InitializeOneOffCommon(GLDisplayEGL* display) { + display->egl_client_extensions = + eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS); + display->egl_extensions = + eglQueryString(display->GetDisplay(), EGL_EXTENSIONS); + + display->egl_create_context_robustness_supported = + display->HasEGLExtension("EGL_EXT_create_context_robustness"); + display->egl_robustness_video_memory_purge_supported = + display->HasEGLExtension("EGL_NV_robustness_video_memory_purge"); + display->egl_create_context_bind_generates_resource_supported = + display->HasEGLExtension( + "EGL_CHROMIUM_create_context_bind_generates_resource"); + display->egl_create_context_webgl_compatability_supported = + display->HasEGLExtension("EGL_ANGLE_create_context_webgl_compatibility"); + display->egl_sync_control_supported = + display->HasEGLExtension("EGL_CHROMIUM_sync_control"); + display->egl_sync_control_rate_supported = + display->HasEGLExtension("EGL_ANGLE_sync_control_rate"); + display->egl_window_fixed_size_supported = + display->HasEGLExtension("EGL_ANGLE_window_fixed_size"); + display->egl_surface_orientation_supported = + display->HasEGLExtension("EGL_ANGLE_surface_orientation"); + display->egl_khr_colorspace = + display->HasEGLExtension("EGL_KHR_gl_colorspace"); + display->egl_ext_colorspace_display_p3 = + display->HasEGLExtension("EGL_EXT_gl_colorspace_display_p3"); + display->egl_ext_colorspace_display_p3_passthrough = + display->HasEGLExtension("EGL_EXT_gl_colorspace_display_p3_passthrough"); // According to https://source.android.com/compatibility/android-cdd.html the // EGL_IMG_context_priority extension is mandatory for Virtual Reality High // Performance support, but due to a bug in Android Nougat the extension @@ -1038,13 +1066,27 @@ // that this implies context priority is also supported. See also: // https://github.com/googlevr/gvr-android-sdk/issues/330 display->egl_context_priority_supported = - display->ext->b_EGL_IMG_context_priority || - (display->ext->b_EGL_ANDROID_front_buffer_auto_refresh && - display->ext->b_EGL_ANDROID_create_native_client_buffer); + display->HasEGLExtension("EGL_IMG_context_priority") || + (display->HasEGLExtension("EGL_ANDROID_front_buffer_auto_refresh") && + display->HasEGLExtension("EGL_ANDROID_create_native_client_buffer")); + + // Need EGL_KHR_no_config_context to allow surfaces with and without alpha to + // be bound to the same context. + display->egl_no_config_context_supported = + display->HasEGLExtension("EGL_KHR_no_config_context"); + + display->egl_display_texture_share_group_supported = + display->HasEGLExtension("EGL_ANGLE_display_texture_share_group"); + display->egl_display_semaphore_share_group_supported = + display->HasEGLExtension("EGL_ANGLE_display_semaphore_share_group"); + display->egl_create_context_client_arrays_supported = + display->HasEGLExtension("EGL_ANGLE_create_context_client_arrays"); + display->egl_robust_resource_init_supported = + display->HasEGLExtension("EGL_ANGLE_robust_resource_initialization"); // Check if SurfacelessEGL is supported. display->egl_surfaceless_context_supported = - display->ext->b_EGL_KHR_surfaceless_context; + display->HasEGLExtension("EGL_KHR_surfaceless_context"); // TODO(oetuaho@nvidia.com): Surfaceless is disabled on Android as a temporary // workaround, since code written for Android WebView takes different paths @@ -1056,7 +1098,7 @@ #if BUILDFLAG(IS_ANDROID) // Use the WebGL compatibility extension for detecting ANGLE. ANGLE always // exposes it. - bool is_angle = display->ext->b_EGL_ANGLE_create_context_webgl_compatibility; + bool is_angle = display->egl_create_context_webgl_compatability_supported; if (!is_angle) { display->egl_surfaceless_context_supported = false; } @@ -1091,7 +1133,7 @@ // Android level, update the heuristic to trust the reported extension from // that version onward. display->egl_android_native_fence_sync_supported = - display->ext->b_EGL_ANDROID_native_fence_sync; + display->HasEGLExtension("EGL_ANDROID_native_fence_sync"); #if BUILDFLAG(IS_ANDROID) if (!display->egl_android_native_fence_sync_supported && base::android::BuildInfo::GetInstance()->sdk_int() >= @@ -1103,7 +1145,25 @@ } #endif - if (display->ext->b_EGL_ANGLE_power_preference) { + display->egl_ext_pixel_format_float_supported = + display->HasEGLExtension("EGL_EXT_pixel_format_float"); + + display->egl_angle_power_preference_supported = + display->HasEGLExtension("EGL_ANGLE_power_preference"); + + display->egl_angle_external_context_and_surface_supported = + display->HasEGLExtension("EGL_ANGLE_external_context_and_surface"); + + display->egl_ext_query_device_supported = + display->HasEGLClientExtension("EGL_EXT_device_query"); + + display->egl_angle_context_virtualization_supported = + display->HasEGLExtension("EGL_ANGLE_context_virtualization"); + + display->egl_angle_vulkan_image_supported = + display->HasEGLExtension("EGL_ANGLE_vulkan_image"); + + if (display->egl_angle_power_preference_supported) { g_egl_gpu_switching_observer = new EGLGpuSwitchingObserver(display); ui::GpuSwitchingManager::GetInstance()->AddObserver( g_egl_gpu_switching_observer); @@ -1116,6 +1176,11 @@ if (display->GetDisplay() == EGL_NO_DISPLAY) return false; display->ext->UpdateConditionalExtensionSettings(display); + display->egl_client_extensions = + eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS); + display->egl_extensions = + eglQueryString(display->GetDisplay(), EGL_EXTENSIONS); + return true; } @@ -1136,9 +1201,21 @@ eglTerminate(display->GetDisplay()); display->SetDisplay(EGL_NO_DISPLAY); + display->egl_client_extensions = nullptr; + display->egl_extensions = nullptr; + display->egl_create_context_robustness_supported = false; + display->egl_robustness_video_memory_purge_supported = false; + display->egl_create_context_bind_generates_resource_supported = false; + display->egl_create_context_webgl_compatability_supported = false; + display->egl_sync_control_supported = false; + display->egl_sync_control_rate_supported = false; + display->egl_window_fixed_size_supported = false; + display->egl_surface_orientation_supported = false; display->egl_surfaceless_context_supported = false; - display->egl_context_priority_supported = false; - display->egl_android_native_fence_sync_supported = false; + display->egl_robust_resource_init_supported = false; + display->egl_display_texture_share_group_supported = false; + display->egl_create_context_client_arrays_supported = false; + display->egl_angle_feature_control_supported = false; } GLSurfaceEGL::~GLSurfaceEGL() = default; @@ -1156,7 +1233,12 @@ gl_display->native_display = native_display; - bool supports_egl_debug = g_driver_egl.client_ext.b_EGL_KHR_debug; + // If EGL_EXT_client_extensions not supported this call to eglQueryString + // will return nullptr. + gl_display->egl_client_extensions = + eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS); + + bool supports_egl_debug = gl_display->HasEGLClientExtension("EGL_KHR_debug"); if (supports_egl_debug) { EGLAttrib controls[] = { EGL_DEBUG_MSG_CRITICAL_KHR, @@ -1182,27 +1264,36 @@ bool supports_angle_egl = false; bool supports_angle_metal = false; // Check for availability of ANGLE extensions. - if (g_driver_egl.client_ext.b_EGL_ANGLE_platform_angle) { - supports_angle_d3d = g_driver_egl.client_ext.b_EGL_ANGLE_platform_angle_d3d; + if (gl_display->HasEGLClientExtension("EGL_ANGLE_platform_angle")) { + supports_angle_d3d = + gl_display->HasEGLClientExtension("EGL_ANGLE_platform_angle_d3d"); supports_angle_opengl = - g_driver_egl.client_ext.b_EGL_ANGLE_platform_angle_opengl; + gl_display->HasEGLClientExtension("EGL_ANGLE_platform_angle_opengl"); supports_angle_null = - g_driver_egl.client_ext.b_EGL_ANGLE_platform_angle_null; + gl_display->HasEGLClientExtension("EGL_ANGLE_platform_angle_null"); supports_angle_vulkan = - g_driver_egl.client_ext.b_EGL_ANGLE_platform_angle_vulkan; - supports_angle_swiftshader = - g_driver_egl.client_ext - .b_EGL_ANGLE_platform_angle_device_type_swiftshader; - supports_angle_egl = g_driver_egl.client_ext - .b_EGL_ANGLE_platform_angle_device_type_egl_angle; + gl_display->HasEGLClientExtension("EGL_ANGLE_platform_angle_vulkan"); + supports_angle_swiftshader = gl_display->HasEGLClientExtension( + "EGL_ANGLE_platform_angle_device_type_swiftshader"); + supports_angle_egl = gl_display->HasEGLClientExtension( + "EGL_ANGLE_platform_angle_device_type_egl_angle"); supports_angle_metal = - g_driver_egl.client_ext.b_EGL_ANGLE_platform_angle_metal; + gl_display->HasEGLClientExtension("EGL_ANGLE_platform_angle_metal"); } bool supports_angle = supports_angle_d3d || supports_angle_opengl || supports_angle_null || supports_angle_vulkan || supports_angle_swiftshader || supports_angle_metal; + gl_display->egl_angle_feature_control_supported = + gl_display->HasEGLClientExtension("EGL_ANGLE_feature_control"); + + gl_display->egl_angle_display_power_preference_supported = + gl_display->HasEGLClientExtension("EGL_ANGLE_display_power_preference"); + + gl_display->egl_angle_platform_angle_device_id_supported = + gl_display->HasEGLClientExtension("EGL_ANGLE_platform_angle_device_id"); + std::vector<DisplayType> init_displays; base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); GetEGLInitDisplays(supports_angle_d3d, supports_angle_opengl, @@ -1317,8 +1408,7 @@ std::vector<EGLint> egl_window_attributes; - if (display_->ext->b_EGL_ANGLE_window_fixed_size && - enable_fixed_size_angle_) { + if (display_->egl_window_fixed_size_supported && enable_fixed_size_angle_) { egl_window_attributes.push_back(EGL_FIXED_SIZE_ANGLE); egl_window_attributes.push_back(EGL_TRUE); egl_window_attributes.push_back(EGL_WIDTH); @@ -1332,7 +1422,7 @@ egl_window_attributes.push_back(EGL_TRUE); } - if (display_->ext->b_EGL_ANGLE_surface_orientation) { + if (display_->egl_surface_orientation_supported) { EGLint attrib; eglGetConfigAttrib(display_->GetDisplay(), GetConfig(), EGL_OPTIMAL_SURFACE_ORIENTATION_ANGLE, &attrib); @@ -1353,7 +1443,7 @@ // Note that COLORSPACE_LINEAR refers to the sRGB color space, but // without opting into sRGB blending. It is equivalent to // COLORSPACE_SRGB with Disable(FRAMEBUFFER_SRGB). - if (display_->ext->b_EGL_KHR_gl_colorspace) { + if (display_->egl_khr_colorspace) { egl_window_attributes.push_back(EGL_GL_COLORSPACE_KHR); egl_window_attributes.push_back(EGL_GL_COLORSPACE_LINEAR_KHR); } @@ -1367,16 +1457,15 @@ // with the P3 gamut instead of the the sRGB gamut. // COLORSPACE_DISPLAY_P3_LINEAR has a linear transfer function, and is // intended for use with 16-bit formats. - bool p3_supported = - display_->ext->b_EGL_EXT_gl_colorspace_display_p3 || - display_->ext->b_EGL_EXT_gl_colorspace_display_p3_passthrough; - if (display_->ext->b_EGL_KHR_gl_colorspace && p3_supported) { + bool p3_supported = display_->egl_ext_colorspace_display_p3 || + display_->egl_ext_colorspace_display_p3_passthrough; + if (display_->egl_khr_colorspace && p3_supported) { egl_window_attributes.push_back(EGL_GL_COLORSPACE_KHR); // Chrome relied on incorrect Android behavior when dealing with P3 / // framebuffer_srgb interactions. This behavior was fixed in Q, which // causes invalid Chrome rendering. To achieve Android-P behavior in Q+, // use EGL_GL_COLORSPACE_P3_PASSTHROUGH_EXT where possible. - if (display_->ext->b_EGL_EXT_gl_colorspace_display_p3_passthrough) { + if (display_->egl_ext_colorspace_display_p3_passthrough) { egl_window_attributes.push_back( EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT); } else { @@ -2002,7 +2091,7 @@ // Enable robust resource init when using SwANGLE if (IsSoftwareGLImplementation(GetGLImplementationParts()) && - display_->ext->b_EGL_ANGLE_robust_resource_initialization) { + display_->IsRobustResourceInitSupported()) { pbuffer_attribs.push_back(EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE); pbuffer_attribs.push_back(EGL_TRUE); }
diff --git a/ui/gl/gl_utils.cc b/ui/gl/gl_utils.cc index dffa2e5..c98a7cd 100644 --- a/ui/gl/gl_utils.cc +++ b/ui/gl/gl_utils.cc
@@ -104,11 +104,11 @@ GLDisplayEGL* display = gl::GLSurfaceEGL::GetGLDisplayEGL(); // Using the passthrough command buffer requires that specific ANGLE // extensions are exposed - return display->ext->b_EGL_CHROMIUM_create_context_bind_generates_resource && - display->ext->b_EGL_ANGLE_create_context_webgl_compatibility && - display->ext->b_EGL_ANGLE_robust_resource_initialization && - display->ext->b_EGL_ANGLE_display_texture_share_group && - display->ext->b_EGL_ANGLE_create_context_client_arrays; + return display->IsCreateContextBindGeneratesResourceSupported() && + display->IsCreateContextWebGLCompatabilitySupported() && + display->IsRobustResourceInitSupported() && + display->IsDisplayTextureShareGroupSupported() && + display->IsCreateContextClientArraysSupported(); #else // The passthrough command buffer is only supported on top of ANGLE/EGL return false;
diff --git a/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc b/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc index 60b3bfa9..43cb0c2 100644 --- a/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc +++ b/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc
@@ -45,9 +45,9 @@ window_(std::move(window)), widget_(widget), has_implicit_external_sync_( - GetGLDisplayEGL()->ext->b_EGL_ARM_implicit_external_sync), + GetGLDisplayEGL()->HasEGLExtension("EGL_ARM_implicit_external_sync")), has_image_flush_external_( - GetGLDisplayEGL()->ext->b_EGL_EXT_image_flush_external) { + GetGLDisplayEGL()->HasEGLExtension("EGL_EXT_image_flush_external")) { surface_factory_->RegisterSurface(window_->widget(), this); supports_plane_gpu_fences_ = window_->SupportsGpuFences(); unsubmitted_frames_.push_back(std::make_unique<PendingFrame>());
diff --git a/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.cc b/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.cc index ae16deb..ebaf402 100644 --- a/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.cc +++ b/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.cc
@@ -16,7 +16,6 @@ #include "ui/gfx/geometry/rrect_f.h" #include "ui/gfx/linux/drm_util_linux.h" #include "ui/gfx/overlay_priority_hint.h" -#include "ui/gl/gl_bindings.h" #include "ui/gl/gl_surface_egl.h" #include "ui/ozone/platform/wayland/common/wayland_overlay_config.h" #include "ui/ozone/platform/wayland/gpu/wayland_surface_gpu.h" @@ -298,9 +297,10 @@ #if defined(WAYLAND_GBM) GbmDevice* WaylandBufferManagerGpu::GetGbmDevice() { // Wayland won't support wl_drm or zwp_linux_dmabuf without this extension. - if (!supports_dmabuf_ || (!gl::GLSurfaceEGL::GetGLDisplayEGL() - ->ext->b_EGL_EXT_image_dma_buf_import && - !use_fake_gbm_device_for_test_)) { + if (!supports_dmabuf_ || + (!gl::GLSurfaceEGL::GetGLDisplayEGL()->HasEGLExtension( + "EGL_EXT_image_dma_buf_import") && + !use_fake_gbm_device_for_test_)) { supports_dmabuf_ = false; return nullptr; }
diff --git a/ui/ozone/platform/wayland/host/shell_toplevel_wrapper.h b/ui/ozone/platform/wayland/host/shell_toplevel_wrapper.h index 4177604..76a9dfe3 100644 --- a/ui/ozone/platform/wayland/host/shell_toplevel_wrapper.h +++ b/ui/ozone/platform/wayland/host/shell_toplevel_wrapper.h
@@ -123,6 +123,10 @@ // Checks if the server supports chrome to control the window position in // screen coordinates. virtual bool SupportsScreenCoordinates() const = 0; + + // Enables screen coordinates support. This is no-op if the server does not + // support the screen coordinates. + virtual void EnableScreenCoordinates() = 0; }; // Look for |value| in |wl_array| in C++ style.
diff --git a/ui/ozone/platform/wayland/host/wayland_toplevel_window.cc b/ui/ozone/platform/wayland/host/wayland_toplevel_window.cc index 844bcbc..27b58bf 100644 --- a/ui/ozone/platform/wayland/host/wayland_toplevel_window.cc +++ b/ui/ozone/platform/wayland/host/wayland_toplevel_window.cc
@@ -69,6 +69,11 @@ LOG(ERROR) << "Failed to create a ShellToplevel."; return false; } + screen_coordinates_enabled_ &= shell_toplevel_->SupportsScreenCoordinates(); + screen_coordinates_enabled_ &= !use_native_frame_; + + if (screen_coordinates_enabled_) + shell_toplevel_->EnableScreenCoordinates(); #if BUILDFLAG(IS_CHROMEOS_LACROS) shell_toplevel_->SetAppId(window_unique_id_); @@ -88,7 +93,6 @@ ZAURA_SURFACE_FRAME_TYPE_SHADOW); } - screen_coordinates_enabled_ &= shell_toplevel_->SupportsScreenCoordinates(); // TODO(oshima): Change to use DIP. if (screen_coordinates_enabled_) SetBoundsInPixels(GetBoundsInPixels());
diff --git a/ui/ozone/platform/wayland/host/xdg_toplevel_wrapper_impl.cc b/ui/ozone/platform/wayland/host/xdg_toplevel_wrapper_impl.cc index 14d1c943..9935ab94 100644 --- a/ui/ozone/platform/wayland/host/xdg_toplevel_wrapper_impl.cc +++ b/ui/ozone/platform/wayland/host/xdg_toplevel_wrapper_impl.cc
@@ -109,23 +109,6 @@ zaura_toplevel_surface_submission_in_pixel_coordinates( aura_toplevel_.get()); } - - if (features::IsWaylandScreenCoordinatesEnabled()) { - if (SupportsScreenCoordinates()) { - zaura_toplevel_set_supports_screen_coordinates(aura_toplevel_.get()); - - static constexpr zaura_toplevel_listener aura_toplevel_listener = { - &ConfigureAuraTopLevel, - &OnOriginChange, - }; - - zaura_toplevel_add_listener(aura_toplevel_.get(), - &aura_toplevel_listener, this); - } else { - LOG(WARNING) << "Server implementation of wayland is incompatible, " - "WaylandScreenCoordinatesEnabled has no effect."; - } - } } } @@ -299,14 +282,6 @@ DecorationMode requested_mode) { if (!zxdg_toplevel_decoration_ || requested_mode == decoration_mode_) return; - // TODO(crbug.com/1261321): Server side decoration decoration will not work - // when the screen coordinate is enabled. - if (SupportsScreenCoordinates() && - requested_mode == DecorationMode::kServerSide) { - LOG(WARNING) << "Server side decoration is not supported when window " - "positioning is enabled"; - return; - } zxdg_toplevel_decoration_v1_set_mode(zxdg_toplevel_decoration_.get(), ToInt32(requested_mode)); @@ -416,6 +391,25 @@ ZAURA_TOPLEVEL_SET_SUPPORTS_SCREEN_COORDINATES_SINCE_VERSION; } +void XDGToplevelWrapperImpl::EnableScreenCoordinates() { + if (!features::IsWaylandScreenCoordinatesEnabled()) + return; + if (!SupportsScreenCoordinates()) { + LOG(WARNING) << "Server implementation of wayland is incompatible, " + "WaylandScreenCoordinatesEnabled has no effect."; + return; + } + zaura_toplevel_set_supports_screen_coordinates(aura_toplevel_.get()); + + static constexpr zaura_toplevel_listener aura_toplevel_listener = { + &ConfigureAuraTopLevel, + &OnOriginChange, + }; + + zaura_toplevel_add_listener(aura_toplevel_.get(), &aura_toplevel_listener, + this); +} + void XDGToplevelWrapperImpl::SetRestoreInfo(int32_t restore_session_id, int32_t restore_window_id) { if (aura_toplevel_ && zaura_toplevel_get_version(aura_toplevel_.get()) >=
diff --git a/ui/ozone/platform/wayland/host/xdg_toplevel_wrapper_impl.h b/ui/ozone/platform/wayland/host/xdg_toplevel_wrapper_impl.h index 5bdf82dc..c8d7830 100644 --- a/ui/ozone/platform/wayland/host/xdg_toplevel_wrapper_impl.h +++ b/ui/ozone/platform/wayland/host/xdg_toplevel_wrapper_impl.h
@@ -49,6 +49,7 @@ void SetRestoreInfoWithWindowIdSource(int32_t, const std::string&) override; void SetSystemModal(bool modal) override; bool SupportsScreenCoordinates() const override; + void EnableScreenCoordinates() override; XDGSurfaceWrapperImpl* xdg_surface_wrapper() const;
diff --git a/ui/ozone/platform/wayland/host/zxdg_toplevel_v6_wrapper_impl.cc b/ui/ozone/platform/wayland/host/zxdg_toplevel_v6_wrapper_impl.cc index ce770a5d9..4ddb3a6 100644 --- a/ui/ozone/platform/wayland/host/zxdg_toplevel_v6_wrapper_impl.cc +++ b/ui/ozone/platform/wayland/host/zxdg_toplevel_v6_wrapper_impl.cc
@@ -211,4 +211,6 @@ return false; } +void ZXDGToplevelV6WrapperImpl::EnableScreenCoordinates() {} + } // namespace ui
diff --git a/ui/ozone/platform/wayland/host/zxdg_toplevel_v6_wrapper_impl.h b/ui/ozone/platform/wayland/host/zxdg_toplevel_v6_wrapper_impl.h index 15cc90f0..140c6778 100644 --- a/ui/ozone/platform/wayland/host/zxdg_toplevel_v6_wrapper_impl.h +++ b/ui/ozone/platform/wayland/host/zxdg_toplevel_v6_wrapper_impl.h
@@ -53,6 +53,7 @@ const std::string& restore_window_id_source) override; void SetSystemModal(bool modal) override; bool SupportsScreenCoordinates() const override; + void EnableScreenCoordinates() override; ZXDGSurfaceV6WrapperImpl* zxdg_surface_v6_wrapper() const;
diff --git a/ui/webui/resources/tools/generate_grd.gni b/ui/webui/resources/tools/generate_grd.gni index 7a99fc8..8f8836f7 100644 --- a/ui/webui/resources/tools/generate_grd.gni +++ b/ui/webui/resources/tools/generate_grd.gni
@@ -10,6 +10,7 @@ [ "deps", "public_deps", + "testonly", ]) inputs = []